22 #include "ogg.h" |
22 #include "ogg.h" |
23 #include "ivorbiscodec.h" |
23 #include "ivorbiscodec.h" |
24 #include "mdct.h" |
24 #include "mdct.h" |
25 #include "codec_internal.h" |
25 #include "codec_internal.h" |
26 #include "codebook.h" |
26 #include "codebook.h" |
|
27 #include "window.h" |
|
28 #include "registry.h" |
27 #include "misc.h" |
29 #include "misc.h" |
28 |
30 |
29 void mapping_clear_info(vorbis_info_mapping *info){ |
31 /* simplistic, wasteful way of doing this (unique lookup for each |
|
32 mode/submapping); there should be a central repository for |
|
33 identical lookups. That will require minor work, so I'm putting it |
|
34 off as low priority. |
|
35 |
|
36 Why a lookup for each backend in a given mode? Because the |
|
37 blocksize is set by the mode, and low backend lookups may require |
|
38 parameters from other areas of the mode/mapping */ |
|
39 |
|
40 typedef struct { |
|
41 vorbis_info_mode *mode; |
|
42 vorbis_info_mapping0 *map; |
|
43 |
|
44 vorbis_look_floor **floor_look; |
|
45 |
|
46 vorbis_look_residue **residue_look; |
|
47 |
|
48 vorbis_func_floor **floor_func; |
|
49 vorbis_func_residue **residue_func; |
|
50 |
|
51 int ch; |
|
52 long lastframe; /* if a different mode is called, we need to |
|
53 invalidate decay */ |
|
54 } vorbis_look_mapping0; |
|
55 |
|
56 static void mapping0_free_info(vorbis_info_mapping *i){ |
|
57 vorbis_info_mapping0 *info=(vorbis_info_mapping0 *)i; |
30 if(info){ |
58 if(info){ |
31 if(info->chmuxlist)_ogg_free(info->chmuxlist); |
|
32 if(info->submaplist)_ogg_free(info->submaplist); |
|
33 if(info->coupling)_ogg_free(info->coupling); |
|
34 memset(info,0,sizeof(*info)); |
59 memset(info,0,sizeof(*info)); |
35 } |
60 _ogg_free(info); |
|
61 } |
|
62 } |
|
63 |
|
64 static void mapping0_free_look(vorbis_look_mapping *look){ |
|
65 int i; |
|
66 vorbis_look_mapping0 *l=(vorbis_look_mapping0 *)look; |
|
67 if(l){ |
|
68 |
|
69 for(i=0;i<l->map->submaps;i++){ |
|
70 l->floor_func[i]->free_look(l->floor_look[i]); |
|
71 l->residue_func[i]->free_look(l->residue_look[i]); |
|
72 } |
|
73 |
|
74 _ogg_free(l->floor_func); |
|
75 _ogg_free(l->residue_func); |
|
76 _ogg_free(l->floor_look); |
|
77 _ogg_free(l->residue_look); |
|
78 memset(l,0,sizeof(*l)); |
|
79 _ogg_free(l); |
|
80 } |
|
81 } |
|
82 |
|
83 static vorbis_look_mapping *mapping0_look(vorbis_dsp_state *vd,vorbis_info_mode *vm, |
|
84 vorbis_info_mapping *m){ |
|
85 int i; |
|
86 vorbis_info *vi=vd->vi; |
|
87 codec_setup_info *ci=(codec_setup_info *)vi->codec_setup; |
|
88 vorbis_look_mapping0 *look=(vorbis_look_mapping0 *)_ogg_calloc(1,sizeof(*look)); |
|
89 vorbis_info_mapping0 *info=look->map=(vorbis_info_mapping0 *)m; |
|
90 look->mode=vm; |
|
91 |
|
92 look->floor_look=(vorbis_look_floor **)_ogg_calloc(info->submaps,sizeof(*look->floor_look)); |
|
93 |
|
94 look->residue_look=(vorbis_look_residue **)_ogg_calloc(info->submaps,sizeof(*look->residue_look)); |
|
95 |
|
96 look->floor_func=(vorbis_func_floor **)_ogg_calloc(info->submaps,sizeof(*look->floor_func)); |
|
97 look->residue_func=(vorbis_func_residue **)_ogg_calloc(info->submaps,sizeof(*look->residue_func)); |
|
98 |
|
99 for(i=0;i<info->submaps;i++){ |
|
100 int floornum=info->floorsubmap[i]; |
|
101 int resnum=info->residuesubmap[i]; |
|
102 |
|
103 look->floor_func[i]=_floor_P[ci->floor_type[floornum]]; |
|
104 look->floor_look[i]=look->floor_func[i]-> |
|
105 look(vd,vm,ci->floor_param[floornum]); |
|
106 look->residue_func[i]=_residue_P[ci->residue_type[resnum]]; |
|
107 look->residue_look[i]=look->residue_func[i]-> |
|
108 look(vd,vm,ci->residue_param[resnum]); |
|
109 |
|
110 } |
|
111 |
|
112 look->ch=vi->channels; |
|
113 |
|
114 return(look); |
36 } |
115 } |
37 |
116 |
38 static int ilog(unsigned int v){ |
117 static int ilog(unsigned int v){ |
39 int ret=0; |
118 int ret=0; |
40 if(v)--v; |
119 if(v)--v; |
44 } |
123 } |
45 return(ret); |
124 return(ret); |
46 } |
125 } |
47 |
126 |
48 /* also responsible for range checking */ |
127 /* also responsible for range checking */ |
49 int mapping_info_unpack(vorbis_info_mapping *info,vorbis_info *vi, |
128 static vorbis_info_mapping *mapping0_unpack(vorbis_info *vi,oggpack_buffer *opb){ |
50 oggpack_buffer *opb){ |
|
51 int i; |
129 int i; |
|
130 vorbis_info_mapping0 *info=(vorbis_info_mapping0 *)_ogg_calloc(1,sizeof(*info)); |
52 codec_setup_info *ci=(codec_setup_info *)vi->codec_setup; |
131 codec_setup_info *ci=(codec_setup_info *)vi->codec_setup; |
53 memset(info,0,sizeof(*info)); |
132 memset(info,0,sizeof(*info)); |
54 |
133 |
55 if(oggpack_read(opb,1)) |
134 if(oggpack_read(opb,1)) |
56 info->submaps=oggpack_read(opb,4)+1; |
135 info->submaps=oggpack_read(opb,4)+1; |
57 else |
136 else |
58 info->submaps=1; |
137 info->submaps=1; |
59 |
138 |
60 if(oggpack_read(opb,1)){ |
139 if(oggpack_read(opb,1)){ |
61 info->coupling_steps=oggpack_read(opb,8)+1; |
140 info->coupling_steps=oggpack_read(opb,8)+1; |
62 info->coupling= |
141 |
63 _ogg_malloc(info->coupling_steps*sizeof(*info->coupling)); |
|
64 |
|
65 for(i=0;i<info->coupling_steps;i++){ |
142 for(i=0;i<info->coupling_steps;i++){ |
66 int testM=info->coupling[i].mag=oggpack_read(opb,ilog(vi->channels)); |
143 int testM=info->coupling_mag[i]=oggpack_read(opb,ilog(vi->channels)); |
67 int testA=info->coupling[i].ang=oggpack_read(opb,ilog(vi->channels)); |
144 int testA=info->coupling_ang[i]=oggpack_read(opb,ilog(vi->channels)); |
68 |
145 |
69 if(testM<0 || |
146 if(testM<0 || |
70 testA<0 || |
147 testA<0 || |
71 testM==testA || |
148 testM==testA || |
72 testM>=vi->channels || |
149 testM>=vi->channels || |
76 } |
153 } |
77 |
154 |
78 if(oggpack_read(opb,2)>0)goto err_out; /* 2,3:reserved */ |
155 if(oggpack_read(opb,2)>0)goto err_out; /* 2,3:reserved */ |
79 |
156 |
80 if(info->submaps>1){ |
157 if(info->submaps>1){ |
81 info->chmuxlist=_ogg_malloc(sizeof(*info->chmuxlist)*vi->channels); |
|
82 for(i=0;i<vi->channels;i++){ |
158 for(i=0;i<vi->channels;i++){ |
83 info->chmuxlist[i]=oggpack_read(opb,4); |
159 info->chmuxlist[i]=oggpack_read(opb,4); |
84 if(info->chmuxlist[i]>=info->submaps)goto err_out; |
160 if(info->chmuxlist[i]>=info->submaps)goto err_out; |
85 } |
161 } |
86 } |
162 } |
87 |
|
88 info->submaplist=_ogg_malloc(sizeof(*info->submaplist)*info->submaps); |
|
89 for(i=0;i<info->submaps;i++){ |
163 for(i=0;i<info->submaps;i++){ |
90 int temp=oggpack_read(opb,8); |
164 int temp=oggpack_read(opb,8); |
91 info->submaplist[i].floor=oggpack_read(opb,8); |
165 if(temp>=ci->times)goto err_out; |
92 if(info->submaplist[i].floor>=ci->floors)goto err_out; |
166 info->floorsubmap[i]=oggpack_read(opb,8); |
93 info->submaplist[i].residue=oggpack_read(opb,8); |
167 if(info->floorsubmap[i]>=ci->floors)goto err_out; |
94 if(info->submaplist[i].residue>=ci->residues)goto err_out; |
168 info->residuesubmap[i]=oggpack_read(opb,8); |
95 } |
169 if(info->residuesubmap[i]>=ci->residues)goto err_out; |
96 |
170 } |
97 return 0; |
171 |
|
172 return info; |
98 |
173 |
99 err_out: |
174 err_out: |
100 mapping_clear_info(info); |
175 mapping0_free_info(info); |
101 return -1; |
176 return(NULL); |
102 } |
177 } |
103 |
178 |
104 int mapping_inverse(vorbis_dsp_state *vd,vorbis_info_mapping *info){ |
179 static int seq=0; |
|
180 static int mapping0_inverse(vorbis_block *vb,vorbis_look_mapping *l){ |
|
181 vorbis_dsp_state *vd=vb->vd; |
105 vorbis_info *vi=vd->vi; |
182 vorbis_info *vi=vd->vi; |
106 codec_setup_info *ci=(codec_setup_info *)vi->codec_setup; |
183 codec_setup_info *ci=(codec_setup_info *)vi->codec_setup; |
|
184 private_state *b=(private_state *)vd->backend_state; |
|
185 vorbis_look_mapping0 *look=(vorbis_look_mapping0 *)l; |
|
186 vorbis_info_mapping0 *info=look->map; |
107 |
187 |
108 int i,j; |
188 int i,j; |
109 long n=ci->blocksizes[vd->W]; |
189 long n=vb->pcmend=ci->blocksizes[vb->W]; |
110 |
190 |
111 ogg_int32_t **pcmbundle= |
191 ogg_int32_t **pcmbundle=(ogg_int32_t **)alloca(sizeof(*pcmbundle)*vi->channels); |
112 (ogg_int32_t **)alloca(sizeof(*pcmbundle)*vi->channels); |
192 int *zerobundle=(int *)alloca(sizeof(*zerobundle)*vi->channels); |
113 int *zerobundle= |
|
114 (int *)alloca(sizeof(*zerobundle)*vi->channels); |
|
115 int *nonzero= |
|
116 (int *)alloca(sizeof(*nonzero)*vi->channels); |
|
117 ogg_int32_t **floormemo= |
|
118 (void **)alloca(sizeof(*floormemo)*vi->channels); |
|
119 |
193 |
|
194 int *nonzero =(int *)alloca(sizeof(*nonzero)*vi->channels); |
|
195 void **floormemo=(void **)alloca(sizeof(*floormemo)*vi->channels); |
|
196 |
|
197 /* time domain information decode (note that applying the |
|
198 information would have to happen later; we'll probably add a |
|
199 function entry to the harness for that later */ |
|
200 /* NOT IMPLEMENTED */ |
|
201 |
120 /* recover the spectral envelope; store it in the PCM vector for now */ |
202 /* recover the spectral envelope; store it in the PCM vector for now */ |
121 for(i=0;i<vi->channels;i++){ |
203 for(i=0;i<vi->channels;i++){ |
122 int submap=0; |
204 int submap=info->chmuxlist[i]; |
123 int floorno; |
205 floormemo[i]=look->floor_func[submap]-> |
124 |
206 inverse1(vb,look->floor_look[submap]); |
125 if(info->submaps>1) |
|
126 submap=info->chmuxlist[i]; |
|
127 floorno=info->submaplist[submap].floor; |
|
128 |
|
129 if(ci->floor_type[floorno]){ |
|
130 /* floor 1 */ |
|
131 floormemo[i]=alloca(sizeof(*floormemo[i])* |
|
132 floor1_memosize(ci->floor_param[floorno])); |
|
133 floormemo[i]=floor1_inverse1(vd,ci->floor_param[floorno],floormemo[i]); |
|
134 }else{ |
|
135 /* floor 0 */ |
|
136 floormemo[i]=alloca(sizeof(*floormemo[i])* |
|
137 floor0_memosize(ci->floor_param[floorno])); |
|
138 floormemo[i]=floor0_inverse1(vd,ci->floor_param[floorno],floormemo[i]); |
|
139 } |
|
140 |
|
141 if(floormemo[i]) |
207 if(floormemo[i]) |
142 nonzero[i]=1; |
208 nonzero[i]=1; |
143 else |
209 else |
144 nonzero[i]=0; |
210 nonzero[i]=0; |
145 memset(vd->work[i],0,sizeof(*vd->work[i])*n/2); |
211 memset(vb->pcm[i],0,sizeof(*vb->pcm[i])*n/2); |
146 } |
212 } |
147 |
213 |
148 /* channel coupling can 'dirty' the nonzero listing */ |
214 /* channel coupling can 'dirty' the nonzero listing */ |
149 for(i=0;i<info->coupling_steps;i++){ |
215 for(i=0;i<info->coupling_steps;i++){ |
150 if(nonzero[info->coupling[i].mag] || |
216 if(nonzero[info->coupling_mag[i]] || |
151 nonzero[info->coupling[i].ang]){ |
217 nonzero[info->coupling_ang[i]]){ |
152 nonzero[info->coupling[i].mag]=1; |
218 nonzero[info->coupling_mag[i]]=1; |
153 nonzero[info->coupling[i].ang]=1; |
219 nonzero[info->coupling_ang[i]]=1; |
154 } |
220 } |
155 } |
221 } |
156 |
222 |
157 /* recover the residue into our working vectors */ |
223 /* recover the residue into our working vectors */ |
158 for(i=0;i<info->submaps;i++){ |
224 for(i=0;i<info->submaps;i++){ |
159 int ch_in_bundle=0; |
225 int ch_in_bundle=0; |
160 for(j=0;j<vi->channels;j++){ |
226 for(j=0;j<vi->channels;j++){ |
161 if(!info->chmuxlist || info->chmuxlist[j]==i){ |
227 if(info->chmuxlist[j]==i){ |
162 if(nonzero[j]) |
228 if(nonzero[j]) |
163 zerobundle[ch_in_bundle]=1; |
229 zerobundle[ch_in_bundle]=1; |
164 else |
230 else |
165 zerobundle[ch_in_bundle]=0; |
231 zerobundle[ch_in_bundle]=0; |
166 pcmbundle[ch_in_bundle++]=vd->work[j]; |
232 pcmbundle[ch_in_bundle++]=vb->pcm[j]; |
167 } |
233 } |
168 } |
234 } |
169 |
235 |
170 res_inverse(vd,ci->residue_param+info->submaplist[i].residue, |
236 look->residue_func[i]->inverse(vb,look->residue_look[i], |
171 pcmbundle,zerobundle,ch_in_bundle); |
237 pcmbundle,zerobundle,ch_in_bundle); |
172 } |
238 } |
173 |
239 |
174 //for(j=0;j<vi->channels;j++) |
240 //for(j=0;j<vi->channels;j++) |
175 //_analysis_output("coupled",seq+j,vb->pcm[j],-8,n/2,0,0); |
241 //_analysis_output("coupled",seq+j,vb->pcm[j],-8,n/2,0,0); |
|
242 |
176 |
243 |
177 /* channel coupling */ |
244 /* channel coupling */ |
178 for(i=info->coupling_steps-1;i>=0;i--){ |
245 for(i=info->coupling_steps-1;i>=0;i--){ |
179 ogg_int32_t *pcmM=vd->work[info->coupling[i].mag]; |
246 ogg_int32_t *pcmM=vb->pcm[info->coupling_mag[i]]; |
180 ogg_int32_t *pcmA=vd->work[info->coupling[i].ang]; |
247 ogg_int32_t *pcmA=vb->pcm[info->coupling_ang[i]]; |
181 |
248 |
182 for(j=0;j<n/2;j++){ |
249 for(j=0;j<n/2;j++){ |
183 ogg_int32_t mag=pcmM[j]; |
250 ogg_int32_t mag=pcmM[j]; |
184 ogg_int32_t ang=pcmA[j]; |
251 ogg_int32_t ang=pcmA[j]; |
185 |
252 |
205 //for(j=0;j<vi->channels;j++) |
272 //for(j=0;j<vi->channels;j++) |
206 //_analysis_output("residue",seq+j,vb->pcm[j],-8,n/2,0,0); |
273 //_analysis_output("residue",seq+j,vb->pcm[j],-8,n/2,0,0); |
207 |
274 |
208 /* compute and apply spectral envelope */ |
275 /* compute and apply spectral envelope */ |
209 for(i=0;i<vi->channels;i++){ |
276 for(i=0;i<vi->channels;i++){ |
210 ogg_int32_t *pcm=vd->work[i]; |
277 ogg_int32_t *pcm=vb->pcm[i]; |
211 int submap=0; |
278 int submap=info->chmuxlist[i]; |
212 int floorno; |
279 look->floor_func[submap]-> |
213 |
280 inverse2(vb,look->floor_look[submap],floormemo[i],pcm); |
214 if(info->submaps>1) |
|
215 submap=info->chmuxlist[i]; |
|
216 floorno=info->submaplist[submap].floor; |
|
217 |
|
218 if(ci->floor_type[floorno]){ |
|
219 /* floor 1 */ |
|
220 floor1_inverse2(vd,ci->floor_param[floorno],floormemo[i],pcm); |
|
221 }else{ |
|
222 /* floor 0 */ |
|
223 floor0_inverse2(vd,ci->floor_param[floorno],floormemo[i],pcm); |
|
224 } |
|
225 } |
281 } |
226 |
282 |
227 //for(j=0;j<vi->channels;j++) |
283 //for(j=0;j<vi->channels;j++) |
228 //_analysis_output("mdct",seq+j,vb->pcm[j],-24,n/2,0,1); |
284 //_analysis_output("mdct",seq+j,vb->pcm[j],-24,n/2,0,1); |
229 |
285 |
230 /* transform the PCM data; takes PCM vector, vb; modifies PCM vector */ |
286 /* transform the PCM data; takes PCM vector, vb; modifies PCM vector */ |
231 /* only MDCT right now.... */ |
287 /* only MDCT right now.... */ |
232 for(i=0;i<vi->channels;i++) |
288 for(i=0;i<vi->channels;i++){ |
233 mdct_backward(n,vd->work[i]); |
289 ogg_int32_t *pcm=vb->pcm[i]; |
|
290 mdct_backward(n,pcm,pcm); |
|
291 } |
234 |
292 |
235 //for(j=0;j<vi->channels;j++) |
293 //for(j=0;j<vi->channels;j++) |
236 //_analysis_output("imdct",seq+j,vb->pcm[j],-24,n,0,0); |
294 //_analysis_output("imdct",seq+j,vb->pcm[j],-24,n,0,0); |
237 |
295 |
|
296 /* window the data */ |
|
297 for(i=0;i<vi->channels;i++){ |
|
298 ogg_int32_t *pcm=vb->pcm[i]; |
|
299 if(nonzero[i]) |
|
300 _vorbis_apply_window(pcm,b->window,ci->blocksizes,vb->lW,vb->W,vb->nW); |
|
301 else |
|
302 for(j=0;j<n;j++) |
|
303 pcm[j]=0; |
|
304 |
|
305 } |
|
306 |
|
307 //for(j=0;j<vi->channels;j++) |
|
308 //_analysis_output("window",seq+j,vb->pcm[j],-24,n,0,0); |
|
309 |
|
310 seq+=vi->channels; |
238 /* all done! */ |
311 /* all done! */ |
239 return(0); |
312 return(0); |
240 } |
313 } |
|
314 |
|
315 /* export hooks */ |
|
316 vorbis_func_mapping mapping0_exportbundle={ |
|
317 &mapping0_unpack, |
|
318 &mapping0_look, |
|
319 &mapping0_free_info, |
|
320 &mapping0_free_look, |
|
321 &mapping0_inverse |
|
322 }; |