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: PCM data vector blocking, windowing and dis/reassembly |
|
15 |
|
16 ********************************************************************/ |
|
17 |
|
18 #include <stdio.h> |
|
19 #include <stdlib.h> |
|
20 #include <string.h> |
|
21 #include "ogg.h" |
|
22 #include "ivorbiscodec.h" |
|
23 #include "codec_internal.h" |
|
24 |
|
25 #include "window.h" |
|
26 #include "registry.h" |
|
27 #include "misc.h" |
|
28 |
|
29 static int ilog(unsigned int v){ |
|
30 int ret=0; |
|
31 if(v)--v; |
|
32 while(v){ |
|
33 ret++; |
|
34 v>>=1; |
|
35 } |
|
36 return(ret); |
|
37 } |
|
38 |
|
39 /* pcm accumulator examples (not exhaustive): |
|
40 |
|
41 <-------------- lW ----------------> |
|
42 <--------------- W ----------------> |
|
43 : .....|..... _______________ | |
|
44 : .''' | '''_--- | |\ | |
|
45 :.....''' |_____--- '''......| | \_______| |
|
46 :.................|__________________|_______|__|______| |
|
47 |<------ Sl ------>| > Sr < |endW |
|
48 |beginSl |endSl | |endSr |
|
49 |beginW |endlW |beginSr |
|
50 |
|
51 |
|
52 |< lW >| |
|
53 <--------------- W ----------------> |
|
54 | | .. ______________ | |
|
55 | | ' `/ | ---_ | |
|
56 |___.'___/`. | ---_____| |
|
57 |_______|__|_______|_________________| |
|
58 | >|Sl|< |<------ Sr ----->|endW |
|
59 | | |endSl |beginSr |endSr |
|
60 |beginW | |endlW |
|
61 mult[0] |beginSl mult[n] |
|
62 |
|
63 <-------------- lW -----------------> |
|
64 |<--W-->| |
|
65 : .............. ___ | | |
|
66 : .''' |`/ \ | | |
|
67 :.....''' |/`....\|...| |
|
68 :.........................|___|___|___| |
|
69 |Sl |Sr |endW |
|
70 | | |endSr |
|
71 | |beginSr |
|
72 | |endSl |
|
73 |beginSl |
|
74 |beginW |
|
75 */ |
|
76 |
|
77 /* block abstraction setup *********************************************/ |
|
78 |
|
79 #ifndef WORD_ALIGN |
|
80 #define WORD_ALIGN 8 |
|
81 #endif |
|
82 |
|
83 int vorbis_block_init(vorbis_dsp_state *v, vorbis_block *vb){ |
|
84 memset(vb,0,sizeof(*vb)); |
|
85 vb->vd=v; |
|
86 vb->localalloc=0; |
|
87 vb->localstore=NULL; |
|
88 |
|
89 return(0); |
|
90 } |
|
91 |
|
92 void *_vorbis_block_alloc(vorbis_block *vb,long bytes){ |
|
93 bytes=(bytes+(WORD_ALIGN-1)) & ~(WORD_ALIGN-1); |
|
94 if(bytes+vb->localtop>vb->localalloc){ |
|
95 /* can't just _ogg_realloc... there are outstanding pointers */ |
|
96 if(vb->localstore){ |
|
97 struct alloc_chain *link=(struct alloc_chain *)_ogg_malloc(sizeof(*link)); |
|
98 vb->totaluse+=vb->localtop; |
|
99 link->next=vb->reap; |
|
100 link->ptr=vb->localstore; |
|
101 vb->reap=link; |
|
102 } |
|
103 /* highly conservative */ |
|
104 vb->localalloc=bytes; |
|
105 vb->localstore=_ogg_malloc(vb->localalloc); |
|
106 vb->localtop=0; |
|
107 } |
|
108 { |
|
109 void *ret=(void *)(((char *)vb->localstore)+vb->localtop); |
|
110 vb->localtop+=bytes; |
|
111 return ret; |
|
112 } |
|
113 } |
|
114 |
|
115 /* reap the chain, pull the ripcord */ |
|
116 void _vorbis_block_ripcord(vorbis_block *vb){ |
|
117 /* reap the chain */ |
|
118 struct alloc_chain *reap=vb->reap; |
|
119 while(reap){ |
|
120 struct alloc_chain *next=reap->next; |
|
121 _ogg_free(reap->ptr); |
|
122 memset(reap,0,sizeof(*reap)); |
|
123 _ogg_free(reap); |
|
124 reap=next; |
|
125 } |
|
126 /* consolidate storage */ |
|
127 if(vb->totaluse){ |
|
128 vb->localstore=_ogg_realloc(vb->localstore,vb->totaluse+vb->localalloc); |
|
129 vb->localalloc+=vb->totaluse; |
|
130 vb->totaluse=0; |
|
131 } |
|
132 |
|
133 /* pull the ripcord */ |
|
134 vb->localtop=0; |
|
135 vb->reap=NULL; |
|
136 } |
|
137 |
|
138 int vorbis_block_clear(vorbis_block *vb){ |
|
139 _vorbis_block_ripcord(vb); |
|
140 if(vb->localstore)_ogg_free(vb->localstore); |
|
141 |
|
142 memset(vb,0,sizeof(*vb)); |
|
143 return(0); |
|
144 } |
|
145 |
|
146 static int _vds_init(vorbis_dsp_state *v,vorbis_info *vi){ |
|
147 int i; |
|
148 codec_setup_info *ci=(codec_setup_info *)vi->codec_setup; |
|
149 private_state *b=NULL; |
|
150 |
|
151 memset(v,0,sizeof(*v)); |
|
152 b=(private_state *)(v->backend_state=_ogg_calloc(1,sizeof(*b))); |
|
153 |
|
154 v->vi=vi; |
|
155 b->modebits=ilog(ci->modes); |
|
156 |
|
157 /* Vorbis I uses only window type 0 */ |
|
158 b->window[0]=_vorbis_window(0,ci->blocksizes[0]/2); |
|
159 b->window[1]=_vorbis_window(0,ci->blocksizes[1]/2); |
|
160 |
|
161 /* finish the codebooks */ |
|
162 if(!ci->fullbooks){ |
|
163 ci->fullbooks=(codebook *)_ogg_calloc(ci->books,sizeof(*ci->fullbooks)); |
|
164 for(i=0;i<ci->books;i++){ |
|
165 vorbis_book_init_decode(ci->fullbooks+i,ci->book_param[i]); |
|
166 /* decode codebooks are now standalone after init */ |
|
167 vorbis_staticbook_destroy(ci->book_param[i]); |
|
168 ci->book_param[i]=NULL; |
|
169 } |
|
170 } |
|
171 |
|
172 v->pcm_storage=ci->blocksizes[1]; |
|
173 v->pcm=(ogg_int32_t **)_ogg_malloc(vi->channels*sizeof(*v->pcm)); |
|
174 v->pcmret=(ogg_int32_t **)_ogg_malloc(vi->channels*sizeof(*v->pcmret)); |
|
175 for(i=0;i<vi->channels;i++) |
|
176 v->pcm[i]=(ogg_int32_t *)_ogg_calloc(v->pcm_storage,sizeof(*v->pcm[i])); |
|
177 |
|
178 /* all 1 (large block) or 0 (small block) */ |
|
179 /* explicitly set for the sake of clarity */ |
|
180 v->lW=0; /* previous window size */ |
|
181 v->W=0; /* current window size */ |
|
182 |
|
183 /* initialize all the mapping/backend lookups */ |
|
184 b->mode=(vorbis_look_mapping **)_ogg_calloc(ci->modes,sizeof(*b->mode)); |
|
185 for(i=0;i<ci->modes;i++){ |
|
186 int mapnum=ci->mode_param[i]->mapping; |
|
187 int maptype=ci->map_type[mapnum]; |
|
188 b->mode[i]=_mapping_P[maptype]->look(v,ci->mode_param[i], |
|
189 ci->map_param[mapnum]); |
|
190 } |
|
191 return(0); |
|
192 } |
|
193 |
|
194 int vorbis_synthesis_restart(vorbis_dsp_state *v){ |
|
195 vorbis_info *vi=v->vi; |
|
196 codec_setup_info *ci; |
|
197 |
|
198 if(!v->backend_state)return -1; |
|
199 if(!vi)return -1; |
|
200 ci=vi->codec_setup; |
|
201 if(!ci)return -1; |
|
202 |
|
203 v->centerW=ci->blocksizes[1]/2; |
|
204 v->pcm_current=v->centerW; |
|
205 |
|
206 v->pcm_returned=-1; |
|
207 v->granulepos=-1; |
|
208 v->sequence=-1; |
|
209 ((private_state *)(v->backend_state))->sample_count=-1; |
|
210 |
|
211 return(0); |
|
212 } |
|
213 |
|
214 int vorbis_synthesis_init(vorbis_dsp_state *v,vorbis_info *vi){ |
|
215 _vds_init(v,vi); |
|
216 vorbis_synthesis_restart(v); |
|
217 |
|
218 return(0); |
|
219 } |
|
220 |
|
221 void vorbis_dsp_clear(vorbis_dsp_state *v){ |
|
222 int i; |
|
223 if(v){ |
|
224 vorbis_info *vi=v->vi; |
|
225 codec_setup_info *ci=(codec_setup_info *)(vi?vi->codec_setup:NULL); |
|
226 private_state *b=(private_state *)v->backend_state; |
|
227 |
|
228 if(v->pcm){ |
|
229 for(i=0;i<vi->channels;i++) |
|
230 if(v->pcm[i])_ogg_free(v->pcm[i]); |
|
231 _ogg_free(v->pcm); |
|
232 if(v->pcmret)_ogg_free(v->pcmret); |
|
233 } |
|
234 |
|
235 /* free mode lookups; these are actually vorbis_look_mapping structs */ |
|
236 if(ci){ |
|
237 for(i=0;i<ci->modes;i++){ |
|
238 int mapnum=ci->mode_param[i]->mapping; |
|
239 int maptype=ci->map_type[mapnum]; |
|
240 if(b && b->mode)_mapping_P[maptype]->free_look(b->mode[i]); |
|
241 } |
|
242 } |
|
243 |
|
244 if(b){ |
|
245 if(b->mode)_ogg_free(b->mode); |
|
246 _ogg_free(b); |
|
247 } |
|
248 |
|
249 memset(v,0,sizeof(*v)); |
|
250 } |
|
251 } |
|
252 |
|
253 /* Unlike in analysis, the window is only partially applied for each |
|
254 block. The time domain envelope is not yet handled at the point of |
|
255 calling (as it relies on the previous block). */ |
|
256 |
|
257 int vorbis_synthesis_blockin(vorbis_dsp_state *v,vorbis_block *vb){ |
|
258 vorbis_info *vi=v->vi; |
|
259 codec_setup_info *ci=(codec_setup_info *)vi->codec_setup; |
|
260 private_state *b=v->backend_state; |
|
261 int i,j; |
|
262 |
|
263 if(v->pcm_current>v->pcm_returned && v->pcm_returned!=-1)return(OV_EINVAL); |
|
264 |
|
265 v->lW=v->W; |
|
266 v->W=vb->W; |
|
267 v->nW=-1; |
|
268 |
|
269 if((v->sequence==-1)|| |
|
270 (v->sequence+1 != vb->sequence)){ |
|
271 v->granulepos=-1; /* out of sequence; lose count */ |
|
272 b->sample_count=-1; |
|
273 } |
|
274 |
|
275 v->sequence=vb->sequence; |
|
276 |
|
277 if(vb->pcm){ /* no pcm to process if vorbis_synthesis_trackonly |
|
278 was called on block */ |
|
279 int n=ci->blocksizes[v->W]/2; |
|
280 int n0=ci->blocksizes[0]/2; |
|
281 int n1=ci->blocksizes[1]/2; |
|
282 |
|
283 int thisCenter; |
|
284 int prevCenter; |
|
285 |
|
286 if(v->centerW){ |
|
287 thisCenter=n1; |
|
288 prevCenter=0; |
|
289 }else{ |
|
290 thisCenter=0; |
|
291 prevCenter=n1; |
|
292 } |
|
293 |
|
294 /* v->pcm is now used like a two-stage double buffer. We don't want |
|
295 to have to constantly shift *or* adjust memory usage. Don't |
|
296 accept a new block until the old is shifted out */ |
|
297 |
|
298 /* overlap/add PCM */ |
|
299 |
|
300 for(j=0;j<vi->channels;j++){ |
|
301 /* the overlap/add section */ |
|
302 if(v->lW){ |
|
303 if(v->W){ |
|
304 /* large/large */ |
|
305 ogg_int32_t *pcm=v->pcm[j]+prevCenter; |
|
306 ogg_int32_t *p=vb->pcm[j]; |
|
307 for(i=0;i<n1;i++) |
|
308 pcm[i]+=p[i]; |
|
309 }else{ |
|
310 /* large/small */ |
|
311 ogg_int32_t *pcm=v->pcm[j]+prevCenter+n1/2-n0/2; |
|
312 ogg_int32_t *p=vb->pcm[j]; |
|
313 for(i=0;i<n0;i++) |
|
314 pcm[i]+=p[i]; |
|
315 } |
|
316 }else{ |
|
317 if(v->W){ |
|
318 /* small/large */ |
|
319 ogg_int32_t *pcm=v->pcm[j]+prevCenter; |
|
320 ogg_int32_t *p=vb->pcm[j]+n1/2-n0/2; |
|
321 for(i=0;i<n0;i++) |
|
322 pcm[i]+=p[i]; |
|
323 for(;i<n1/2+n0/2;i++) |
|
324 pcm[i]=p[i]; |
|
325 }else{ |
|
326 /* small/small */ |
|
327 ogg_int32_t *pcm=v->pcm[j]+prevCenter; |
|
328 ogg_int32_t *p=vb->pcm[j]; |
|
329 for(i=0;i<n0;i++) |
|
330 pcm[i]+=p[i]; |
|
331 } |
|
332 } |
|
333 |
|
334 /* the copy section */ |
|
335 { |
|
336 ogg_int32_t *pcm=v->pcm[j]+thisCenter; |
|
337 ogg_int32_t *p=vb->pcm[j]+n; |
|
338 for(i=0;i<n;i++) |
|
339 pcm[i]=p[i]; |
|
340 } |
|
341 } |
|
342 |
|
343 if(v->centerW) |
|
344 v->centerW=0; |
|
345 else |
|
346 v->centerW=n1; |
|
347 |
|
348 /* deal with initial packet state; we do this using the explicit |
|
349 pcm_returned==-1 flag otherwise we're sensitive to first block |
|
350 being short or long */ |
|
351 |
|
352 if(v->pcm_returned==-1){ |
|
353 v->pcm_returned=thisCenter; |
|
354 v->pcm_current=thisCenter; |
|
355 }else{ |
|
356 v->pcm_returned=prevCenter; |
|
357 v->pcm_current=prevCenter+ |
|
358 ci->blocksizes[v->lW]/4+ |
|
359 ci->blocksizes[v->W]/4; |
|
360 } |
|
361 |
|
362 } |
|
363 |
|
364 /* track the frame number... This is for convenience, but also |
|
365 making sure our last packet doesn't end with added padding. If |
|
366 the last packet is partial, the number of samples we'll have to |
|
367 return will be past the vb->granulepos. |
|
368 |
|
369 This is not foolproof! It will be confused if we begin |
|
370 decoding at the last page after a seek or hole. In that case, |
|
371 we don't have a starting point to judge where the last frame |
|
372 is. For this reason, vorbisfile will always try to make sure |
|
373 it reads the last two marked pages in proper sequence */ |
|
374 |
|
375 if(b->sample_count==-1){ |
|
376 b->sample_count=0; |
|
377 }else{ |
|
378 b->sample_count+=ci->blocksizes[v->lW]/4+ci->blocksizes[v->W]/4; |
|
379 } |
|
380 |
|
381 if(v->granulepos==-1){ |
|
382 if(vb->granulepos!=-1){ /* only set if we have a position to set to */ |
|
383 |
|
384 v->granulepos=vb->granulepos; |
|
385 |
|
386 /* is this a short page? */ |
|
387 if(b->sample_count>v->granulepos){ |
|
388 /* corner case; if this is both the first and last audio page, |
|
389 then spec says the end is cut, not beginning */ |
|
390 if(vb->eofflag){ |
|
391 /* trim the end */ |
|
392 /* no preceeding granulepos; assume we started at zero (we'd |
|
393 have to in a short single-page stream) */ |
|
394 /* granulepos could be -1 due to a seek, but that would result |
|
395 in a long coun`t, not short count */ |
|
396 |
|
397 v->pcm_current-=(b->sample_count-v->granulepos); |
|
398 }else{ |
|
399 /* trim the beginning */ |
|
400 v->pcm_returned+=(b->sample_count-v->granulepos); |
|
401 if(v->pcm_returned>v->pcm_current) |
|
402 v->pcm_returned=v->pcm_current; |
|
403 } |
|
404 |
|
405 } |
|
406 |
|
407 } |
|
408 }else{ |
|
409 v->granulepos+=ci->blocksizes[v->lW]/4+ci->blocksizes[v->W]/4; |
|
410 if(vb->granulepos!=-1 && v->granulepos!=vb->granulepos){ |
|
411 |
|
412 if(v->granulepos>vb->granulepos){ |
|
413 long extra=v->granulepos-vb->granulepos; |
|
414 |
|
415 if(extra) |
|
416 if(vb->eofflag){ |
|
417 /* partial last frame. Strip the extra samples off */ |
|
418 v->pcm_current-=extra; |
|
419 } /* else {Shouldn't happen *unless* the bitstream is out of |
|
420 spec. Either way, believe the bitstream } */ |
|
421 } /* else {Shouldn't happen *unless* the bitstream is out of |
|
422 spec. Either way, believe the bitstream } */ |
|
423 v->granulepos=vb->granulepos; |
|
424 } |
|
425 } |
|
426 |
|
427 /* Update, cleanup */ |
|
428 |
|
429 if(vb->eofflag)v->eofflag=1; |
|
430 return(0); |
|
431 } |
|
432 |
|
433 /* pcm==NULL indicates we just want the pending samples, no more */ |
|
434 int vorbis_synthesis_pcmout(vorbis_dsp_state *v,ogg_int32_t ***pcm){ |
|
435 vorbis_info *vi=v->vi; |
|
436 if(v->pcm_returned>-1 && v->pcm_returned<v->pcm_current){ |
|
437 if(pcm){ |
|
438 int i; |
|
439 for(i=0;i<vi->channels;i++) |
|
440 v->pcmret[i]=v->pcm[i]+v->pcm_returned; |
|
441 *pcm=v->pcmret; |
|
442 } |
|
443 return(v->pcm_current-v->pcm_returned); |
|
444 } |
|
445 return(0); |
|
446 } |
|
447 |
|
448 int vorbis_synthesis_read(vorbis_dsp_state *v,int bytes){ |
|
449 if(bytes && v->pcm_returned+bytes>v->pcm_current)return(OV_EINVAL); |
|
450 v->pcm_returned+=bytes; |
|
451 return(0); |
|
452 } |
|
453 |
|