New makefile solution: A single invocation of 'make' to build the entire tree. Fully...
[kugel-rb.git] / apps / codecs / libtremor / block.c
blobe609fc44f77406840b6f91716ab720b55f4f022c
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 ********************************************************************
14 function: PCM data vector blocking, windowing and dis/reassembly
16 ********************************************************************/
18 #include "config-tremor.h"
19 #include <stdio.h>
20 #include <string.h>
21 #include "ogg.h"
22 #include "ivorbiscodec.h"
23 #include "codec_internal.h"
25 #include "window.h"
26 #include "registry.h"
27 #include "misc.h"
29 static int ilog(unsigned int v){
30 int ret=0;
31 if(v)--v;
32 while(v){
33 ret++;
34 v>>=1;
36 return(ret);
39 /* pcm accumulator examples (not exhaustive):
41 <-------------- lW ---------------->
42 <--------------- W ---------------->
43 : .....|..... _______________ |
44 : .''' | '''_--- | |\ |
45 :.....''' |_____--- '''......| | \_______|
46 :.................|__________________|_______|__|______|
47 |<------ Sl ------>| > Sr < |endW
48 |beginSl |endSl | |endSr
49 |beginW |endlW |beginSr
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]
63 <-------------- lW ----------------->
64 |<--W-->|
65 : .............. ___ | |
66 : .''' |`/ \ | |
67 :.....''' |/`....\|...|
68 :.........................|___|___|___|
69 |Sl |Sr |endW
70 | | |endSr
71 | |beginSr
72 | |endSl
73 |beginSl
74 |beginW
77 /* block abstraction setup *********************************************/
79 #ifndef WORD_ALIGN
80 #define WORD_ALIGN 8
81 #endif
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;
89 return(0);
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;
103 /* highly conservative */
104 vb->localalloc=bytes;
105 vb->localstore=_ogg_malloc(vb->localalloc);
106 vb->localtop=0;
109 void *ret=(void *)(((char *)vb->localstore)+vb->localtop);
110 vb->localtop+=bytes;
111 return ret;
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;
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;
133 /* pull the ripcord */
134 vb->localtop=0;
135 vb->reap=NULL;
138 int vorbis_block_clear(vorbis_block *vb){
139 _vorbis_block_ripcord(vb);
140 if(vb->localstore)_ogg_free(vb->localstore);
142 memset(vb,0,sizeof(*vb));
143 return(0);
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;
151 memset(v,0,sizeof(*v));
152 b=(private_state *)(v->backend_state=_ogg_calloc(1,sizeof(*b)));
154 v->vi=vi;
155 b->modebits=ilog(ci->modes);
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);
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;
172 v->pcm_storage=ci->blocksizes[1];
173 v->pcm=(ogg_int32_t **)_ogg_malloc(vi->channels*sizeof(*v->pcm));
174 v->pcmb=(ogg_int32_t **)_ogg_malloc(vi->channels*sizeof(*v->pcmb));
175 v->pcmret=(ogg_int32_t **)_ogg_malloc(vi->channels*sizeof(*v->pcmret));
177 for(i=0;i<vi->channels;i++)
178 v->pcm[i]=(ogg_int32_t *)_ogg_calloc(v->pcm_storage,sizeof(*v->pcm[i]));
181 /* all 1 (large block) or 0 (small block) */
182 /* explicitly set for the sake of clarity */
183 v->lW=0; /* previous window size */
184 v->W=0; /* current window size */
186 /* initialize all the mapping/backend lookups */
187 b->mode=(vorbis_look_mapping **)_ogg_calloc(ci->modes,sizeof(*b->mode));
188 for(i=0;i<ci->modes;i++){
189 int mapnum=ci->mode_param[i]->mapping;
190 int maptype=ci->map_type[mapnum];
191 b->mode[i]=_mapping_P[maptype]->look(v,ci->mode_param[i],
192 ci->map_param[mapnum]);
194 return(0);
197 int vorbis_synthesis_restart(vorbis_dsp_state *v){
198 vorbis_info *vi=v->vi;
199 codec_setup_info *ci;
201 if(!v->backend_state)return -1;
202 if(!vi)return -1;
203 ci=vi->codec_setup;
204 if(!ci)return -1;
206 v->centerW=ci->blocksizes[1]/2;
207 v->pcm_current=v->centerW;
209 v->pcm_returned=-1;
210 v->granulepos=-1;
211 v->sequence=-1;
212 ((private_state *)(v->backend_state))->sample_count=-1;
214 return(0);
217 int vorbis_synthesis_init(vorbis_dsp_state *v,vorbis_info *vi){
218 _vds_init(v,vi);
219 vorbis_synthesis_restart(v);
221 return(0);
224 void vorbis_dsp_clear(vorbis_dsp_state *v){
225 int i;
226 if(v){
227 vorbis_info *vi=v->vi;
228 codec_setup_info *ci=(codec_setup_info *)(vi?vi->codec_setup:NULL);
229 private_state *b=(private_state *)v->backend_state;
231 if(v->pcm){
232 for(i=0;i<vi->channels;i++)
233 if(v->pcm[i])_ogg_free(v->pcm[i]);
234 _ogg_free(v->pcm);
235 if(v->pcmret)_ogg_free(v->pcmret);
238 /* free mode lookups; these are actually vorbis_look_mapping structs */
239 if(ci){
240 for(i=0;i<ci->modes;i++){
241 int mapnum=ci->mode_param[i]->mapping;
242 int maptype=ci->map_type[mapnum];
243 if(b && b->mode)_mapping_P[maptype]->free_look(b->mode[i]);
247 if(b){
248 if(b->mode)_ogg_free(b->mode);
249 _ogg_free(b);
252 memset(v,0,sizeof(*v));
256 /* Unlike in analysis, the window is only partially applied for each
257 block. The time domain envelope is not yet handled at the point of
258 calling (as it relies on the previous block). */
260 int vorbis_synthesis_blockin(vorbis_dsp_state *v,vorbis_block *vb)
261 ICODE_ATTR_TREMOR_NOT_MDCT;
262 int vorbis_synthesis_blockin(vorbis_dsp_state *v,vorbis_block *vb){
263 vorbis_info *vi=v->vi;
264 codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
265 private_state *b=v->backend_state;
266 int j;
268 if(v->pcm_current>v->pcm_returned && v->pcm_returned!=-1)return(OV_EINVAL);
270 v->lW=v->W;
271 v->W=vb->W;
272 v->nW=-1;
274 if((v->sequence==-1)||
275 (v->sequence+1 != vb->sequence)){
276 v->granulepos=-1; /* out of sequence; lose count */
277 b->sample_count=-1;
280 v->sequence=vb->sequence;
282 if(vb->pcm){ /* no pcm to process if vorbis_synthesis_trackonly
283 was called on block */
284 int n=ci->blocksizes[v->W]/2;
285 int n0=ci->blocksizes[0]/2;
286 int n1=ci->blocksizes[1]/2;
288 int thisCenter;
289 int prevCenter;
291 if(v->centerW){
292 thisCenter=n1;
293 prevCenter=0;
294 }else{
295 thisCenter=0;
296 prevCenter=n1;
299 /* v->pcm is now used like a two-stage double buffer. We don't want
300 to have to constantly shift *or* adjust memory usage. Don't
301 accept a new block until the old is shifted out */
303 /* overlap/add PCM */
305 for(j=0;j<vi->channels;j++){
306 /* the overlap/add section */
307 if(v->lW){
308 if(v->W){
309 /* large/large */
310 ogg_int32_t *pcm=v->pcm[j]+prevCenter;
311 ogg_int32_t *p=vb->pcm[j];
312 vect_add(p, pcm, n1);
313 v->pcmb[j]=p;
314 }else{
315 /* large/small */
316 ogg_int32_t *pcm=v->pcm[j]+prevCenter+n1/2-n0/2;
317 ogg_int32_t *p=vb->pcm[j];
318 vect_add(pcm, p, n0);
319 v->pcmb[j]=v->pcm[j]+prevCenter;
321 }else{
322 if(v->W){
323 /* small/large */
324 ogg_int32_t *pcm=v->pcm[j]+prevCenter;
325 ogg_int32_t *p=vb->pcm[j]+n1/2-n0/2;
326 vect_add(p, pcm, n0);
327 v->pcmb[j]=p;
328 }else{
329 /* small/small */
330 ogg_int32_t *pcm=v->pcm[j]+prevCenter;
331 ogg_int32_t *p=vb->pcm[j];
332 vect_add(p, pcm, n0);
333 v->pcmb[j]=p;
337 /* the copy section */
339 ogg_int32_t *pcm=v->pcm[j]+thisCenter;
340 ogg_int32_t *p=vb->pcm[j]+n;
341 vect_copy(pcm, p, n);
345 if(v->centerW)
346 v->centerW=0;
347 else
348 v->centerW=n1;
350 /* deal with initial packet state; we do this using the explicit
351 pcm_returned==-1 flag otherwise we're sensitive to first block
352 being short or long */
354 if(v->pcm_returned==-1){
355 v->pcm_returned=thisCenter;
356 v->pcm_current=thisCenter;
357 }else{
358 v->pcm_returned=0;
359 v->pcm_current=ci->blocksizes[v->lW]/4+ci->blocksizes[v->W]/4;
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.
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 */
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;
381 if(v->granulepos==-1){
382 if(vb->granulepos!=-1){ /* only set if we have a position to set to */
384 v->granulepos=vb->granulepos;
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 */
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;
408 }else{
409 v->granulepos+=ci->blocksizes[v->lW]/4+ci->blocksizes[v->W]/4;
410 if(vb->granulepos!=-1 && v->granulepos!=vb->granulepos){
412 if(v->granulepos>vb->granulepos){
413 long extra=v->granulepos-vb->granulepos;
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;
427 /* Update, cleanup */
429 if(vb->eofflag)v->eofflag=1;
430 return(0);
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) ICODE_ATTR;
435 int vorbis_synthesis_pcmout(vorbis_dsp_state *v,ogg_int32_t ***pcm){
436 vorbis_info *vi=v->vi;
437 if(v->pcm_returned>-1 && v->pcm_returned<v->pcm_current){
438 if(pcm){
439 int i;
440 for(i=0;i<vi->channels;i++)
441 v->pcmret[i]=v->pcmb[i]+v->pcm_returned;
442 *pcm=v->pcmret;
444 return(v->pcm_current-v->pcm_returned);
446 return(0);
449 int vorbis_synthesis_read(vorbis_dsp_state *v,int bytes){
450 if(bytes && v->pcm_returned+bytes>v->pcm_current)return(OV_EINVAL);
451 v->pcm_returned+=bytes;
452 return(0);