comparison tremor/block.c @ 14280:8631a3803289

internal Tremor decoder for Ogg/Vorbis
author henry
date Thu, 30 Dec 2004 12:11:32 +0000
parents
children cd6b211be811
comparison
equal deleted inserted replaced
14279:b4b202086260 14280:8631a3803289
1 /********************************************************************
2 * *
3 * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
4 * *
5 * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
6 * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
7 * ALL REDISTRIBUTION RIGHTS RESERVED. *
8 * *
9 ********************************************************************
10
11 function: PCM data vector blocking, windowing and dis/reassembly
12
13 ********************************************************************/
14
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include "ogg.h"
19 #include "ivorbiscodec.h"
20 #include "codec_internal.h"
21
22 #include "window.h"
23 #include "registry.h"
24 #include "misc.h"
25
26 static int ilog(unsigned int v){
27 int ret=0;
28 if(v)--v;
29 while(v){
30 ret++;
31 v>>=1;
32 }
33 return(ret);
34 }
35
36 /* pcm accumulator examples (not exhaustive):
37
38 <-------------- lW ---------------->
39 <--------------- W ---------------->
40 : .....|..... _______________ |
41 : .''' | '''_--- | |\ |
42 :.....''' |_____--- '''......| | \_______|
43 :.................|__________________|_______|__|______|
44 |<------ Sl ------>| > Sr < |endW
45 |beginSl |endSl | |endSr
46 |beginW |endlW |beginSr
47
48
49 |< lW >|
50 <--------------- W ---------------->
51 | | .. ______________ |
52 | | ' `/ | ---_ |
53 |___.'___/`. | ---_____|
54 |_______|__|_______|_________________|
55 | >|Sl|< |<------ Sr ----->|endW
56 | | |endSl |beginSr |endSr
57 |beginW | |endlW
58 mult[0] |beginSl mult[n]
59
60 <-------------- lW ----------------->
61 |<--W-->|
62 : .............. ___ | |
63 : .''' |`/ \ | |
64 :.....''' |/`....\|...|
65 :.........................|___|___|___|
66 |Sl |Sr |endW
67 | | |endSr
68 | |beginSr
69 | |endSl
70 |beginSl
71 |beginW
72 */
73
74 /* block abstraction setup *********************************************/
75
76 #ifndef WORD_ALIGN
77 #define WORD_ALIGN 8
78 #endif
79
80 int vorbis_block_init(vorbis_dsp_state *v, vorbis_block *vb){
81 memset(vb,0,sizeof(*vb));
82 vb->vd=v;
83 vb->localalloc=0;
84 vb->localstore=NULL;
85
86 return(0);
87 }
88
89 void *_vorbis_block_alloc(vorbis_block *vb,long bytes){
90 bytes=(bytes+(WORD_ALIGN-1)) & ~(WORD_ALIGN-1);
91 if(bytes+vb->localtop>vb->localalloc){
92 /* can't just _ogg_realloc... there are outstanding pointers */
93 if(vb->localstore){
94 struct alloc_chain *link=(struct alloc_chain *)_ogg_malloc(sizeof(*link));
95 vb->totaluse+=vb->localtop;
96 link->next=vb->reap;
97 link->ptr=vb->localstore;
98 vb->reap=link;
99 }
100 /* highly conservative */
101 vb->localalloc=bytes;
102 vb->localstore=_ogg_malloc(vb->localalloc);
103 vb->localtop=0;
104 }
105 {
106 void *ret=(void *)(((char *)vb->localstore)+vb->localtop);
107 vb->localtop+=bytes;
108 return ret;
109 }
110 }
111
112 /* reap the chain, pull the ripcord */
113 void _vorbis_block_ripcord(vorbis_block *vb){
114 /* reap the chain */
115 struct alloc_chain *reap=vb->reap;
116 while(reap){
117 struct alloc_chain *next=reap->next;
118 _ogg_free(reap->ptr);
119 memset(reap,0,sizeof(*reap));
120 _ogg_free(reap);
121 reap=next;
122 }
123 /* consolidate storage */
124 if(vb->totaluse){
125 vb->localstore=_ogg_realloc(vb->localstore,vb->totaluse+vb->localalloc);
126 vb->localalloc+=vb->totaluse;
127 vb->totaluse=0;
128 }
129
130 /* pull the ripcord */
131 vb->localtop=0;
132 vb->reap=NULL;
133 }
134
135 int vorbis_block_clear(vorbis_block *vb){
136 _vorbis_block_ripcord(vb);
137 if(vb->localstore)_ogg_free(vb->localstore);
138
139 memset(vb,0,sizeof(*vb));
140 return(0);
141 }
142
143 int vorbis_synthesis_init(vorbis_dsp_state *v,vorbis_info *vi){
144 int i;
145 codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
146 backend_lookup_state *b=NULL;
147
148 memset(v,0,sizeof(*v));
149 b=(backend_lookup_state *)(v->backend_state=_ogg_calloc(1,sizeof(*b)));
150
151 v->vi=vi;
152 b->modebits=ilog(ci->modes);
153
154 /* Vorbis I uses only window type 0 */
155 b->window[0]=_vorbis_window(0,ci->blocksizes[0]/2);
156 b->window[1]=_vorbis_window(0,ci->blocksizes[1]/2);
157
158 /* finish the codebooks */
159 if(!ci->fullbooks){
160 ci->fullbooks=(codebook *)_ogg_calloc(ci->books,sizeof(*ci->fullbooks));
161 for(i=0;i<ci->books;i++){
162 vorbis_book_init_decode(ci->fullbooks+i,ci->book_param[i]);
163 /* decode codebooks are now standalone after init */
164 vorbis_staticbook_destroy(ci->book_param[i]);
165 ci->book_param[i]=NULL;
166 }
167 }
168
169 v->pcm_storage=ci->blocksizes[1];
170 v->pcm=(ogg_int32_t **)_ogg_malloc(vi->channels*sizeof(*v->pcm));
171 v->pcmret=(ogg_int32_t **)_ogg_malloc(vi->channels*sizeof(*v->pcmret));
172 for(i=0;i<vi->channels;i++)
173 v->pcm[i]=(ogg_int32_t *)_ogg_calloc(v->pcm_storage,sizeof(*v->pcm[i]));
174
175 /* all 1 (large block) or 0 (small block) */
176 /* explicitly set for the sake of clarity */
177 v->lW=0; /* previous window size */
178 v->W=0; /* current window size */
179
180 /* all vector indexes */
181 v->centerW=ci->blocksizes[1]/2;
182
183 v->pcm_current=v->centerW;
184
185 /* initialize all the mapping/backend lookups */
186 b->mode=(vorbis_look_mapping **)_ogg_calloc(ci->modes,sizeof(*b->mode));
187 for(i=0;i<ci->modes;i++){
188 int mapnum=ci->mode_param[i]->mapping;
189 int maptype=ci->map_type[mapnum];
190 b->mode[i]=_mapping_P[maptype]->look(v,ci->mode_param[i],
191 ci->map_param[mapnum]);
192 }
193
194 v->pcm_returned=-1;
195 v->granulepos=-1;
196 v->sequence=-1;
197
198 return(0);
199 }
200
201 void vorbis_dsp_clear(vorbis_dsp_state *v){
202 int i;
203 if(v){
204 vorbis_info *vi=v->vi;
205 codec_setup_info *ci=(codec_setup_info *)(vi?vi->codec_setup:NULL);
206 backend_lookup_state *b=(backend_lookup_state *)v->backend_state;
207
208 if(v->pcm){
209 for(i=0;i<vi->channels;i++)
210 if(v->pcm[i])_ogg_free(v->pcm[i]);
211 _ogg_free(v->pcm);
212 if(v->pcmret)_ogg_free(v->pcmret);
213 }
214
215 /* free mode lookups; these are actually vorbis_look_mapping structs */
216 if(ci){
217 for(i=0;i<ci->modes;i++){
218 int mapnum=ci->mode_param[i]->mapping;
219 int maptype=ci->map_type[mapnum];
220 if(b && b->mode)_mapping_P[maptype]->free_look(b->mode[i]);
221 }
222 }
223
224 if(b){
225 if(b->mode)_ogg_free(b->mode);
226 _ogg_free(b);
227 }
228
229 memset(v,0,sizeof(*v));
230 }
231 }
232
233 /* Unlike in analysis, the window is only partially applied for each
234 block. The time domain envelope is not yet handled at the point of
235 calling (as it relies on the previous block). */
236
237 int vorbis_synthesis_blockin(vorbis_dsp_state *v,vorbis_block *vb){
238 vorbis_info *vi=v->vi;
239 codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
240 int i,j;
241
242 if(v->pcm_current>v->pcm_returned && v->pcm_returned!=-1)return(OV_EINVAL);
243
244 v->lW=v->W;
245 v->W=vb->W;
246 v->nW=-1;
247
248 if(v->sequence+1 != vb->sequence)v->granulepos=-1; /* out of sequence;
249 lose count */
250
251 v->sequence=vb->sequence;
252
253 {
254 int n=ci->blocksizes[v->W]/2;
255 int n0=ci->blocksizes[0]/2;
256 int n1=ci->blocksizes[1]/2;
257
258 int thisCenter;
259 int prevCenter;
260
261 if(v->centerW){
262 thisCenter=n1;
263 prevCenter=0;
264 }else{
265 thisCenter=0;
266 prevCenter=n1;
267 }
268
269 /* v->pcm is now used like a two-stage double buffer. We don't want
270 to have to constantly shift *or* adjust memory usage. Don't
271 accept a new block until the old is shifted out */
272
273 /* overlap/add PCM */
274
275 for(j=0;j<vi->channels;j++){
276 /* the overlap/add section */
277 if(v->lW){
278 if(v->W){
279 /* large/large */
280 ogg_int32_t *pcm=v->pcm[j]+prevCenter;
281 ogg_int32_t *p=vb->pcm[j];
282 for(i=0;i<n1;i++)
283 pcm[i]+=p[i];
284 }else{
285 /* large/small */
286 ogg_int32_t *pcm=v->pcm[j]+prevCenter+n1/2-n0/2;
287 ogg_int32_t *p=vb->pcm[j];
288 for(i=0;i<n0;i++)
289 pcm[i]+=p[i];
290 }
291 }else{
292 if(v->W){
293 /* small/large */
294 ogg_int32_t *pcm=v->pcm[j]+prevCenter;
295 ogg_int32_t *p=vb->pcm[j]+n1/2-n0/2;
296 for(i=0;i<n0;i++)
297 pcm[i]+=p[i];
298 for(;i<n1/2+n0/2;i++)
299 pcm[i]=p[i];
300 }else{
301 /* small/small */
302 ogg_int32_t *pcm=v->pcm[j]+prevCenter;
303 ogg_int32_t *p=vb->pcm[j];
304 for(i=0;i<n0;i++)
305 pcm[i]+=p[i];
306 }
307 }
308
309 /* the copy section */
310 {
311 ogg_int32_t *pcm=v->pcm[j]+thisCenter;
312 ogg_int32_t *p=vb->pcm[j]+n;
313 for(i=0;i<n;i++)
314 pcm[i]=p[i];
315 }
316 }
317
318 if(v->centerW)
319 v->centerW=0;
320 else
321 v->centerW=n1;
322
323 /* deal with initial packet state; we do this using the explicit
324 pcm_returned==-1 flag otherwise we're sensitive to first block
325 being short or long */
326
327 if(v->pcm_returned==-1){
328 v->pcm_returned=thisCenter;
329 v->pcm_current=thisCenter;
330 }else{
331 v->pcm_returned=prevCenter;
332 v->pcm_current=prevCenter+
333 ci->blocksizes[v->lW]/4+
334 ci->blocksizes[v->W]/4;
335 }
336
337 /* track the frame number... This is for convenience, but also
338 making sure our last packet doesn't end with added padding. If
339 the last packet is partial, the number of samples we'll have to
340 return will be past the vb->granulepos.
341
342 This is not foolproof! It will be confused if we begin
343 decoding at the last page after a seek or hole. In that case,
344 we don't have a starting point to judge where the last frame
345 is. For this reason, vorbisfile will always try to make sure
346 it reads the last two marked pages in proper sequence */
347
348 if(v->granulepos==-1)
349 if(vb->granulepos==-1){
350 v->granulepos=0;
351 }else{
352 v->granulepos=vb->granulepos;
353 }
354 else{
355 v->granulepos+=ci->blocksizes[v->lW]/4+ci->blocksizes[v->W]/4;
356 if(vb->granulepos!=-1 && v->granulepos!=vb->granulepos){
357
358 if(v->granulepos>vb->granulepos){
359 long extra=v->granulepos-vb->granulepos;
360
361 if(vb->eofflag){
362 /* partial last frame. Strip the extra samples off */
363 v->pcm_current-=extra;
364 }else if(vb->sequence == 1){
365 /* ^^^ argh, this can be 1 from seeking! */
366
367
368 /* partial first frame. Discard extra leading samples */
369 v->pcm_returned+=extra;
370 if(v->pcm_returned>v->pcm_current)
371 v->pcm_returned=v->pcm_current;
372
373 }
374
375 }/* else{ Shouldn't happen *unless* the bitstream is out of
376 spec. Either way, believe the bitstream } */
377 v->granulepos=vb->granulepos;
378 }
379 }
380
381 /* Update, cleanup */
382
383 if(vb->eofflag)v->eofflag=1;
384 }
385
386 return(0);
387 }
388
389 /* pcm==NULL indicates we just want the pending samples, no more */
390 int vorbis_synthesis_pcmout(vorbis_dsp_state *v,ogg_int32_t ***pcm){
391 vorbis_info *vi=v->vi;
392 if(v->pcm_returned>-1 && v->pcm_returned<v->pcm_current){
393 if(pcm){
394 int i;
395 for(i=0;i<vi->channels;i++)
396 v->pcmret[i]=v->pcm[i]+v->pcm_returned;
397 *pcm=v->pcmret;
398 }
399 return(v->pcm_current-v->pcm_returned);
400 }
401 return(0);
402 }
403
404 int vorbis_synthesis_read(vorbis_dsp_state *v,int bytes){
405 if(bytes && v->pcm_returned+bytes>v->pcm_current)return(OV_EINVAL);
406 v->pcm_returned+=bytes;
407 return(0);
408 }
409