Fix compilation by adding forgotten comma.
[mplayer/glamo.git] / tremor / block.c
blob7f9c0940611d9d3200bb61961195e5df0e60d597
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 <stdio.h>
19 #include <stdlib.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 int vorbis_synthesis_init(vorbis_dsp_state *v,vorbis_info *vi){
147 int i;
148 codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
149 backend_lookup_state *b=NULL;
151 memset(v,0,sizeof(*v));
152 b=(backend_lookup_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->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]));
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 */
183 /* all vector indexes */
184 v->centerW=ci->blocksizes[1]/2;
186 v->pcm_current=v->centerW;
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]);
197 v->pcm_returned=-1;
198 v->granulepos=-1;
199 v->sequence=-1;
201 return(0);
204 void vorbis_dsp_clear(vorbis_dsp_state *v){
205 int i;
206 if(v){
207 vorbis_info *vi=v->vi;
208 codec_setup_info *ci=(codec_setup_info *)(vi?vi->codec_setup:NULL);
209 backend_lookup_state *b=(backend_lookup_state *)v->backend_state;
211 if(v->pcm){
212 for(i=0;i<vi->channels;i++)
213 if(v->pcm[i])_ogg_free(v->pcm[i]);
214 _ogg_free(v->pcm);
215 if(v->pcmret)_ogg_free(v->pcmret);
218 /* free mode lookups; these are actually vorbis_look_mapping structs */
219 if(ci){
220 for(i=0;i<ci->modes;i++){
221 int mapnum=ci->mode_param[i]->mapping;
222 int maptype=ci->map_type[mapnum];
223 if(b && b->mode)_mapping_P[maptype]->free_look(b->mode[i]);
227 if(b){
228 if(b->mode)_ogg_free(b->mode);
229 _ogg_free(b);
232 memset(v,0,sizeof(*v));
236 /* Unlike in analysis, the window is only partially applied for each
237 block. The time domain envelope is not yet handled at the point of
238 calling (as it relies on the previous block). */
240 int vorbis_synthesis_blockin(vorbis_dsp_state *v,vorbis_block *vb){
241 vorbis_info *vi=v->vi;
242 codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
243 int i,j;
245 if(v->pcm_current>v->pcm_returned && v->pcm_returned!=-1)return(OV_EINVAL);
247 v->lW=v->W;
248 v->W=vb->W;
249 v->nW=-1;
251 if(v->sequence+1 != vb->sequence)v->granulepos=-1; /* out of sequence;
252 lose count */
254 v->sequence=vb->sequence;
257 int n=ci->blocksizes[v->W]/2;
258 int n0=ci->blocksizes[0]/2;
259 int n1=ci->blocksizes[1]/2;
261 int thisCenter;
262 int prevCenter;
264 if(v->centerW){
265 thisCenter=n1;
266 prevCenter=0;
267 }else{
268 thisCenter=0;
269 prevCenter=n1;
272 /* v->pcm is now used like a two-stage double buffer. We don't want
273 to have to constantly shift *or* adjust memory usage. Don't
274 accept a new block until the old is shifted out */
276 /* overlap/add PCM */
278 for(j=0;j<vi->channels;j++){
279 /* the overlap/add section */
280 if(v->lW){
281 if(v->W){
282 /* large/large */
283 ogg_int32_t *pcm=v->pcm[j]+prevCenter;
284 ogg_int32_t *p=vb->pcm[j];
285 for(i=0;i<n1;i++)
286 pcm[i]+=p[i];
287 }else{
288 /* large/small */
289 ogg_int32_t *pcm=v->pcm[j]+prevCenter+n1/2-n0/2;
290 ogg_int32_t *p=vb->pcm[j];
291 for(i=0;i<n0;i++)
292 pcm[i]+=p[i];
294 }else{
295 if(v->W){
296 /* small/large */
297 ogg_int32_t *pcm=v->pcm[j]+prevCenter;
298 ogg_int32_t *p=vb->pcm[j]+n1/2-n0/2;
299 for(i=0;i<n0;i++)
300 pcm[i]+=p[i];
301 for(;i<n1/2+n0/2;i++)
302 pcm[i]=p[i];
303 }else{
304 /* small/small */
305 ogg_int32_t *pcm=v->pcm[j]+prevCenter;
306 ogg_int32_t *p=vb->pcm[j];
307 for(i=0;i<n0;i++)
308 pcm[i]+=p[i];
312 /* the copy section */
314 ogg_int32_t *pcm=v->pcm[j]+thisCenter;
315 ogg_int32_t *p=vb->pcm[j]+n;
316 for(i=0;i<n;i++)
317 pcm[i]=p[i];
321 if(v->centerW)
322 v->centerW=0;
323 else
324 v->centerW=n1;
326 /* deal with initial packet state; we do this using the explicit
327 pcm_returned==-1 flag otherwise we're sensitive to first block
328 being short or long */
330 if(v->pcm_returned==-1){
331 v->pcm_returned=thisCenter;
332 v->pcm_current=thisCenter;
333 }else{
334 v->pcm_returned=prevCenter;
335 v->pcm_current=prevCenter+
336 ci->blocksizes[v->lW]/4+
337 ci->blocksizes[v->W]/4;
340 /* track the frame number... This is for convenience, but also
341 making sure our last packet doesn't end with added padding. If
342 the last packet is partial, the number of samples we'll have to
343 return will be past the vb->granulepos.
345 This is not foolproof! It will be confused if we begin
346 decoding at the last page after a seek or hole. In that case,
347 we don't have a starting point to judge where the last frame
348 is. For this reason, vorbisfile will always try to make sure
349 it reads the last two marked pages in proper sequence */
351 if(v->granulepos==-1)
352 if(vb->granulepos==-1){
353 v->granulepos=0;
354 }else{
355 v->granulepos=vb->granulepos;
357 else{
358 v->granulepos+=ci->blocksizes[v->lW]/4+ci->blocksizes[v->W]/4;
359 if(vb->granulepos!=-1 && v->granulepos!=vb->granulepos){
361 if(v->granulepos>vb->granulepos){
362 long extra=v->granulepos-vb->granulepos;
364 if(vb->eofflag){
365 /* partial last frame. Strip the extra samples off */
366 v->pcm_current-=extra;
367 }else if(vb->sequence == 1){
368 /* ^^^ argh, this can be 1 from seeking! */
371 /* partial first frame. Discard extra leading samples */
372 v->pcm_returned+=extra;
373 if(v->pcm_returned>v->pcm_current)
374 v->pcm_returned=v->pcm_current;
378 }/* else{ Shouldn't happen *unless* the bitstream is out of
379 spec. Either way, believe the bitstream } */
380 v->granulepos=vb->granulepos;
384 /* Update, cleanup */
386 if(vb->eofflag)v->eofflag=1;
389 return(0);
392 /* pcm==NULL indicates we just want the pending samples, no more */
393 int vorbis_synthesis_pcmout(vorbis_dsp_state *v,ogg_int32_t ***pcm){
394 vorbis_info *vi=v->vi;
395 if(v->pcm_returned>-1 && v->pcm_returned<v->pcm_current){
396 if(pcm){
397 int i;
398 for(i=0;i<vi->channels;i++)
399 v->pcmret[i]=v->pcm[i]+v->pcm_returned;
400 *pcm=v->pcmret;
402 return(v->pcm_current-v->pcm_returned);
404 return(0);
407 int vorbis_synthesis_read(vorbis_dsp_state *v,int bytes){
408 if(bytes && v->pcm_returned+bytes>v->pcm_current)return(OV_EINVAL);
409 v->pcm_returned+=bytes;
410 return(0);