7859
|
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 |
********************************************************************
|
|
13 |
|
|
14 |
function: PCM data vector blocking, windowing and dis/reassembly
|
|
15 |
|
|
16 |
********************************************************************/
|
|
17 |
|
|
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"
|
|
24 |
|
|
25 |
#include "window.h"
|
|
26 |
#include "registry.h"
|
|
27 |
#include "misc.h"
|
|
28 |
|
|
29 |
static int ilog(unsigned int v){
|
|
30 |
int ret=0;
|
|
31 |
if(v)--v;
|
|
32 |
while(v){
|
|
33 |
ret++;
|
|
34 |
v>>=1;
|
|
35 |
}
|
|
36 |
return(ret);
|
|
37 |
}
|
|
38 |
|
|
39 |
/* pcm accumulator examples (not exhaustive):
|
|
40 |
|
|
41 |
<-------------- lW ---------------->
|
|
42 |
<--------------- W ---------------->
|
|
43 |
: .....|..... _______________ |
|
|
44 |
: .''' | '''_--- | |\ |
|
|
45 |
:.....''' |_____--- '''......| | \_______|
|
|
46 |
:.................|__________________|_______|__|______|
|
|
47 |
|<------ Sl ------>| > Sr < |endW
|
|
48 |
|beginSl |endSl | |endSr
|
|
49 |
|beginW |endlW |beginSr
|
|
50 |
|
|
51 |
|
|
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]
|
|
62 |
|
|
63 |
<-------------- lW ----------------->
|
|
64 |
|<--W-->|
|
|
65 |
: .............. ___ | |
|
|
66 |
: .''' |`/ \ | |
|
|
67 |
:.....''' |/`....\|...|
|
|
68 |
:.........................|___|___|___|
|
|
69 |
|Sl |Sr |endW
|
|
70 |
| | |endSr
|
|
71 |
| |beginSr
|
|
72 |
| |endSl
|
|
73 |
|beginSl
|
|
74 |
|beginW
|
|
75 |
*/
|
|
76 |
|
|
77 |
/* block abstraction setup *********************************************/
|
|
78 |
|
|
79 |
#ifndef WORD_ALIGN
|
|
80 |
#define WORD_ALIGN 8
|
|
81 |
#endif
|
|
82 |
|
|
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;
|
|
88 |
|
|
89 |
return(0);
|
|
90 |
}
|
|
91 |
|
|
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;
|
|
102 |
}
|
|
103 |
/* highly conservative */
|
|
104 |
vb->localalloc=bytes;
|
|
105 |
vb->localstore=_ogg_malloc(vb->localalloc);
|
|
106 |
vb->localtop=0;
|
|
107 |
}
|
|
108 |
{
|
|
109 |
void *ret=(void *)(((char *)vb->localstore)+vb->localtop);
|
|
110 |
vb->localtop+=bytes;
|
|
111 |
return ret;
|
|
112 |
}
|
|
113 |
}
|
|
114 |
|
|
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;
|
|
125 |
}
|
|
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;
|
|
131 |
}
|
|
132 |
|
|
133 |
/* pull the ripcord */
|
|
134 |
vb->localtop=0;
|
|
135 |
vb->reap=NULL;
|
|
136 |
}
|
|
137 |
|
|
138 |
int vorbis_block_clear(vorbis_block *vb){
|
|
139 |
_vorbis_block_ripcord(vb);
|
|
140 |
if(vb->localstore)_ogg_free(vb->localstore);
|
|
141 |
|
|
142 |
memset(vb,0,sizeof(*vb));
|
|
143 |
return(0);
|
|
144 |
}
|
|
145 |
|
|
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;
|
|
150 |
|
|
151 |
memset(v,0,sizeof(*v));
|
|
152 |
b=(private_state *)(v->backend_state=_ogg_calloc(1,sizeof(*b)));
|
|
153 |
|
|
154 |
v->vi=vi;
|
|
155 |
b->modebits=ilog(ci->modes);
|
|
156 |
|
|
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);
|
|
160 |
|
|
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;
|
|
169 |
}
|
|
170 |
}
|
|
171 |
|
|
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]));
|
|
177 |
|
|
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 */
|
|
182 |
|
|
183 |
/* initialize all the mapping/backend lookups */
|
|
184 |
b->mode=(vorbis_look_mapping **)_ogg_calloc(ci->modes,sizeof(*b->mode));
|
|
185 |
for(i=0;i<ci->modes;i++){
|
|
186 |
int mapnum=ci->mode_param[i]->mapping;
|
|
187 |
int maptype=ci->map_type[mapnum];
|
|
188 |
b->mode[i]=_mapping_P[maptype]->look(v,ci->mode_param[i],
|
|
189 |
ci->map_param[mapnum]);
|
|
190 |
}
|
|
191 |
return(0);
|
|
192 |
}
|
|
193 |
|
|
194 |
int vorbis_synthesis_restart(vorbis_dsp_state *v){
|
|
195 |
vorbis_info *vi=v->vi;
|
|
196 |
codec_setup_info *ci;
|
|
197 |
|
|
198 |
if(!v->backend_state)return -1;
|
|
199 |
if(!vi)return -1;
|
|
200 |
ci=vi->codec_setup;
|
|
201 |
if(!ci)return -1;
|
|
202 |
|
|
203 |
v->centerW=ci->blocksizes[1]/2;
|
|
204 |
v->pcm_current=v->centerW;
|
|
205 |
|
|
206 |
v->pcm_returned=-1;
|
|
207 |
v->granulepos=-1;
|
|
208 |
v->sequence=-1;
|
|
209 |
((private_state *)(v->backend_state))->sample_count=-1;
|
|
210 |
|
|
211 |
return(0);
|
|
212 |
}
|
|
213 |
|
|
214 |
int vorbis_synthesis_init(vorbis_dsp_state *v,vorbis_info *vi){
|
|
215 |
_vds_init(v,vi);
|
|
216 |
vorbis_synthesis_restart(v);
|
|
217 |
|
|
218 |
return(0);
|
|
219 |
}
|
|
220 |
|
|
221 |
void vorbis_dsp_clear(vorbis_dsp_state *v){
|
|
222 |
int i;
|
|
223 |
if(v){
|
|
224 |
vorbis_info *vi=v->vi;
|
|
225 |
codec_setup_info *ci=(codec_setup_info *)(vi?vi->codec_setup:NULL);
|
|
226 |
private_state *b=(private_state *)v->backend_state;
|
|
227 |
|
|
228 |
if(v->pcm){
|
|
229 |
for(i=0;i<vi->channels;i++)
|
|
230 |
if(v->pcm[i])_ogg_free(v->pcm[i]);
|
|
231 |
_ogg_free(v->pcm);
|
|
232 |
if(v->pcmret)_ogg_free(v->pcmret);
|
|
233 |
}
|
|
234 |
|
|
235 |
/* free mode lookups; these are actually vorbis_look_mapping structs */
|
|
236 |
if(ci){
|
|
237 |
for(i=0;i<ci->modes;i++){
|
|
238 |
int mapnum=ci->mode_param[i]->mapping;
|
|
239 |
int maptype=ci->map_type[mapnum];
|
|
240 |
if(b && b->mode)_mapping_P[maptype]->free_look(b->mode[i]);
|
|
241 |
}
|
|
242 |
}
|
|
243 |
|
|
244 |
if(b){
|
|
245 |
if(b->mode)_ogg_free(b->mode);
|
|
246 |
_ogg_free(b);
|
|
247 |
}
|
|
248 |
|
|
249 |
memset(v,0,sizeof(*v));
|
|
250 |
}
|
|
251 |
}
|
|
252 |
|
|
253 |
/* Unlike in analysis, the window is only partially applied for each
|
|
254 |
block. The time domain envelope is not yet handled at the point of
|
|
255 |
calling (as it relies on the previous block). */
|
|
256 |
|
|
257 |
int vorbis_synthesis_blockin(vorbis_dsp_state *v,vorbis_block *vb){
|
|
258 |
vorbis_info *vi=v->vi;
|
|
259 |
codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
|
|
260 |
private_state *b=v->backend_state;
|
|
261 |
int i,j;
|
|
262 |
|
|
263 |
if(v->pcm_current>v->pcm_returned && v->pcm_returned!=-1)return(OV_EINVAL);
|
|
264 |
|
|
265 |
v->lW=v->W;
|
|
266 |
v->W=vb->W;
|
|
267 |
v->nW=-1;
|
|
268 |
|
|
269 |
if((v->sequence==-1)||
|
|
270 |
(v->sequence+1 != vb->sequence)){
|
|
271 |
v->granulepos=-1; /* out of sequence; lose count */
|
|
272 |
b->sample_count=-1;
|
|
273 |
}
|
|
274 |
|
|
275 |
v->sequence=vb->sequence;
|
|
276 |
|
|
277 |
if(vb->pcm){ /* no pcm to process if vorbis_synthesis_trackonly
|
|
278 |
was called on block */
|
|
279 |
int n=ci->blocksizes[v->W]/2;
|
|
280 |
int n0=ci->blocksizes[0]/2;
|
|
281 |
int n1=ci->blocksizes[1]/2;
|
|
282 |
|
|
283 |
int thisCenter;
|
|
284 |
int prevCenter;
|
|
285 |
|
|
286 |
if(v->centerW){
|
|
287 |
thisCenter=n1;
|
|
288 |
prevCenter=0;
|
|
289 |
}else{
|
|
290 |
thisCenter=0;
|
|
291 |
prevCenter=n1;
|
|
292 |
}
|
|
293 |
|
|
294 |
/* v->pcm is now used like a two-stage double buffer. We don't want
|
|
295 |
to have to constantly shift *or* adjust memory usage. Don't
|
|
296 |
accept a new block until the old is shifted out */
|
|
297 |
|
|
298 |
/* overlap/add PCM */
|
|
299 |
|
|
300 |
for(j=0;j<vi->channels;j++){
|
|
301 |
/* the overlap/add section */
|
|
302 |
if(v->lW){
|
|
303 |
if(v->W){
|
|
304 |
/* large/large */
|
|
305 |
ogg_int32_t *pcm=v->pcm[j]+prevCenter;
|
|
306 |
ogg_int32_t *p=vb->pcm[j];
|
|
307 |
for(i=0;i<n1;i++)
|
|
308 |
pcm[i]+=p[i];
|
|
309 |
}else{
|
|
310 |
/* large/small */
|
|
311 |
ogg_int32_t *pcm=v->pcm[j]+prevCenter+n1/2-n0/2;
|
|
312 |
ogg_int32_t *p=vb->pcm[j];
|
|
313 |
for(i=0;i<n0;i++)
|
|
314 |
pcm[i]+=p[i];
|
|
315 |
}
|
|
316 |
}else{
|
|
317 |
if(v->W){
|
|
318 |
/* small/large */
|
|
319 |
ogg_int32_t *pcm=v->pcm[j]+prevCenter;
|
|
320 |
ogg_int32_t *p=vb->pcm[j]+n1/2-n0/2;
|
|
321 |
for(i=0;i<n0;i++)
|
|
322 |
pcm[i]+=p[i];
|
|
323 |
for(;i<n1/2+n0/2;i++)
|
|
324 |
pcm[i]=p[i];
|
|
325 |
}else{
|
|
326 |
/* small/small */
|
|
327 |
ogg_int32_t *pcm=v->pcm[j]+prevCenter;
|
|
328 |
ogg_int32_t *p=vb->pcm[j];
|
|
329 |
for(i=0;i<n0;i++)
|
|
330 |
pcm[i]+=p[i];
|
|
331 |
}
|
|
332 |
}
|
|
333 |
|
|
334 |
/* the copy section */
|
|
335 |
{
|
|
336 |
ogg_int32_t *pcm=v->pcm[j]+thisCenter;
|
|
337 |
ogg_int32_t *p=vb->pcm[j]+n;
|
|
338 |
for(i=0;i<n;i++)
|
|
339 |
pcm[i]=p[i];
|
|
340 |
}
|
|
341 |
}
|
|
342 |
|
|
343 |
if(v->centerW)
|
|
344 |
v->centerW=0;
|
|
345 |
else
|
|
346 |
v->centerW=n1;
|
|
347 |
|
|
348 |
/* deal with initial packet state; we do this using the explicit
|
|
349 |
pcm_returned==-1 flag otherwise we're sensitive to first block
|
|
350 |
being short or long */
|
|
351 |
|
|
352 |
if(v->pcm_returned==-1){
|
|
353 |
v->pcm_returned=thisCenter;
|
|
354 |
v->pcm_current=thisCenter;
|
|
355 |
}else{
|
|
356 |
v->pcm_returned=prevCenter;
|
|
357 |
v->pcm_current=prevCenter+
|
|
358 |
ci->blocksizes[v->lW]/4+
|
|
359 |
ci->blocksizes[v->W]/4;
|
|
360 |
}
|
|
361 |
|
|
362 |
}
|
|
363 |
|
|
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.
|
|
368 |
|
|
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 */
|
|
374 |
|
|
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;
|
|
379 |
}
|
|
380 |
|
|
381 |
if(v->granulepos==-1){
|
|
382 |
if(vb->granulepos!=-1){ /* only set if we have a position to set to */
|
|
383 |
|
|
384 |
v->granulepos=vb->granulepos;
|
|
385 |
|
|
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 */
|
|
396 |
|
|
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;
|
|
403 |
}
|
|
404 |
|
|
405 |
}
|
|
406 |
|
|
407 |
}
|
|
408 |
}else{
|
|
409 |
v->granulepos+=ci->blocksizes[v->lW]/4+ci->blocksizes[v->W]/4;
|
|
410 |
if(vb->granulepos!=-1 && v->granulepos!=vb->granulepos){
|
|
411 |
|
|
412 |
if(v->granulepos>vb->granulepos){
|
|
413 |
long extra=v->granulepos-vb->granulepos;
|
|
414 |
|
|
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;
|
|
424 |
}
|
|
425 |
}
|
|
426 |
|
|
427 |
/* Update, cleanup */
|
|
428 |
|
|
429 |
if(vb->eofflag)v->eofflag=1;
|
|
430 |
return(0);
|
|
431 |
}
|
|
432 |
|
|
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){
|
|
435 |
vorbis_info *vi=v->vi;
|
|
436 |
if(v->pcm_returned>-1 && v->pcm_returned<v->pcm_current){
|
|
437 |
if(pcm){
|
|
438 |
int i;
|
|
439 |
for(i=0;i<vi->channels;i++)
|
|
440 |
v->pcmret[i]=v->pcm[i]+v->pcm_returned;
|
|
441 |
*pcm=v->pcmret;
|
|
442 |
}
|
|
443 |
return(v->pcm_current-v->pcm_returned);
|
|
444 |
}
|
|
445 |
return(0);
|
|
446 |
}
|
|
447 |
|
|
448 |
int vorbis_synthesis_read(vorbis_dsp_state *v,int bytes){
|
|
449 |
if(bytes && v->pcm_returned+bytes>v->pcm_current)return(OV_EINVAL);
|
|
450 |
v->pcm_returned+=bytes;
|
|
451 |
return(0);
|
|
452 |
}
|
|
453 |
|