Line | Count | Source (jump to first uncovered line) |
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 | 8.59k | static void mapping0_free_info(vorbis_info_mapping *i){ |
57 | 8.59k | vorbis_info_mapping0 *info=(vorbis_info_mapping0 *)i; |
58 | 8.59k | if(info){ |
59 | 8.59k | memset(info,0,sizeof(*info)); |
60 | 8.59k | _ogg_free(info); |
61 | 8.59k | } |
62 | 8.59k | } |
63 | | |
64 | 10.1k | static void mapping0_free_look(vorbis_look_mapping *look){ |
65 | 10.1k | int i; |
66 | 10.1k | vorbis_look_mapping0 *l=(vorbis_look_mapping0 *)look; |
67 | 10.1k | if(l){ |
68 | | |
69 | 22.0k | for(i=0;i<l->map->submaps;i++){ |
70 | 11.9k | l->floor_func[i]->free_look(l->floor_look[i]); |
71 | 11.9k | l->residue_func[i]->free_look(l->residue_look[i]); |
72 | 11.9k | } |
73 | | |
74 | 10.1k | _ogg_free(l->floor_func); |
75 | 10.1k | _ogg_free(l->residue_func); |
76 | 10.1k | _ogg_free(l->floor_look); |
77 | 10.1k | _ogg_free(l->residue_look); |
78 | 10.1k | memset(l,0,sizeof(*l)); |
79 | 10.1k | _ogg_free(l); |
80 | 10.1k | } |
81 | 10.1k | } |
82 | | |
83 | | static vorbis_look_mapping *mapping0_look(vorbis_dsp_state *vd,vorbis_info_mode *vm, |
84 | 10.1k | vorbis_info_mapping *m){ |
85 | 10.1k | int i; |
86 | 10.1k | vorbis_info *vi=vd->vi; |
87 | 10.1k | codec_setup_info *ci=(codec_setup_info *)vi->codec_setup; |
88 | 10.1k | vorbis_look_mapping0 *look=(vorbis_look_mapping0 *)_ogg_calloc(1,sizeof(*look)); |
89 | 10.1k | vorbis_info_mapping0 *info=look->map=(vorbis_info_mapping0 *)m; |
90 | 10.1k | look->mode=vm; |
91 | | |
92 | 10.1k | look->floor_look=(vorbis_look_floor **)_ogg_calloc(info->submaps,sizeof(*look->floor_look)); |
93 | | |
94 | 10.1k | look->residue_look=(vorbis_look_residue **)_ogg_calloc(info->submaps,sizeof(*look->residue_look)); |
95 | | |
96 | 10.1k | look->floor_func=(vorbis_func_floor **)_ogg_calloc(info->submaps,sizeof(*look->floor_func)); |
97 | 10.1k | look->residue_func=(vorbis_func_residue **)_ogg_calloc(info->submaps,sizeof(*look->residue_func)); |
98 | | |
99 | 22.0k | for(i=0;i<info->submaps;i++){ |
100 | 11.9k | int floornum=info->floorsubmap[i]; |
101 | 11.9k | int resnum=info->residuesubmap[i]; |
102 | | |
103 | 11.9k | look->floor_func[i]=_floor_P[ci->floor_type[floornum]]; |
104 | 11.9k | look->floor_look[i]=look->floor_func[i]-> |
105 | 11.9k | look(vd,vm,ci->floor_param[floornum]); |
106 | 11.9k | look->residue_func[i]=_residue_P[ci->residue_type[resnum]]; |
107 | 11.9k | look->residue_look[i]=look->residue_func[i]-> |
108 | 11.9k | look(vd,vm,ci->residue_param[resnum]); |
109 | | |
110 | 11.9k | } |
111 | | |
112 | 10.1k | look->ch=vi->channels; |
113 | | |
114 | 10.1k | return(look); |
115 | 10.1k | } |
116 | | |
117 | 2.85k | static int ilog(unsigned int v){ |
118 | 2.85k | int ret=0; |
119 | 2.85k | if(v)--v; |
120 | 13.1k | while(v){ |
121 | 10.2k | ret++; |
122 | 10.2k | v>>=1; |
123 | 10.2k | } |
124 | 2.85k | return(ret); |
125 | 2.85k | } |
126 | | |
127 | | /* also responsible for range checking */ |
128 | 8.59k | static vorbis_info_mapping *mapping0_unpack(vorbis_info *vi,oggpack_buffer *opb){ |
129 | 8.59k | int i,b; |
130 | 8.59k | vorbis_info_mapping0 *info=(vorbis_info_mapping0 *)_ogg_calloc(1,sizeof(*info)); |
131 | 8.59k | codec_setup_info *ci=(codec_setup_info *)vi->codec_setup; |
132 | 8.59k | memset(info,0,sizeof(*info)); |
133 | | |
134 | 8.59k | b=oggpack_read(opb,1); |
135 | 8.59k | if(b<0)goto err_out; |
136 | 8.58k | if(b){ |
137 | 498 | info->submaps=oggpack_read(opb,4)+1; |
138 | 498 | if(info->submaps<=0)goto err_out; |
139 | 498 | }else |
140 | 8.08k | info->submaps=1; |
141 | | |
142 | 8.58k | b=oggpack_read(opb,1); |
143 | 8.58k | if(b<0)goto err_out; |
144 | 8.58k | if(b){ |
145 | 692 | info->coupling_steps=oggpack_read(opb,8)+1; |
146 | 692 | if(info->coupling_steps<=0)goto err_out; |
147 | 2.06k | for(i=0;i<info->coupling_steps;i++){ |
148 | 1.42k | int testM=info->coupling_mag[i]=oggpack_read(opb,ilog(vi->channels)); |
149 | 1.42k | int testA=info->coupling_ang[i]=oggpack_read(opb,ilog(vi->channels)); |
150 | | |
151 | 1.42k | if(testM<0 || |
152 | 1.42k | testA<0 || |
153 | 1.42k | testM==testA || |
154 | 1.42k | testM>=vi->channels || |
155 | 1.42k | testA>=vi->channels) goto err_out; |
156 | 1.42k | } |
157 | | |
158 | 689 | } |
159 | | |
160 | 8.53k | if(oggpack_read(opb,2)!=0)goto err_out; /* 2,3:reserved */ |
161 | | |
162 | 8.52k | if(info->submaps>1){ |
163 | 2.11k | for(i=0;i<vi->channels;i++){ |
164 | 1.82k | info->chmuxlist[i]=oggpack_read(opb,4); |
165 | 1.82k | if(info->chmuxlist[i]>=info->submaps || info->chmuxlist[i]<0)goto err_out; |
166 | 1.82k | } |
167 | 314 | } |
168 | 17.8k | for(i=0;i<info->submaps;i++){ |
169 | 9.35k | int temp=oggpack_read(opb,8); |
170 | 9.35k | if(temp>=ci->times)goto err_out; |
171 | 9.33k | info->floorsubmap[i]=oggpack_read(opb,8); |
172 | 9.33k | if(info->floorsubmap[i]>=ci->floors || info->floorsubmap[i]<0)goto err_out; |
173 | 9.31k | info->residuesubmap[i]=oggpack_read(opb,8); |
174 | 9.31k | if(info->residuesubmap[i]>=ci->residues || info->residuesubmap[i]<0) |
175 | 16 | goto err_out; |
176 | 9.31k | } |
177 | | |
178 | 8.45k | return info; |
179 | | |
180 | 134 | err_out: |
181 | 134 | mapping0_free_info(info); |
182 | 134 | return(NULL); |
183 | 8.50k | } |
184 | | |
185 | | static int seq=0; |
186 | 33.6k | static int mapping0_inverse(vorbis_block *vb,vorbis_look_mapping *l){ |
187 | 33.6k | vorbis_dsp_state *vd=vb->vd; |
188 | 33.6k | vorbis_info *vi=vd->vi; |
189 | 33.6k | codec_setup_info *ci=(codec_setup_info *)vi->codec_setup; |
190 | 33.6k | private_state *b=(private_state *)vd->backend_state; |
191 | 33.6k | vorbis_look_mapping0 *look=(vorbis_look_mapping0 *)l; |
192 | 33.6k | vorbis_info_mapping0 *info=look->map; |
193 | | |
194 | 33.6k | int i,j; |
195 | 33.6k | long n=vb->pcmend=ci->blocksizes[vb->W]; |
196 | | |
197 | 33.6k | ogg_int32_t **pcmbundle=(ogg_int32_t **)alloca(sizeof(*pcmbundle)*vi->channels); |
198 | 33.6k | int *zerobundle=(int *)alloca(sizeof(*zerobundle)*vi->channels); |
199 | | |
200 | 33.6k | int *nonzero =(int *)alloca(sizeof(*nonzero)*vi->channels); |
201 | 33.6k | 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 | 2.99M | for(i=0;i<vi->channels;i++){ |
210 | 2.96M | int submap=info->chmuxlist[i]; |
211 | 2.96M | floormemo[i]=look->floor_func[submap]-> |
212 | 2.96M | inverse1(vb,look->floor_look[submap]); |
213 | 2.96M | if(floormemo[i]) |
214 | 76.0k | nonzero[i]=1; |
215 | 2.88M | else |
216 | 2.88M | nonzero[i]=0; |
217 | 2.96M | memset(vb->pcm[i],0,sizeof(*vb->pcm[i])*n/2); |
218 | 2.96M | } |
219 | | |
220 | | /* channel coupling can 'dirty' the nonzero listing */ |
221 | 39.2k | for(i=0;i<info->coupling_steps;i++){ |
222 | 5.58k | if(nonzero[info->coupling_mag[i]] || |
223 | 5.58k | nonzero[info->coupling_ang[i]]){ |
224 | 2.67k | nonzero[info->coupling_mag[i]]=1; |
225 | 2.67k | nonzero[info->coupling_ang[i]]=1; |
226 | 2.67k | } |
227 | 5.58k | } |
228 | | |
229 | | /* recover the residue into our working vectors */ |
230 | 70.1k | for(i=0;i<info->submaps;i++){ |
231 | 36.4k | int ch_in_bundle=0; |
232 | 3.02M | for(j=0;j<vi->channels;j++){ |
233 | 2.98M | if(info->chmuxlist[j]==i){ |
234 | 2.96M | if(nonzero[j]) |
235 | 78.5k | zerobundle[ch_in_bundle]=1; |
236 | 2.88M | else |
237 | 2.88M | zerobundle[ch_in_bundle]=0; |
238 | 2.96M | pcmbundle[ch_in_bundle++]=vb->pcm[j]; |
239 | 2.96M | } |
240 | 2.98M | } |
241 | | |
242 | 36.4k | look->residue_func[i]->inverse(vb,look->residue_look[i], |
243 | 36.4k | pcmbundle,zerobundle,ch_in_bundle); |
244 | 36.4k | } |
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 | 39.2k | for(i=info->coupling_steps-1;i>=0;i--){ |
252 | 5.58k | ogg_int32_t *pcmM=vb->pcm[info->coupling_mag[i]]; |
253 | 5.58k | ogg_int32_t *pcmA=vb->pcm[info->coupling_ang[i]]; |
254 | | |
255 | 3.59M | for(j=0;j<n/2;j++){ |
256 | 3.58M | ogg_int32_t mag=pcmM[j]; |
257 | 3.58M | ogg_int32_t ang=pcmA[j]; |
258 | | |
259 | 3.58M | if(mag>0) |
260 | 13.4k | if(ang>0){ |
261 | 7.69k | pcmM[j]=mag; |
262 | 7.69k | pcmA[j]=mag-ang; |
263 | 7.69k | }else{ |
264 | 5.79k | pcmA[j]=mag; |
265 | 5.79k | pcmM[j]=mag+ang; |
266 | 5.79k | } |
267 | 3.57M | else |
268 | 3.57M | if(ang>0){ |
269 | 4.67k | pcmM[j]=mag; |
270 | 4.67k | pcmA[j]=mag+ang; |
271 | 3.56M | }else{ |
272 | 3.56M | pcmA[j]=mag; |
273 | 3.56M | pcmM[j]=mag-ang; |
274 | 3.56M | } |
275 | 3.58M | } |
276 | 5.58k | } |
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 | 2.99M | for(i=0;i<vi->channels;i++){ |
283 | 2.96M | ogg_int32_t *pcm=vb->pcm[i]; |
284 | 2.96M | int submap=info->chmuxlist[i]; |
285 | 2.96M | look->floor_func[submap]-> |
286 | 2.96M | inverse2(vb,look->floor_look[submap],floormemo[i],pcm); |
287 | 2.96M | } |
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 | 2.99M | for(i=0;i<vi->channels;i++){ |
295 | 2.96M | ogg_int32_t *pcm=vb->pcm[i]; |
296 | 2.96M | mdct_backward(n,pcm,pcm); |
297 | 2.96M | } |
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 | 2.99M | for(i=0;i<vi->channels;i++){ |
304 | 2.96M | ogg_int32_t *pcm=vb->pcm[i]; |
305 | 2.96M | if(nonzero[i]) |
306 | 78.5k | _vorbis_apply_window(pcm,b->window,ci->blocksizes,vb->lW,vb->W,vb->nW); |
307 | 2.88M | else |
308 | 6.22G | for(j=0;j<n;j++) |
309 | 6.22G | pcm[j]=0; |
310 | | |
311 | 2.96M | } |
312 | | |
313 | | //for(j=0;j<vi->channels;j++) |
314 | | //_analysis_output("window",seq+j,vb->pcm[j],-24,n,0,0); |
315 | | |
316 | 33.6k | seq+=vi->channels; |
317 | | /* all done! */ |
318 | 33.6k | return(0); |
319 | 33.6k | } |
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 | | }; |