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/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
ilog(unsigned int v)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
vorbis_block_init(vorbis_dsp_state * v,vorbis_block * vb)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
_vorbis_block_alloc(vorbis_block * vb,long bytes)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 */
_vorbis_block_ripcord(vorbis_block * vb)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
vorbis_block_clear(vorbis_block * vb)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
_vds_init(vorbis_dsp_state * v,vorbis_info * vi)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 if(ci==NULL) return 1;
152
153 memset(v,0,sizeof(*v));
154 b=(private_state *)(v->backend_state=_ogg_calloc(1,sizeof(*b)));
155
156 v->vi=vi;
157 b->modebits=ilog(ci->modes);
158
159 /* Vorbis I uses only window type 0 */
160 b->window[0]=_vorbis_window(0,ci->blocksizes[0]/2);
161 b->window[1]=_vorbis_window(0,ci->blocksizes[1]/2);
162
163 /* finish the codebooks */
164 if(!ci->fullbooks){
165 ci->fullbooks=(codebook *)_ogg_calloc(ci->books,sizeof(*ci->fullbooks));
166 for(i=0;i<ci->books;i++){
167 if(ci->book_param[i]==NULL)
168 goto abort_books;
169 if(vorbis_book_init_decode(ci->fullbooks+i,ci->book_param[i]))
170 goto abort_books;
171 /* decode codebooks are now standalone after init */
172 vorbis_staticbook_destroy(ci->book_param[i]);
173 ci->book_param[i]=NULL;
174 }
175 }
176
177 v->pcm_storage=ci->blocksizes[1];
178 v->pcm=(ogg_int32_t **)_ogg_malloc(vi->channels*sizeof(*v->pcm));
179 v->pcmret=(ogg_int32_t **)_ogg_malloc(vi->channels*sizeof(*v->pcmret));
180 for(i=0;i<vi->channels;i++)
181 v->pcm[i]=(ogg_int32_t *)_ogg_calloc(v->pcm_storage,sizeof(*v->pcm[i]));
182
183 /* all 1 (large block) or 0 (small block) */
184 /* explicitly set for the sake of clarity */
185 v->lW=0; /* previous window size */
186 v->W=0; /* current window size */
187
188 /* initialize all the mapping/backend lookups */
189 b->mode=(vorbis_look_mapping **)_ogg_calloc(ci->modes,sizeof(*b->mode));
190 for(i=0;i<ci->modes;i++){
191 int mapnum=ci->mode_param[i]->mapping;
192 int maptype=ci->map_type[mapnum];
193 b->mode[i]=_mapping_P[maptype]->look(v,ci->mode_param[i],
194 ci->map_param[mapnum]);
195 }
196 return 0;
197 abort_books:
198 for(i=0;i<ci->books;i++){
199 if(ci->book_param[i]!=NULL){
200 vorbis_staticbook_destroy(ci->book_param[i]);
201 ci->book_param[i]=NULL;
202 }
203 }
204 vorbis_dsp_clear(v);
205 return -1;
206 }
207
vorbis_synthesis_restart(vorbis_dsp_state * v)208 int vorbis_synthesis_restart(vorbis_dsp_state *v){
209 vorbis_info *vi=v->vi;
210 codec_setup_info *ci;
211
212 if(!v->backend_state)return -1;
213 if(!vi)return -1;
214 ci=vi->codec_setup;
215 if(!ci)return -1;
216
217 v->centerW=ci->blocksizes[1]/2;
218 v->pcm_current=v->centerW;
219
220 v->pcm_returned=-1;
221 v->granulepos=-1;
222 v->sequence=-1;
223 ((private_state *)(v->backend_state))->sample_count=-1;
224
225 return(0);
226 }
227
vorbis_synthesis_init(vorbis_dsp_state * v,vorbis_info * vi)228 int vorbis_synthesis_init(vorbis_dsp_state *v,vorbis_info *vi){
229 if(_vds_init(v,vi))return 1;
230 vorbis_synthesis_restart(v);
231
232 return 0;
233 }
234
vorbis_dsp_clear(vorbis_dsp_state * v)235 void vorbis_dsp_clear(vorbis_dsp_state *v){
236 int i;
237 if(v){
238 vorbis_info *vi=v->vi;
239 codec_setup_info *ci=(codec_setup_info *)(vi?vi->codec_setup:NULL);
240 private_state *b=(private_state *)v->backend_state;
241
242 if(v->pcm){
243 for(i=0;i<vi->channels;i++)
244 if(v->pcm[i])_ogg_free(v->pcm[i]);
245 _ogg_free(v->pcm);
246 if(v->pcmret)_ogg_free(v->pcmret);
247 }
248
249 /* free mode lookups; these are actually vorbis_look_mapping structs */
250 if(ci){
251 for(i=0;i<ci->modes;i++){
252 int mapnum=ci->mode_param[i]->mapping;
253 int maptype=ci->map_type[mapnum];
254 if(b && b->mode)_mapping_P[maptype]->free_look(b->mode[i]);
255 }
256 }
257
258 if(b){
259 if(b->mode)_ogg_free(b->mode);
260 _ogg_free(b);
261 }
262
263 memset(v,0,sizeof(*v));
264 }
265 }
266
267 /* Unlike in analysis, the window is only partially applied for each
268 block. The time domain envelope is not yet handled at the point of
269 calling (as it relies on the previous block). */
270
vorbis_synthesis_blockin(vorbis_dsp_state * v,vorbis_block * vb)271 int vorbis_synthesis_blockin(vorbis_dsp_state *v,vorbis_block *vb){
272 vorbis_info *vi=v->vi;
273 codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
274 private_state *b=v->backend_state;
275 int i,j;
276
277 if(v->pcm_current>v->pcm_returned && v->pcm_returned!=-1)return(OV_EINVAL);
278
279 v->lW=v->W;
280 v->W=vb->W;
281 v->nW=-1;
282
283 if((v->sequence==-1)||
284 (v->sequence+1 != vb->sequence)){
285 v->granulepos=-1; /* out of sequence; lose count */
286 b->sample_count=-1;
287 }
288
289 v->sequence=vb->sequence;
290
291 if(vb->pcm){ /* no pcm to process if vorbis_synthesis_trackonly
292 was called on block */
293 int n=ci->blocksizes[v->W]/2;
294 int n0=ci->blocksizes[0]/2;
295 int n1=ci->blocksizes[1]/2;
296
297 int thisCenter;
298 int prevCenter;
299
300 if(v->centerW){
301 thisCenter=n1;
302 prevCenter=0;
303 }else{
304 thisCenter=0;
305 prevCenter=n1;
306 }
307
308 /* v->pcm is now used like a two-stage double buffer. We don't want
309 to have to constantly shift *or* adjust memory usage. Don't
310 accept a new block until the old is shifted out */
311
312 /* overlap/add PCM */
313
314 for(j=0;j<vi->channels;j++){
315 /* the overlap/add section */
316 if(v->lW){
317 if(v->W){
318 /* large/large */
319 ogg_int32_t *pcm=v->pcm[j]+prevCenter;
320 ogg_int32_t *p=vb->pcm[j];
321 for(i=0;i<n1;i++)
322 pcm[i]+=p[i];
323 }else{
324 /* large/small */
325 ogg_int32_t *pcm=v->pcm[j]+prevCenter+n1/2-n0/2;
326 ogg_int32_t *p=vb->pcm[j];
327 for(i=0;i<n0;i++)
328 pcm[i]+=p[i];
329 }
330 }else{
331 if(v->W){
332 /* small/large */
333 ogg_int32_t *pcm=v->pcm[j]+prevCenter;
334 ogg_int32_t *p=vb->pcm[j]+n1/2-n0/2;
335 for(i=0;i<n0;i++)
336 pcm[i]+=p[i];
337 for(;i<n1/2+n0/2;i++)
338 pcm[i]=p[i];
339 }else{
340 /* small/small */
341 ogg_int32_t *pcm=v->pcm[j]+prevCenter;
342 ogg_int32_t *p=vb->pcm[j];
343 for(i=0;i<n0;i++)
344 pcm[i]+=p[i];
345 }
346 }
347
348 /* the copy section */
349 {
350 ogg_int32_t *pcm=v->pcm[j]+thisCenter;
351 ogg_int32_t *p=vb->pcm[j]+n;
352 for(i=0;i<n;i++)
353 pcm[i]=p[i];
354 }
355 }
356
357 if(v->centerW)
358 v->centerW=0;
359 else
360 v->centerW=n1;
361
362 /* deal with initial packet state; we do this using the explicit
363 pcm_returned==-1 flag otherwise we're sensitive to first block
364 being short or long */
365
366 if(v->pcm_returned==-1){
367 v->pcm_returned=thisCenter;
368 v->pcm_current=thisCenter;
369 }else{
370 v->pcm_returned=prevCenter;
371 v->pcm_current=prevCenter+
372 ci->blocksizes[v->lW]/4+
373 ci->blocksizes[v->W]/4;
374 }
375
376 }
377
378 /* track the frame number... This is for convenience, but also
379 making sure our last packet doesn't end with added padding. If
380 the last packet is partial, the number of samples we'll have to
381 return will be past the vb->granulepos.
382
383 This is not foolproof! It will be confused if we begin
384 decoding at the last page after a seek or hole. In that case,
385 we don't have a starting point to judge where the last frame
386 is. For this reason, vorbisfile will always try to make sure
387 it reads the last two marked pages in proper sequence */
388
389 if(b->sample_count==-1){
390 b->sample_count=0;
391 }else{
392 b->sample_count+=ci->blocksizes[v->lW]/4+ci->blocksizes[v->W]/4;
393 }
394
395 if(v->granulepos==-1){
396 if(vb->granulepos!=-1){ /* only set if we have a position to set to */
397
398 v->granulepos=vb->granulepos;
399
400 /* is this a short page? */
401 if(b->sample_count>v->granulepos){
402 /* corner case; if this is both the first and last audio page,
403 then spec says the end is cut, not beginning */
404 long extra=b->sample_count-vb->granulepos;
405
406 /* we use ogg_int64_t for granule positions because a
407 uint64 isn't universally available. Unfortunately,
408 that means granposes can be 'negative' and result in
409 extra being negative */
410 if(extra<0)
411 extra=0;
412
413 if(vb->eofflag){
414 /* trim the end */
415 /* no preceeding granulepos; assume we started at zero (we'd
416 have to in a short single-page stream) */
417 /* granulepos could be -1 due to a seek, but that would result
418 in a long coun`t, not short count */
419
420 /* Guard against corrupt/malicious frames that set EOP and
421 a backdated granpos; don't rewind more samples than we
422 actually have */
423 if(extra > v->pcm_current - v->pcm_returned)
424 extra = v->pcm_current - v->pcm_returned;
425
426 v->pcm_current-=extra;
427 }else{
428 /* trim the beginning */
429 v->pcm_returned+=extra;
430 if(v->pcm_returned>v->pcm_current)
431 v->pcm_returned=v->pcm_current;
432 }
433
434 }
435
436 }
437 }else{
438 v->granulepos+=ci->blocksizes[v->lW]/4+ci->blocksizes[v->W]/4;
439 if(vb->granulepos!=-1 && v->granulepos!=vb->granulepos){
440
441 if(v->granulepos>vb->granulepos){
442 long extra=v->granulepos-vb->granulepos;
443
444 if(extra)
445 if(vb->eofflag){
446 /* partial last frame. Strip the extra samples off */
447
448 /* Guard against corrupt/malicious frames that set EOP and
449 a backdated granpos; don't rewind more samples than we
450 actually have */
451 if(extra > v->pcm_current - v->pcm_returned)
452 extra = v->pcm_current - v->pcm_returned;
453
454 /* we use ogg_int64_t for granule positions because a
455 uint64 isn't universally available. Unfortunately,
456 that means granposes can be 'negative' and result in
457 extra being negative */
458 if(extra<0)
459 extra=0;
460
461 v->pcm_current-=extra;
462
463 } /* else {Shouldn't happen *unless* the bitstream is out of
464 spec. Either way, believe the bitstream } */
465 } /* else {Shouldn't happen *unless* the bitstream is out of
466 spec. Either way, believe the bitstream } */
467 v->granulepos=vb->granulepos;
468 }
469 }
470
471 /* Update, cleanup */
472
473 if(vb->eofflag)v->eofflag=1;
474 return(0);
475 }
476
477 /* pcm==NULL indicates we just want the pending samples, no more */
vorbis_synthesis_pcmout(vorbis_dsp_state * v,ogg_int32_t *** pcm)478 int vorbis_synthesis_pcmout(vorbis_dsp_state *v,ogg_int32_t ***pcm){
479 vorbis_info *vi=v->vi;
480 if(v->pcm_returned>-1 && v->pcm_returned<v->pcm_current){
481 if(pcm){
482 int i;
483 for(i=0;i<vi->channels;i++)
484 v->pcmret[i]=v->pcm[i]+v->pcm_returned;
485 *pcm=v->pcmret;
486 }
487 return(v->pcm_current-v->pcm_returned);
488 }
489 return(0);
490 }
491
vorbis_synthesis_read(vorbis_dsp_state * v,int bytes)492 int vorbis_synthesis_read(vorbis_dsp_state *v,int bytes){
493 if(bytes && v->pcm_returned+bytes>v->pcm_current)return(OV_EINVAL);
494 v->pcm_returned+=bytes;
495 return(0);
496 }
497
498