1 /********************************************************************
2 * *
3 * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
4 * *
5 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
6 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
7 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
8 * *
9 * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2003 *
10 * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
11 * *
12 ********************************************************************
13
14 function: channel mapping 0 implementation
15
16 ********************************************************************/
17
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <math.h>
22 #include "ogg.h"
23 #include "os.h"
24 #include "ivorbiscodec.h"
25 #include "mdct.h"
26 #include "codec_internal.h"
27 #include "codebook.h"
28 #include "misc.h"
29
mapping_clear_info(vorbis_info_mapping * info)30 void mapping_clear_info(vorbis_info_mapping *info){
31 if(info){
32 if(info->chmuxlist)_ogg_free(info->chmuxlist);
33 if(info->submaplist)_ogg_free(info->submaplist);
34 if(info->coupling)_ogg_free(info->coupling);
35 memset(info,0,sizeof(*info));
36 }
37 }
38
ilog(unsigned int v)39 static int ilog(unsigned int v){
40 int ret=0;
41 if(v)--v;
42 while(v){
43 ret++;
44 v>>=1;
45 }
46 return(ret);
47 }
48
49 /* also responsible for range checking */
mapping_info_unpack(vorbis_info_mapping * info,vorbis_info * vi,oggpack_buffer * opb)50 int mapping_info_unpack(vorbis_info_mapping *info,vorbis_info *vi,
51 oggpack_buffer *opb){
52 int i;
53 codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
54 memset(info,0,sizeof(*info));
55
56 if(oggpack_read(opb,1))
57 info->submaps=oggpack_read(opb,4)+1;
58 else
59 info->submaps=1;
60
61 if(oggpack_read(opb,1)){
62 info->coupling_steps=oggpack_read(opb,8)+1;
63 info->coupling=
64 _ogg_malloc(info->coupling_steps*sizeof(*info->coupling));
65
66 for(i=0;i<info->coupling_steps;i++){
67 int testM=info->coupling[i].mag=oggpack_read(opb,ilog(vi->channels));
68 int testA=info->coupling[i].ang=oggpack_read(opb,ilog(vi->channels));
69
70 if(testM<0 ||
71 testA<0 ||
72 testM==testA ||
73 testM>=vi->channels ||
74 testA>=vi->channels) goto err_out;
75 }
76
77 }
78
79 if(oggpack_read(opb,2)>0)goto err_out; /* 2,3:reserved */
80
81 if(info->submaps>1){
82 info->chmuxlist=_ogg_malloc(sizeof(*info->chmuxlist)*vi->channels);
83 for(i=0;i<vi->channels;i++){
84 info->chmuxlist[i]=oggpack_read(opb,4);
85 if(info->chmuxlist[i]>=info->submaps)goto err_out;
86 }
87 }
88
89 info->submaplist=_ogg_malloc(sizeof(*info->submaplist)*info->submaps);
90 for(i=0;i<info->submaps;i++){
91 int temp=oggpack_read(opb,8);
92 info->submaplist[i].floor=oggpack_read(opb,8);
93 if(info->submaplist[i].floor>=ci->floors)goto err_out;
94 info->submaplist[i].residue=oggpack_read(opb,8);
95 if(info->submaplist[i].residue>=ci->residues)goto err_out;
96 }
97
98 return 0;
99
100 err_out:
101 mapping_clear_info(info);
102 return -1;
103 }
104
mapping_inverse(vorbis_dsp_state * vd,vorbis_info_mapping * info)105 int mapping_inverse(vorbis_dsp_state *vd,vorbis_info_mapping *info){
106 vorbis_info *vi=vd->vi;
107 codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
108
109 int i,j;
110 long n=ci->blocksizes[vd->W];
111
112 ogg_int32_t **pcmbundle=
113 alloca(sizeof(*pcmbundle)*vi->channels);
114 int *zerobundle=
115 alloca(sizeof(*zerobundle)*vi->channels);
116 int *nonzero=
117 alloca(sizeof(*nonzero)*vi->channels);
118 ogg_int32_t **floormemo=
119 alloca(sizeof(*floormemo)*vi->channels);
120
121 /* recover the spectral envelope; store it in the PCM vector for now */
122 for(i=0;i<vi->channels;i++){
123 int submap=0;
124 int floorno;
125
126 if(info->submaps>1)
127 submap=info->chmuxlist[i];
128 floorno=info->submaplist[submap].floor;
129
130 if(ci->floor_type[floorno]){
131 /* floor 1 */
132 floormemo[i]=alloca(sizeof(*floormemo[i])*
133 floor1_memosize(ci->floor_param[floorno]));
134 floormemo[i]=floor1_inverse1(vd,ci->floor_param[floorno],floormemo[i]);
135 }else{
136 /* floor 0 */
137 floormemo[i]=alloca(sizeof(*floormemo[i])*
138 floor0_memosize(ci->floor_param[floorno]));
139 floormemo[i]=floor0_inverse1(vd,ci->floor_param[floorno],floormemo[i]);
140 }
141
142 if(floormemo[i])
143 nonzero[i]=1;
144 else
145 nonzero[i]=0;
146 memset(vd->work[i],0,sizeof(*vd->work[i])*n/2);
147 }
148
149 /* channel coupling can 'dirty' the nonzero listing */
150 for(i=0;i<info->coupling_steps;i++){
151 if(nonzero[info->coupling[i].mag] ||
152 nonzero[info->coupling[i].ang]){
153 nonzero[info->coupling[i].mag]=1;
154 nonzero[info->coupling[i].ang]=1;
155 }
156 }
157
158 /* recover the residue into our working vectors */
159 for(i=0;i<info->submaps;i++){
160 int ch_in_bundle=0;
161 for(j=0;j<vi->channels;j++){
162 if(!info->chmuxlist || info->chmuxlist[j]==i){
163 if(nonzero[j])
164 zerobundle[ch_in_bundle]=1;
165 else
166 zerobundle[ch_in_bundle]=0;
167 pcmbundle[ch_in_bundle++]=vd->work[j];
168 }
169 }
170
171 res_inverse(vd,ci->residue_param+info->submaplist[i].residue,
172 pcmbundle,zerobundle,ch_in_bundle);
173 }
174
175 //for(j=0;j<vi->channels;j++)
176 //_analysis_output("coupled",seq+j,vb->pcm[j],-8,n/2,0,0);
177
178 /* channel coupling */
179 for(i=info->coupling_steps-1;i>=0;i--){
180 ogg_int32_t *pcmM=vd->work[info->coupling[i].mag];
181 ogg_int32_t *pcmA=vd->work[info->coupling[i].ang];
182
183 for(j=0;j<n/2;j++){
184 ogg_int32_t mag=pcmM[j];
185 ogg_int32_t ang=pcmA[j];
186
187 if(mag>0)
188 if(ang>0){
189 pcmM[j]=mag;
190 pcmA[j]=mag-ang;
191 }else{
192 pcmA[j]=mag;
193 pcmM[j]=mag+ang;
194 }
195 else
196 if(ang>0){
197 pcmM[j]=mag;
198 pcmA[j]=mag+ang;
199 }else{
200 pcmA[j]=mag;
201 pcmM[j]=mag-ang;
202 }
203 }
204 }
205
206 //for(j=0;j<vi->channels;j++)
207 //_analysis_output("residue",seq+j,vb->pcm[j],-8,n/2,0,0);
208
209 /* compute and apply spectral envelope */
210 for(i=0;i<vi->channels;i++){
211 ogg_int32_t *pcm=vd->work[i];
212 int submap=0;
213 int floorno;
214
215 if(info->submaps>1)
216 submap=info->chmuxlist[i];
217 floorno=info->submaplist[submap].floor;
218
219 if(ci->floor_type[floorno]){
220 /* floor 1 */
221 floor1_inverse2(vd,ci->floor_param[floorno],floormemo[i],pcm);
222 }else{
223 /* floor 0 */
224 floor0_inverse2(vd,ci->floor_param[floorno],floormemo[i],pcm);
225 }
226 }
227
228 //for(j=0;j<vi->channels;j++)
229 //_analysis_output("mdct",seq+j,vb->pcm[j],-24,n/2,0,1);
230
231 /* transform the PCM data; takes PCM vector, vb; modifies PCM vector */
232 /* only MDCT right now.... */
233 for(i=0;i<vi->channels;i++)
234 mdct_backward(n,vd->work[i]);
235
236 //for(j=0;j<vi->channels;j++)
237 //_analysis_output("imdct",seq+j,vb->pcm[j],-24,n,0,0);
238
239 /* all done! */
240 return(0);
241 }
242