Line | Count | Source |
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-2002 * |
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/ogg.h> |
23 | | #include "ivorbiscodec.h" |
24 | | #include "mdct.h" |
25 | | #include "codec_internal.h" |
26 | | #include "codebook.h" |
27 | | #include "window.h" |
28 | | #include "registry.h" |
29 | | #include "misc.h" |
30 | | |
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 | 7.75k | static void mapping0_free_info(vorbis_info_mapping *i){ |
57 | 7.75k | vorbis_info_mapping0 *info=(vorbis_info_mapping0 *)i; |
58 | 7.75k | if(info){ |
59 | 7.75k | memset(info,0,sizeof(*info)); |
60 | 7.75k | _ogg_free(info); |
61 | 7.75k | } |
62 | 7.75k | } |
63 | | |
64 | 9.05k | static void mapping0_free_look(vorbis_look_mapping *look){ |
65 | 9.05k | int i; |
66 | 9.05k | vorbis_look_mapping0 *l=(vorbis_look_mapping0 *)look; |
67 | 9.05k | if(l){ |
68 | | |
69 | 19.6k | for(i=0;i<l->map->submaps;i++){ |
70 | 10.5k | l->floor_func[i]->free_look(l->floor_look[i]); |
71 | 10.5k | l->residue_func[i]->free_look(l->residue_look[i]); |
72 | 10.5k | } |
73 | | |
74 | 9.05k | _ogg_free(l->floor_func); |
75 | 9.05k | _ogg_free(l->residue_func); |
76 | 9.05k | _ogg_free(l->floor_look); |
77 | 9.05k | _ogg_free(l->residue_look); |
78 | 9.05k | memset(l,0,sizeof(*l)); |
79 | 9.05k | _ogg_free(l); |
80 | 9.05k | } |
81 | 9.05k | } |
82 | | |
83 | | static vorbis_look_mapping *mapping0_look(vorbis_dsp_state *vd,vorbis_info_mode *vm, |
84 | 9.05k | vorbis_info_mapping *m){ |
85 | 9.05k | int i; |
86 | 9.05k | vorbis_info *vi=vd->vi; |
87 | 9.05k | codec_setup_info *ci=(codec_setup_info *)vi->codec_setup; |
88 | 9.05k | vorbis_look_mapping0 *look=(vorbis_look_mapping0 *)_ogg_calloc(1,sizeof(*look)); |
89 | 9.05k | vorbis_info_mapping0 *info=look->map=(vorbis_info_mapping0 *)m; |
90 | 9.05k | look->mode=vm; |
91 | | |
92 | 9.05k | look->floor_look=(vorbis_look_floor **)_ogg_calloc(info->submaps,sizeof(*look->floor_look)); |
93 | | |
94 | 9.05k | look->residue_look=(vorbis_look_residue **)_ogg_calloc(info->submaps,sizeof(*look->residue_look)); |
95 | | |
96 | 9.05k | look->floor_func=(vorbis_func_floor **)_ogg_calloc(info->submaps,sizeof(*look->floor_func)); |
97 | 9.05k | look->residue_func=(vorbis_func_residue **)_ogg_calloc(info->submaps,sizeof(*look->residue_func)); |
98 | | |
99 | 19.6k | for(i=0;i<info->submaps;i++){ |
100 | 10.5k | int floornum=info->floorsubmap[i]; |
101 | 10.5k | int resnum=info->residuesubmap[i]; |
102 | | |
103 | 10.5k | look->floor_func[i]=_floor_P[ci->floor_type[floornum]]; |
104 | 10.5k | look->floor_look[i]=look->floor_func[i]-> |
105 | 10.5k | look(vd,vm,ci->floor_param[floornum]); |
106 | 10.5k | look->residue_func[i]=_residue_P[ci->residue_type[resnum]]; |
107 | 10.5k | look->residue_look[i]=look->residue_func[i]-> |
108 | 10.5k | look(vd,vm,ci->residue_param[resnum]); |
109 | | |
110 | 10.5k | } |
111 | | |
112 | 9.05k | look->ch=vi->channels; |
113 | | |
114 | 9.05k | return(look); |
115 | 9.05k | } |
116 | | |
117 | 2.54k | static int ilog(unsigned int v){ |
118 | 2.54k | int ret=0; |
119 | 2.54k | if(v)--v; |
120 | 11.5k | while(v){ |
121 | 8.96k | ret++; |
122 | 8.96k | v>>=1; |
123 | 8.96k | } |
124 | 2.54k | return(ret); |
125 | 2.54k | } |
126 | | |
127 | | /* also responsible for range checking */ |
128 | 7.75k | static vorbis_info_mapping *mapping0_unpack(vorbis_info *vi,oggpack_buffer *opb){ |
129 | 7.75k | int i,b; |
130 | 7.75k | vorbis_info_mapping0 *info=(vorbis_info_mapping0 *)_ogg_calloc(1,sizeof(*info)); |
131 | 7.75k | codec_setup_info *ci=(codec_setup_info *)vi->codec_setup; |
132 | 7.75k | memset(info,0,sizeof(*info)); |
133 | | |
134 | 7.75k | b=oggpack_read(opb,1); |
135 | 7.75k | if(b<0)goto err_out; |
136 | 7.75k | if(b){ |
137 | 382 | info->submaps=oggpack_read(opb,4)+1; |
138 | 382 | if(info->submaps<=0)goto err_out; |
139 | 382 | }else |
140 | 7.37k | info->submaps=1; |
141 | | |
142 | 7.75k | b=oggpack_read(opb,1); |
143 | 7.75k | if(b<0)goto err_out; |
144 | 7.75k | if(b){ |
145 | 563 | info->coupling_steps=oggpack_read(opb,8)+1; |
146 | 563 | if(info->coupling_steps<=0)goto err_out; |
147 | 1.79k | for(i=0;i<info->coupling_steps;i++){ |
148 | 1.27k | int testM=info->coupling_mag[i]=oggpack_read(opb,ilog(vi->channels)); |
149 | 1.27k | int testA=info->coupling_ang[i]=oggpack_read(opb,ilog(vi->channels)); |
150 | | |
151 | 1.27k | if(testM<0 || |
152 | 1.25k | testA<0 || |
153 | 1.24k | testM==testA || |
154 | 1.23k | testM>=vi->channels || |
155 | 1.23k | testA>=vi->channels) goto err_out; |
156 | 1.27k | } |
157 | | |
158 | 561 | } |
159 | | |
160 | 7.70k | if(oggpack_read(opb,2)!=0)goto err_out; /* 2,3:reserved */ |
161 | | |
162 | 7.69k | if(info->submaps>1){ |
163 | 1.25k | for(i=0;i<vi->channels;i++){ |
164 | 982 | info->chmuxlist[i]=oggpack_read(opb,4); |
165 | 982 | if(info->chmuxlist[i]>=info->submaps || info->chmuxlist[i]<0)goto err_out; |
166 | 982 | } |
167 | 289 | } |
168 | 16.0k | for(i=0;i<info->submaps;i++){ |
169 | 8.42k | int temp=oggpack_read(opb,8); |
170 | 8.42k | if(temp>=ci->times)goto err_out; |
171 | 8.42k | info->floorsubmap[i]=oggpack_read(opb,8); |
172 | 8.42k | if(info->floorsubmap[i]>=ci->floors || info->floorsubmap[i]<0)goto err_out; |
173 | 8.40k | info->residuesubmap[i]=oggpack_read(opb,8); |
174 | 8.40k | if(info->residuesubmap[i]>=ci->residues || info->residuesubmap[i]<0) |
175 | 17 | goto err_out; |
176 | 8.40k | } |
177 | | |
178 | 7.64k | return info; |
179 | | |
180 | 113 | err_out: |
181 | 113 | mapping0_free_info(info); |
182 | 113 | return(NULL); |
183 | 7.68k | } |
184 | | |
185 | | static int seq=0; |
186 | 43.3k | static int mapping0_inverse(vorbis_block *vb,vorbis_look_mapping *l){ |
187 | 43.3k | vorbis_dsp_state *vd=vb->vd; |
188 | 43.3k | vorbis_info *vi=vd->vi; |
189 | 43.3k | codec_setup_info *ci=(codec_setup_info *)vi->codec_setup; |
190 | 43.3k | private_state *b=(private_state *)vd->backend_state; |
191 | 43.3k | vorbis_look_mapping0 *look=(vorbis_look_mapping0 *)l; |
192 | 43.3k | vorbis_info_mapping0 *info=look->map; |
193 | | |
194 | 43.3k | int i,j; |
195 | 43.3k | long n=vb->pcmend=ci->blocksizes[vb->W]; |
196 | | |
197 | 43.3k | ogg_int32_t **pcmbundle=(ogg_int32_t **)alloca(sizeof(*pcmbundle)*vi->channels); |
198 | 43.3k | int *zerobundle=(int *)alloca(sizeof(*zerobundle)*vi->channels); |
199 | | |
200 | 43.3k | int *nonzero =(int *)alloca(sizeof(*nonzero)*vi->channels); |
201 | 43.3k | void **floormemo=(void **)alloca(sizeof(*floormemo)*vi->channels); |
202 | | |
203 | | /* time domain information decode (note that applying the |
204 | | information would have to happen later; we'll probably add a |
205 | | function entry to the harness for that later */ |
206 | | /* NOT IMPLEMENTED */ |
207 | | |
208 | | /* recover the spectral envelope; store it in the PCM vector for now */ |
209 | 5.14M | for(i=0;i<vi->channels;i++){ |
210 | 5.09M | int submap=info->chmuxlist[i]; |
211 | 5.09M | floormemo[i]=look->floor_func[submap]-> |
212 | 5.09M | inverse1(vb,look->floor_look[submap]); |
213 | 5.09M | if(floormemo[i]) |
214 | 94.6k | nonzero[i]=1; |
215 | 5.00M | else |
216 | 5.00M | nonzero[i]=0; |
217 | 5.09M | memset(vb->pcm[i],0,sizeof(*vb->pcm[i])*n/2); |
218 | 5.09M | } |
219 | | |
220 | | /* channel coupling can 'dirty' the nonzero listing */ |
221 | 53.0k | for(i=0;i<info->coupling_steps;i++){ |
222 | 9.71k | if(nonzero[info->coupling_mag[i]] || |
223 | 7.75k | nonzero[info->coupling_ang[i]]){ |
224 | 4.58k | nonzero[info->coupling_mag[i]]=1; |
225 | 4.58k | nonzero[info->coupling_ang[i]]=1; |
226 | 4.58k | } |
227 | 9.71k | } |
228 | | |
229 | | /* recover the residue into our working vectors */ |
230 | 88.9k | for(i=0;i<info->submaps;i++){ |
231 | 45.6k | int ch_in_bundle=0; |
232 | 5.14M | for(j=0;j<vi->channels;j++){ |
233 | 5.10M | if(info->chmuxlist[j]==i){ |
234 | 5.09M | if(nonzero[j]) |
235 | 98.7k | zerobundle[ch_in_bundle]=1; |
236 | 5.00M | else |
237 | 5.00M | zerobundle[ch_in_bundle]=0; |
238 | 5.09M | pcmbundle[ch_in_bundle++]=vb->pcm[j]; |
239 | 5.09M | } |
240 | 5.10M | } |
241 | | |
242 | 45.6k | look->residue_func[i]->inverse(vb,look->residue_look[i], |
243 | 45.6k | pcmbundle,zerobundle,ch_in_bundle); |
244 | 45.6k | } |
245 | | |
246 | | //for(j=0;j<vi->channels;j++) |
247 | | //_analysis_output("coupled",seq+j,vb->pcm[j],-8,n/2,0,0); |
248 | | |
249 | | |
250 | | /* channel coupling */ |
251 | 53.0k | for(i=info->coupling_steps-1;i>=0;i--){ |
252 | 9.71k | ogg_int32_t *pcmM=vb->pcm[info->coupling_mag[i]]; |
253 | 9.71k | ogg_int32_t *pcmA=vb->pcm[info->coupling_ang[i]]; |
254 | | |
255 | 3.44M | for(j=0;j<n/2;j++){ |
256 | 3.43M | ogg_int32_t mag=pcmM[j]; |
257 | 3.43M | ogg_int32_t ang=pcmA[j]; |
258 | | |
259 | 3.43M | if(mag>0) |
260 | 15.7k | if(ang>0){ |
261 | 11.4k | pcmM[j]=mag; |
262 | 11.4k | pcmA[j]=mag-ang; |
263 | 11.4k | }else{ |
264 | 4.28k | pcmA[j]=mag; |
265 | 4.28k | pcmM[j]=mag+ang; |
266 | 4.28k | } |
267 | 3.41M | else |
268 | 3.41M | if(ang>0){ |
269 | 4.10k | pcmM[j]=mag; |
270 | 4.10k | pcmA[j]=mag+ang; |
271 | 3.41M | }else{ |
272 | 3.41M | pcmA[j]=mag; |
273 | 3.41M | pcmM[j]=mag-ang; |
274 | 3.41M | } |
275 | 3.43M | } |
276 | 9.71k | } |
277 | | |
278 | | //for(j=0;j<vi->channels;j++) |
279 | | //_analysis_output("residue",seq+j,vb->pcm[j],-8,n/2,0,0); |
280 | | |
281 | | /* compute and apply spectral envelope */ |
282 | 5.14M | for(i=0;i<vi->channels;i++){ |
283 | 5.09M | ogg_int32_t *pcm=vb->pcm[i]; |
284 | 5.09M | int submap=info->chmuxlist[i]; |
285 | 5.09M | look->floor_func[submap]-> |
286 | 5.09M | inverse2(vb,look->floor_look[submap],floormemo[i],pcm); |
287 | 5.09M | } |
288 | | |
289 | | //for(j=0;j<vi->channels;j++) |
290 | | //_analysis_output("mdct",seq+j,vb->pcm[j],-24,n/2,0,1); |
291 | | |
292 | | /* transform the PCM data; takes PCM vector, vb; modifies PCM vector */ |
293 | | /* only MDCT right now.... */ |
294 | 5.14M | for(i=0;i<vi->channels;i++){ |
295 | 5.09M | ogg_int32_t *pcm=vb->pcm[i]; |
296 | 5.09M | mdct_backward(n,pcm,pcm); |
297 | 5.09M | } |
298 | | |
299 | | //for(j=0;j<vi->channels;j++) |
300 | | //_analysis_output("imdct",seq+j,vb->pcm[j],-24,n,0,0); |
301 | | |
302 | | /* window the data */ |
303 | 5.14M | for(i=0;i<vi->channels;i++){ |
304 | 5.09M | ogg_int32_t *pcm=vb->pcm[i]; |
305 | 5.09M | if(nonzero[i]) |
306 | 98.7k | _vorbis_apply_window(pcm,b->window,ci->blocksizes,vb->lW,vb->W,vb->nW); |
307 | 5.00M | else |
308 | 6.42G | for(j=0;j<n;j++) |
309 | 6.41G | pcm[j]=0; |
310 | | |
311 | 5.09M | } |
312 | | |
313 | | //for(j=0;j<vi->channels;j++) |
314 | | //_analysis_output("window",seq+j,vb->pcm[j],-24,n,0,0); |
315 | | |
316 | 43.3k | seq+=vi->channels; |
317 | | /* all done! */ |
318 | 43.3k | return(0); |
319 | 43.3k | } |
320 | | |
321 | | /* export hooks */ |
322 | | vorbis_func_mapping mapping0_exportbundle={ |
323 | | &mapping0_unpack, |
324 | | &mapping0_look, |
325 | | &mapping0_free_info, |
326 | | &mapping0_free_look, |
327 | | &mapping0_inverse |
328 | | }; |