Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/genplus-gx32/core/tremor/block.c
2 views
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
454
455