Call the oddly labelled button on the gigabeat remote "Menu" in the
[kugel-rb.git] / apps / codecs / libtremor / block.c
blob3947b90239233f26fe94b989102e44ede88be338
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 static ogg_int32_t* _pcmp [CHANNELS] IBSS_ATTR;
40 static ogg_int32_t* _pcmbp[CHANNELS] IBSS_ATTR;
41 static ogg_int32_t* _pcmret[CHANNELS] IBSS_ATTR;
43 /* pcm accumulator examples (not exhaustive):
45 <-------------- lW ---------------->
46 <--------------- W ---------------->
47 : .....|..... _______________ |
48 : .''' | '''_--- | |\ |
49 :.....''' |_____--- '''......| | \_______|
50 :.................|__________________|_______|__|______|
51 |<------ Sl ------>| > Sr < |endW
52 |beginSl |endSl | |endSr
53 |beginW |endlW |beginSr
56 |< lW >|
57 <--------------- W ---------------->
58 | | .. ______________ |
59 | | ' `/ | ---_ |
60 |___.'___/`. | ---_____|
61 |_______|__|_______|_________________|
62 | >|Sl|< |<------ Sr ----->|endW
63 | | |endSl |beginSr |endSr
64 |beginW | |endlW
65 mult[0] |beginSl mult[n]
67 <-------------- lW ----------------->
68 |<--W-->|
69 : .............. ___ | |
70 : .''' |`/ \ | |
71 :.....''' |/`....\|...|
72 :.........................|___|___|___|
73 |Sl |Sr |endW
74 | | |endSr
75 | |beginSr
76 | |endSl
77 |beginSl
78 |beginW
81 /* block abstraction setup *********************************************/
83 #ifndef WORD_ALIGN
84 #define WORD_ALIGN 8
85 #endif
87 int vorbis_block_init(vorbis_dsp_state *v, vorbis_block *vb){
88 memset(vb,0,sizeof(*vb));
89 vb->vd=v;
90 vb->localalloc=0;
91 vb->localstore=NULL;
93 return(0);
96 void *_vorbis_block_alloc(vorbis_block *vb,long bytes){
97 bytes=(bytes+(WORD_ALIGN-1)) & ~(WORD_ALIGN-1);
98 if(bytes+vb->localtop>vb->localalloc){
99 /* can't just _ogg_realloc... there are outstanding pointers */
100 if(vb->localstore){
101 struct alloc_chain *link=(struct alloc_chain *)_ogg_malloc(sizeof(*link));
102 vb->totaluse+=vb->localtop;
103 link->next=vb->reap;
104 link->ptr=vb->localstore;
105 vb->reap=link;
107 /* highly conservative */
108 vb->localalloc=bytes;
109 vb->localstore=_ogg_malloc(vb->localalloc);
110 vb->localtop=0;
113 void *ret=(void *)(((char *)vb->localstore)+vb->localtop);
114 vb->localtop+=bytes;
115 return ret;
119 /* reap the chain, pull the ripcord */
120 void _vorbis_block_ripcord(vorbis_block *vb){
121 /* reap the chain */
122 struct alloc_chain *reap=vb->reap;
123 while(reap){
124 struct alloc_chain *next=reap->next;
125 _ogg_free(reap->ptr);
126 memset(reap,0,sizeof(*reap));
127 _ogg_free(reap);
128 reap=next;
130 /* consolidate storage */
131 if(vb->totaluse){
132 vb->localstore=_ogg_realloc(vb->localstore,vb->totaluse+vb->localalloc);
133 vb->localalloc+=vb->totaluse;
134 vb->totaluse=0;
137 /* pull the ripcord */
138 vb->localtop=0;
139 vb->reap=NULL;
142 int vorbis_block_clear(vorbis_block *vb){
143 _vorbis_block_ripcord(vb);
144 if(vb->localstore)_ogg_free(vb->localstore);
146 memset(vb,0,sizeof(*vb));
147 return(0);
150 static int _vds_init(vorbis_dsp_state *v,vorbis_info *vi){
151 int i;
152 long b_size[2];
153 LOOKUP_TNC *iramposw;
155 codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
156 private_state *b=NULL;
158 memset(v,0,sizeof(*v));
159 v->reset_pcmb=true;
160 b=(private_state *)(v->backend_state=_ogg_calloc(1,sizeof(*b)));
162 v->vi=vi;
163 b->modebits=ilog(ci->modes);
165 /* allocate IRAM buffer for the PCM data generated by synthesis */
166 iram_malloc_init();
167 v->iram_pcm=(ogg_int32_t *)iram_malloc(vi->channels*ci->blocksizes[1]*sizeof(ogg_int32_t));
168 if(v->iram_pcm != NULL) v->iram_pcm_storage=ci->blocksizes[1];
169 else v->iram_pcm_storage=0;
171 v->centerW=0;
173 /* Vorbis I uses only window type 0 */
174 b_size[0]=ci->blocksizes[0]/2;
175 b_size[1]=ci->blocksizes[1]/2;
176 b->window[0]=_vorbis_window(0,b_size[0]);
177 b->window[1]=_vorbis_window(0,b_size[1]);
179 /* allocate IRAM buffer for window tables too, if sufficient iram available */
180 /* give preference to the larger window over the smaller window
181 (on the assumption that both windows are equally likely used) */
182 for(i=1; i>=0; i--){
183 iramposw=(LOOKUP_TNC *)iram_malloc(b_size[i]*sizeof(LOOKUP_TNC));
184 if(iramposw!=NULL) {
185 memcpy(iramposw, b->window[i], b_size[i]*sizeof(LOOKUP_TNC));
186 b->window[i]=iramposw;
190 /* finish the codebooks */
191 if(!ci->fullbooks){
192 ci->fullbooks=(codebook *)_ogg_calloc(ci->books,sizeof(*ci->fullbooks));
193 for(i=0;i<ci->books;i++){
194 vorbis_book_init_decode(ci->fullbooks+i,ci->book_param[i]);
195 /* decode codebooks are now standalone after init */
196 vorbis_staticbook_destroy(ci->book_param[i]);
197 ci->book_param[i]=NULL;
201 /* if we can get away with it, put a double buffer into IRAM too, so that
202 overlap-add runs iram-to-iram and we avoid needing to memcpy */
203 v->pcm_storage=ci->blocksizes[1];
204 v->pcm=_pcmp;
205 v->pcmret=_pcmret;
206 v->pcmb=_pcmbp;
208 _pcmp[0]=NULL;
209 _pcmp[1]=NULL;
210 _pcmbp[0]=NULL;
211 _pcmbp[1]=NULL;
212 if(NULL != (v->iram_double_pcm = iram_malloc(vi->channels*v->pcm_storage*sizeof(ogg_int32_t))))
214 /* one-time initialisation at codec start or on switch from
215 blocksizes greater than IRAM_PCM_END to sizes that fit */
216 for(i=0;i<vi->channels;i++)
217 v->pcm[i]=&v->iram_double_pcm[i*v->pcm_storage];
219 else
221 /* one-time initialisation at codec start or on switch from
222 blocksizes that fit in IRAM_PCM_END to those that don't */
223 for(i=0;i<vi->channels;i++)
224 v->pcm[i]=(ogg_int32_t *)_ogg_calloc(v->pcm_storage,sizeof(*v->pcm[i]));
227 /* all 1 (large block) or 0 (small block) */
228 /* explicitly set for the sake of clarity */
229 v->lW=0; /* previous window size */
230 v->W=0; /* current window size */
232 /* initialize all the mapping/backend lookups */
233 b->mode=(vorbis_look_mapping **)_ogg_calloc(ci->modes,sizeof(*b->mode));
234 for(i=0;i<ci->modes;i++){
235 int mapnum=ci->mode_param[i]->mapping;
236 int maptype=ci->map_type[mapnum];
237 b->mode[i]=_mapping_P[maptype]->look(v,ci->mode_param[i],
238 ci->map_param[mapnum]);
240 return(0);
243 int vorbis_synthesis_restart(vorbis_dsp_state *v){
244 vorbis_info *vi=v->vi;
245 codec_setup_info *ci;
246 int i;
248 if(!v->backend_state)return -1;
249 if(!vi)return -1;
250 ci=vi->codec_setup;
251 if(!ci)return -1;
253 v->centerW=0;
254 v->pcm_current=0;
256 v->pcm_returned=-1;
257 v->granulepos=-1;
258 v->sequence=-1;
259 ((private_state *)(v->backend_state))->sample_count=-1;
261 /* indicate to synthesis code that buffer pointers no longer valid
262 (if we're using double pcm buffer) and will need to reset them */
263 v->reset_pcmb = true;
264 /* also reset our copy of the double buffer pointers if we have one */
265 if(v->iram_double_pcm)
266 for(i=0;i<vi->channels;i++)
267 v->pcm[i]=&v->iram_double_pcm[i*v->pcm_storage];
269 return(0);
272 int vorbis_synthesis_init(vorbis_dsp_state *v,vorbis_info *vi){
273 _vds_init(v,vi);
274 vorbis_synthesis_restart(v);
276 return(0);
279 void vorbis_dsp_clear(vorbis_dsp_state *v){
280 int i;
281 if(v){
282 vorbis_info *vi=v->vi;
283 codec_setup_info *ci=(codec_setup_info *)(vi?vi->codec_setup:NULL);
284 private_state *b=(private_state *)v->backend_state;
286 if(NULL == v->iram_double_pcm)
288 /* pcm buffer came from oggmalloc rather than iram */
289 for(i=0;i<vi->channels;i++)
290 if(v->pcm[i])_ogg_free(v->pcm[i]);
293 /* free mode lookups; these are actually vorbis_look_mapping structs */
294 if(ci){
295 for(i=0;i<ci->modes;i++){
296 int mapnum=ci->mode_param[i]->mapping;
297 int maptype=ci->map_type[mapnum];
298 if(b && b->mode)_mapping_P[maptype]->free_look(b->mode[i]);
302 if(b){
303 if(b->mode)_ogg_free(b->mode);
304 _ogg_free(b);
307 memset(v,0,sizeof(*v));
311 /* Unlike in analysis, the window is only partially applied for each
312 block. The time domain envelope is not yet handled at the point of
313 calling (as it relies on the previous block). */
315 int vorbis_synthesis_blockin(vorbis_dsp_state *v,vorbis_block *vb)
316 ICODE_ATTR;
317 int vorbis_synthesis_blockin(vorbis_dsp_state *v,vorbis_block *vb){
318 vorbis_info *vi=v->vi;
319 codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
320 private_state *b=v->backend_state;
321 int j;
322 bool iram_pcm_doublebuffer = (NULL != v->iram_double_pcm);
324 if(v->pcm_current>v->pcm_returned && v->pcm_returned!=-1)return(OV_EINVAL);
326 v->lW=v->W;
327 v->W=vb->W;
328 v->nW=-1;
330 if((v->sequence==-1)||
331 (v->sequence+1 != vb->sequence)){
332 v->granulepos=-1; /* out of sequence; lose count */
333 b->sample_count=-1;
336 v->sequence=vb->sequence;
337 int n=ci->blocksizes[v->W]/2;
338 int ln=ci->blocksizes[v->lW]/2;
340 if(LIKELY(vb->pcm)){ /* no pcm to process if vorbis_synthesis_trackonly
341 was called on block */
342 int prevCenter;
343 int n0=ci->blocksizes[0]/2;
344 int n1=ci->blocksizes[1]/2;
346 if(iram_pcm_doublebuffer)
348 prevCenter = ln;
350 else
352 prevCenter = v->centerW;
353 v->centerW = n1 - v->centerW;
356 /* overlap/add PCM */
357 /* nb nothing to overlap with on first block so don't bother */
358 if(LIKELY(v->pcm_returned!=-1))
360 for(j=0;j<vi->channels;j++)
362 ogg_int32_t *pcm=v->pcm[j]+prevCenter;
363 ogg_int32_t *p=vb->pcm[j];
365 /* the overlap/add section */
366 if(v->lW == v->W)
368 /* large/large or small/small */
369 vect_add_right_left(pcm,p,n);
370 v->pcmb[j]=pcm;
372 else if (!v->W)
374 /* large/small */
375 vect_add_right_left(pcm + (n1-n0)/2, p, n0);
376 v->pcmb[j]=pcm;
378 else
380 /* small/large */
381 p += (n1-n0)/2;
382 vect_add_left_right(p,pcm,n0);
383 v->pcmb[j]=p;
388 /* the copy section */
389 if(iram_pcm_doublebuffer)
391 /* just flip the pointers over as we have a double buffer in iram */
392 ogg_int32_t *p;
393 p=v->pcm[0];
394 v->pcm[0]=vb->pcm[0];
395 vb->pcm[0] = p;
396 p=v->pcm[1];
397 v->pcm[1]=vb->pcm[1];
398 vb->pcm[1] = p;
400 else
402 for(j=0;j<vi->channels;j++)
404 /* at best only vb->pcm is in iram, and that's where we do the
405 synthesis, so we copy out the right-hand subframe of last
406 synthesis into (noniram) local buffer so we can still do
407 synth in iram */
408 vect_copy(v->pcm[j]+v->centerW, vb->pcm[j]+n, n);
412 /* deal with initial packet state; we do this using the explicit
413 pcm_returned==-1 flag otherwise we're sensitive to first block
414 being short or long */
416 if(v->pcm_returned==-1){
417 v->pcm_returned=0;
418 v->pcm_current=0;
419 }else{
420 v->pcm_returned=0;
421 v->pcm_current=(n+ln)/2;
426 /* track the frame number... This is for convenience, but also
427 making sure our last packet doesn't end with added padding. If
428 the last packet is partial, the number of samples we'll have to
429 return will be past the vb->granulepos.
431 This is not foolproof! It will be confused if we begin
432 decoding at the last page after a seek or hole. In that case,
433 we don't have a starting point to judge where the last frame
434 is. For this reason, vorbisfile will always try to make sure
435 it reads the last two marked pages in proper sequence */
437 if(b->sample_count==-1){
438 b->sample_count=0;
439 }else{
440 b->sample_count+=(n+ln)/2;
443 if(v->granulepos==-1){
444 if(vb->granulepos!=-1){ /* only set if we have a position to set to */
446 v->granulepos=vb->granulepos;
448 /* is this a short page? */
449 if(b->sample_count>v->granulepos){
450 /* corner case; if this is both the first and last audio page,
451 then spec says the end is cut, not beginning */
452 if(vb->eofflag){
453 /* trim the end */
454 /* no preceeding granulepos; assume we started at zero (we'd
455 have to in a short single-page stream) */
456 /* granulepos could be -1 due to a seek, but that would result
457 in a long coun`t, not short count */
459 v->pcm_current-=(b->sample_count-v->granulepos);
460 }else{
461 /* trim the beginning */
462 v->pcm_returned+=(b->sample_count-v->granulepos);
463 if(v->pcm_returned>v->pcm_current)
464 v->pcm_returned=v->pcm_current;
470 }else{
471 v->granulepos+=(n+ln)/2;
472 if(vb->granulepos!=-1 && v->granulepos!=vb->granulepos){
474 if(v->granulepos>vb->granulepos){
475 long extra=v->granulepos-vb->granulepos;
477 if(extra)
478 if(vb->eofflag){
479 /* partial last frame. Strip the extra samples off */
480 v->pcm_current-=extra;
481 } /* else {Shouldn't happen *unless* the bitstream is out of
482 spec. Either way, believe the bitstream } */
483 } /* else {Shouldn't happen *unless* the bitstream is out of
484 spec. Either way, believe the bitstream } */
485 v->granulepos=vb->granulepos;
489 /* Update, cleanup */
491 if(vb->eofflag)v->eofflag=1;
492 return(0);
495 /* pcm==NULL indicates we just want the pending samples, no more */
496 int vorbis_synthesis_pcmout(vorbis_dsp_state *v,ogg_int32_t ***pcm) ICODE_ATTR;
497 int vorbis_synthesis_pcmout(vorbis_dsp_state *v,ogg_int32_t ***pcm){
498 vorbis_info *vi=v->vi;
499 if(v->pcm_returned>-1 && v->pcm_returned<v->pcm_current){
500 if(pcm){
501 int i;
502 for(i=0;i<vi->channels;i++)
503 v->pcmret[i]=v->pcmb[i]+v->pcm_returned;
504 *pcm=v->pcmret;
506 return(v->pcm_current-v->pcm_returned);
508 return(0);
511 int vorbis_synthesis_read(vorbis_dsp_state *v,int bytes){
512 if(bytes && v->pcm_returned+bytes>v->pcm_current)return(OV_EINVAL);
513 v->pcm_returned+=bytes;
514 return(0);