diff options
Diffstat (limited to 'apps/codecs/Tremor/block.c')
-rw-r--r-- | apps/codecs/Tremor/block.c | 453 |
1 files changed, 453 insertions, 0 deletions
diff --git a/apps/codecs/Tremor/block.c b/apps/codecs/Tremor/block.c new file mode 100644 index 0000000000..8949253a16 --- /dev/null +++ b/apps/codecs/Tremor/block.c | |||
@@ -0,0 +1,453 @@ | |||
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 | |||