sync with en/mplayer.1 r30075
[mplayer/glamo.git] / tremor / block.c
blobe09fea553c20577ec2ee92819290a9d214ec339e
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"
28 #include "block.h"
30 static int ilog(unsigned int v){
31 int ret=0;
32 if(v)--v;
33 while(v){
34 ret++;
35 v>>=1;
37 return(ret);
40 /* pcm accumulator examples (not exhaustive):
42 <-------------- lW ---------------->
43 <--------------- W ---------------->
44 : .....|..... _______________ |
45 : .''' | '''_--- | |\ |
46 :.....''' |_____--- '''......| | \_______|
47 :.................|__________________|_______|__|______|
48 |<------ Sl ------>| > Sr < |endW
49 |beginSl |endSl | |endSr
50 |beginW |endlW |beginSr
53 |< lW >|
54 <--------------- W ---------------->
55 | | .. ______________ |
56 | | ' `/ | ---_ |
57 |___.'___/`. | ---_____|
58 |_______|__|_______|_________________|
59 | >|Sl|< |<------ Sr ----->|endW
60 | | |endSl |beginSr |endSr
61 |beginW | |endlW
62 mult[0] |beginSl mult[n]
64 <-------------- lW ----------------->
65 |<--W-->|
66 : .............. ___ | |
67 : .''' |`/ \ | |
68 :.....''' |/`....\|...|
69 :.........................|___|___|___|
70 |Sl |Sr |endW
71 | | |endSr
72 | |beginSr
73 | |endSl
74 |beginSl
75 |beginW
78 /* block abstraction setup *********************************************/
80 #ifndef WORD_ALIGN
81 #define WORD_ALIGN 8
82 #endif
84 int vorbis_block_init(vorbis_dsp_state *v, vorbis_block *vb){
85 memset(vb,0,sizeof(*vb));
86 vb->vd=v;
87 vb->localalloc=0;
88 vb->localstore=NULL;
90 return(0);
93 void *_vorbis_block_alloc(vorbis_block *vb,long bytes){
94 bytes=(bytes+(WORD_ALIGN-1)) & ~(WORD_ALIGN-1);
95 if(bytes+vb->localtop>vb->localalloc){
96 /* can't just _ogg_realloc... there are outstanding pointers */
97 if(vb->localstore){
98 struct alloc_chain *link=(struct alloc_chain *)_ogg_malloc(sizeof(*link));
99 vb->totaluse+=vb->localtop;
100 link->next=vb->reap;
101 link->ptr=vb->localstore;
102 vb->reap=link;
104 /* highly conservative */
105 vb->localalloc=bytes;
106 vb->localstore=_ogg_malloc(vb->localalloc);
107 vb->localtop=0;
110 void *ret=(void *)(((char *)vb->localstore)+vb->localtop);
111 vb->localtop+=bytes;
112 return ret;
116 /* reap the chain, pull the ripcord */
117 void _vorbis_block_ripcord(vorbis_block *vb){
118 /* reap the chain */
119 struct alloc_chain *reap=vb->reap;
120 while(reap){
121 struct alloc_chain *next=reap->next;
122 _ogg_free(reap->ptr);
123 memset(reap,0,sizeof(*reap));
124 _ogg_free(reap);
125 reap=next;
127 /* consolidate storage */
128 if(vb->totaluse){
129 vb->localstore=_ogg_realloc(vb->localstore,vb->totaluse+vb->localalloc);
130 vb->localalloc+=vb->totaluse;
131 vb->totaluse=0;
134 /* pull the ripcord */
135 vb->localtop=0;
136 vb->reap=NULL;
139 int vorbis_block_clear(vorbis_block *vb){
140 _vorbis_block_ripcord(vb);
141 if(vb->localstore)_ogg_free(vb->localstore);
143 memset(vb,0,sizeof(*vb));
144 return(0);
147 int vorbis_synthesis_init(vorbis_dsp_state *v,vorbis_info *vi){
148 int i;
149 codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
150 backend_lookup_state *b=NULL;
152 memset(v,0,sizeof(*v));
153 b=(backend_lookup_state *)(v->backend_state=_ogg_calloc(1,sizeof(*b)));
155 v->vi=vi;
156 b->modebits=ilog(ci->modes);
158 /* Vorbis I uses only window type 0 */
159 b->window[0]=_vorbis_window(0,ci->blocksizes[0]/2);
160 b->window[1]=_vorbis_window(0,ci->blocksizes[1]/2);
162 /* finish the codebooks */
163 if(!ci->fullbooks){
164 ci->fullbooks=(codebook *)_ogg_calloc(ci->books,sizeof(*ci->fullbooks));
165 for(i=0;i<ci->books;i++){
166 vorbis_book_init_decode(ci->fullbooks+i,ci->book_param[i]);
167 /* decode codebooks are now standalone after init */
168 vorbis_staticbook_destroy(ci->book_param[i]);
169 ci->book_param[i]=NULL;
173 v->pcm_storage=ci->blocksizes[1];
174 v->pcm=(ogg_int32_t **)_ogg_malloc(vi->channels*sizeof(*v->pcm));
175 v->pcmret=(ogg_int32_t **)_ogg_malloc(vi->channels*sizeof(*v->pcmret));
176 for(i=0;i<vi->channels;i++)
177 v->pcm[i]=(ogg_int32_t *)_ogg_calloc(v->pcm_storage,sizeof(*v->pcm[i]));
179 /* all 1 (large block) or 0 (small block) */
180 /* explicitly set for the sake of clarity */
181 v->lW=0; /* previous window size */
182 v->W=0; /* current window size */
184 /* all vector indexes */
185 v->centerW=ci->blocksizes[1]/2;
187 v->pcm_current=v->centerW;
189 /* initialize all the mapping/backend lookups */
190 b->mode=(vorbis_look_mapping **)_ogg_calloc(ci->modes,sizeof(*b->mode));
191 for(i=0;i<ci->modes;i++){
192 int mapnum=ci->mode_param[i]->mapping;
193 int maptype=ci->map_type[mapnum];
194 b->mode[i]=_mapping_P[maptype]->look(v,ci->mode_param[i],
195 ci->map_param[mapnum]);
198 v->pcm_returned=-1;
199 v->granulepos=-1;
200 v->sequence=-1;
202 return(0);
205 void vorbis_dsp_clear(vorbis_dsp_state *v){
206 int i;
207 if(v){
208 vorbis_info *vi=v->vi;
209 codec_setup_info *ci=(codec_setup_info *)(vi?vi->codec_setup:NULL);
210 backend_lookup_state *b=(backend_lookup_state *)v->backend_state;
212 if(v->pcm){
213 for(i=0;i<vi->channels;i++)
214 if(v->pcm[i])_ogg_free(v->pcm[i]);
215 _ogg_free(v->pcm);
216 if(v->pcmret)_ogg_free(v->pcmret);
219 /* free mode lookups; these are actually vorbis_look_mapping structs */
220 if(ci){
221 for(i=0;i<ci->modes;i++){
222 int mapnum=ci->mode_param[i]->mapping;
223 int maptype=ci->map_type[mapnum];
224 if(b && b->mode)_mapping_P[maptype]->free_look(b->mode[i]);
228 if(b){
229 if(b->mode)_ogg_free(b->mode);
230 _ogg_free(b);
233 memset(v,0,sizeof(*v));
237 /* Unlike in analysis, the window is only partially applied for each
238 block. The time domain envelope is not yet handled at the point of
239 calling (as it relies on the previous block). */
241 int vorbis_synthesis_blockin(vorbis_dsp_state *v,vorbis_block *vb){
242 vorbis_info *vi=v->vi;
243 codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
244 int i,j;
246 if(v->pcm_current>v->pcm_returned && v->pcm_returned!=-1)return(OV_EINVAL);
248 v->lW=v->W;
249 v->W=vb->W;
250 v->nW=-1;
252 if(v->sequence+1 != vb->sequence)v->granulepos=-1; /* out of sequence;
253 lose count */
255 v->sequence=vb->sequence;
258 int n=ci->blocksizes[v->W]/2;
259 int n0=ci->blocksizes[0]/2;
260 int n1=ci->blocksizes[1]/2;
262 int thisCenter;
263 int prevCenter;
265 if(v->centerW){
266 thisCenter=n1;
267 prevCenter=0;
268 }else{
269 thisCenter=0;
270 prevCenter=n1;
273 /* v->pcm is now used like a two-stage double buffer. We don't want
274 to have to constantly shift *or* adjust memory usage. Don't
275 accept a new block until the old is shifted out */
277 /* overlap/add PCM */
279 for(j=0;j<vi->channels;j++){
280 /* the overlap/add section */
281 if(v->lW){
282 if(v->W){
283 /* large/large */
284 ogg_int32_t *pcm=v->pcm[j]+prevCenter;
285 ogg_int32_t *p=vb->pcm[j];
286 for(i=0;i<n1;i++)
287 pcm[i]+=p[i];
288 }else{
289 /* large/small */
290 ogg_int32_t *pcm=v->pcm[j]+prevCenter+n1/2-n0/2;
291 ogg_int32_t *p=vb->pcm[j];
292 for(i=0;i<n0;i++)
293 pcm[i]+=p[i];
295 }else{
296 if(v->W){
297 /* small/large */
298 ogg_int32_t *pcm=v->pcm[j]+prevCenter;
299 ogg_int32_t *p=vb->pcm[j]+n1/2-n0/2;
300 for(i=0;i<n0;i++)
301 pcm[i]+=p[i];
302 for(;i<n1/2+n0/2;i++)
303 pcm[i]=p[i];
304 }else{
305 /* small/small */
306 ogg_int32_t *pcm=v->pcm[j]+prevCenter;
307 ogg_int32_t *p=vb->pcm[j];
308 for(i=0;i<n0;i++)
309 pcm[i]+=p[i];
313 /* the copy section */
315 ogg_int32_t *pcm=v->pcm[j]+thisCenter;
316 ogg_int32_t *p=vb->pcm[j]+n;
317 for(i=0;i<n;i++)
318 pcm[i]=p[i];
322 if(v->centerW)
323 v->centerW=0;
324 else
325 v->centerW=n1;
327 /* deal with initial packet state; we do this using the explicit
328 pcm_returned==-1 flag otherwise we're sensitive to first block
329 being short or long */
331 if(v->pcm_returned==-1){
332 v->pcm_returned=thisCenter;
333 v->pcm_current=thisCenter;
334 }else{
335 v->pcm_returned=prevCenter;
336 v->pcm_current=prevCenter+
337 ci->blocksizes[v->lW]/4+
338 ci->blocksizes[v->W]/4;
341 /* track the frame number... This is for convenience, but also
342 making sure our last packet doesn't end with added padding. If
343 the last packet is partial, the number of samples we'll have to
344 return will be past the vb->granulepos.
346 This is not foolproof! It will be confused if we begin
347 decoding at the last page after a seek or hole. In that case,
348 we don't have a starting point to judge where the last frame
349 is. For this reason, vorbisfile will always try to make sure
350 it reads the last two marked pages in proper sequence */
352 if(v->granulepos==-1)
353 if(vb->granulepos==-1){
354 v->granulepos=0;
355 }else{
356 v->granulepos=vb->granulepos;
358 else{
359 v->granulepos+=ci->blocksizes[v->lW]/4+ci->blocksizes[v->W]/4;
360 if(vb->granulepos!=-1 && v->granulepos!=vb->granulepos){
362 if(v->granulepos>vb->granulepos){
363 long extra=v->granulepos-vb->granulepos;
365 if(vb->eofflag){
366 /* partial last frame. Strip the extra samples off */
367 v->pcm_current-=extra;
368 }else if(vb->sequence == 1){
369 /* ^^^ argh, this can be 1 from seeking! */
372 /* partial first frame. Discard extra leading samples */
373 v->pcm_returned+=extra;
374 if(v->pcm_returned>v->pcm_current)
375 v->pcm_returned=v->pcm_current;
379 }/* else{ Shouldn't happen *unless* the bitstream is out of
380 spec. Either way, believe the bitstream } */
381 v->granulepos=vb->granulepos;
385 /* Update, cleanup */
387 if(vb->eofflag)v->eofflag=1;
390 return(0);
393 /* pcm==NULL indicates we just want the pending samples, no more */
394 int vorbis_synthesis_pcmout(vorbis_dsp_state *v,ogg_int32_t ***pcm){
395 vorbis_info *vi=v->vi;
396 if(v->pcm_returned>-1 && v->pcm_returned<v->pcm_current){
397 if(pcm){
398 int i;
399 for(i=0;i<vi->channels;i++)
400 v->pcmret[i]=v->pcm[i]+v->pcm_returned;
401 *pcm=v->pcmret;
403 return(v->pcm_current-v->pcm_returned);
405 return(0);
408 int vorbis_synthesis_read(vorbis_dsp_state *v,int bytes){
409 if(bytes && v->pcm_returned+bytes>v->pcm_current)return(OV_EINVAL);
410 v->pcm_returned+=bytes;
411 return(0);