1 /********************************************************************
3 * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
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. *
9 * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
10 * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
12 ********************************************************************
14 function: PCM data vector blocking, windowing and dis/reassembly
16 ********************************************************************/
18 #include "config-tremor.h"
22 #include "ivorbiscodec.h"
23 #include "codec_internal.h"
29 static int ilog(unsigned int v
){
39 static ogg_int32_t
* _pcmp
[CHANNELS
] IBSS_ATTR
;
40 static ogg_int32_t
* _pcmbp
[CHANNELS
] IBSS_ATTR
;
41 static ogg_int32_t
* _pcmret
[CHANNELS
] IBSS_ATTR
;
43 /* pcm accumulator examples (not exhaustive):
45 <-------------- lW ---------------->
46 <--------------- W ---------------->
47 : .....|..... _______________ |
48 : .''' | '''_--- | |\ |
49 :.....''' |_____--- '''......| | \_______|
50 :.................|__________________|_______|__|______|
51 |<------ Sl ------>| > Sr < |endW
52 |beginSl |endSl | |endSr
53 |beginW |endlW |beginSr
57 <--------------- W ---------------->
58 | | .. ______________ |
60 |___.'___/`. | ---_____|
61 |_______|__|_______|_________________|
62 | >|Sl|< |<------ Sr ----->|endW
63 | | |endSl |beginSr |endSr
65 mult[0] |beginSl mult[n]
67 <-------------- lW ----------------->
69 : .............. ___ | |
71 :.....''' |/`....\|...|
72 :.........................|___|___|___|
81 /* block abstraction setup *********************************************/
87 int vorbis_block_init(vorbis_dsp_state
*v
, vorbis_block
*vb
){
88 memset(vb
,0,sizeof(*vb
));
96 void *_vorbis_block_alloc(vorbis_block
*vb
,long bytes
){
97 bytes
=(bytes
+(WORD_ALIGN
-1)) & ~(WORD_ALIGN
-1);
98 if(bytes
+vb
->localtop
>vb
->localalloc
){
99 /* can't just _ogg_realloc... there are outstanding pointers */
101 struct alloc_chain
*link
=(struct alloc_chain
*)_ogg_malloc(sizeof(*link
));
102 vb
->totaluse
+=vb
->localtop
;
104 link
->ptr
=vb
->localstore
;
107 /* highly conservative */
108 vb
->localalloc
=bytes
;
109 vb
->localstore
=_ogg_malloc(vb
->localalloc
);
113 void *ret
=(void *)(((char *)vb
->localstore
)+vb
->localtop
);
119 /* reap the chain, pull the ripcord */
120 void _vorbis_block_ripcord(vorbis_block
*vb
){
122 struct alloc_chain
*reap
=vb
->reap
;
124 struct alloc_chain
*next
=reap
->next
;
125 _ogg_free(reap
->ptr
);
126 memset(reap
,0,sizeof(*reap
));
130 /* consolidate storage */
132 vb
->localstore
=_ogg_realloc(vb
->localstore
,vb
->totaluse
+vb
->localalloc
);
133 vb
->localalloc
+=vb
->totaluse
;
137 /* pull the ripcord */
142 int vorbis_block_clear(vorbis_block
*vb
){
143 _vorbis_block_ripcord(vb
);
144 if(vb
->localstore
)_ogg_free(vb
->localstore
);
146 memset(vb
,0,sizeof(*vb
));
150 static int _vds_init(vorbis_dsp_state
*v
,vorbis_info
*vi
){
153 LOOKUP_TNC
*iramposw
;
155 codec_setup_info
*ci
=(codec_setup_info
*)vi
->codec_setup
;
156 private_state
*b
=NULL
;
158 memset(v
,0,sizeof(*v
));
160 b
=(private_state
*)(v
->backend_state
=_ogg_calloc(1,sizeof(*b
)));
163 b
->modebits
=ilog(ci
->modes
);
165 /* allocate IRAM buffer for the PCM data generated by synthesis */
167 v
->iram_pcm
=(ogg_int32_t
*)iram_malloc(vi
->channels
*ci
->blocksizes
[1]*sizeof(ogg_int32_t
));
168 if(v
->iram_pcm
!= NULL
) v
->iram_pcm_storage
=ci
->blocksizes
[1];
169 else v
->iram_pcm_storage
=0;
173 /* Vorbis I uses only window type 0 */
174 b_size
[0]=ci
->blocksizes
[0]/2;
175 b_size
[1]=ci
->blocksizes
[1]/2;
176 b
->window
[0]=_vorbis_window(0,b_size
[0]);
177 b
->window
[1]=_vorbis_window(0,b_size
[1]);
179 /* allocate IRAM buffer for window tables too, if sufficient iram available */
180 /* give preference to the larger window over the smaller window
181 (on the assumption that both windows are equally likely used) */
183 iramposw
=(LOOKUP_TNC
*)iram_malloc(b_size
[i
]*sizeof(LOOKUP_TNC
));
185 memcpy(iramposw
, b
->window
[i
], b_size
[i
]*sizeof(LOOKUP_TNC
));
186 b
->window
[i
]=iramposw
;
190 /* finish the codebooks */
192 ci
->fullbooks
=(codebook
*)_ogg_calloc(ci
->books
,sizeof(*ci
->fullbooks
));
193 for(i
=0;i
<ci
->books
;i
++){
194 vorbis_book_init_decode(ci
->fullbooks
+i
,ci
->book_param
[i
]);
195 /* decode codebooks are now standalone after init */
196 vorbis_staticbook_destroy(ci
->book_param
[i
]);
197 ci
->book_param
[i
]=NULL
;
201 /* if we can get away with it, put a double buffer into IRAM too, so that
202 overlap-add runs iram-to-iram and we avoid needing to memcpy */
203 v
->pcm_storage
=ci
->blocksizes
[1];
212 if(NULL
!= (v
->iram_double_pcm
= iram_malloc(vi
->channels
*v
->pcm_storage
*sizeof(ogg_int32_t
))))
214 /* one-time initialisation at codec start or on switch from
215 blocksizes greater than IRAM_PCM_END to sizes that fit */
216 for(i
=0;i
<vi
->channels
;i
++)
217 v
->pcm
[i
]=&v
->iram_double_pcm
[i
*v
->pcm_storage
];
221 /* one-time initialisation at codec start or on switch from
222 blocksizes that fit in IRAM_PCM_END to those that don't */
223 for(i
=0;i
<vi
->channels
;i
++)
224 v
->pcm
[i
]=(ogg_int32_t
*)_ogg_calloc(v
->pcm_storage
,sizeof(*v
->pcm
[i
]));
227 /* all 1 (large block) or 0 (small block) */
228 /* explicitly set for the sake of clarity */
229 v
->lW
=0; /* previous window size */
230 v
->W
=0; /* current window size */
232 /* initialize all the mapping/backend lookups */
233 b
->mode
=(vorbis_look_mapping
**)_ogg_calloc(ci
->modes
,sizeof(*b
->mode
));
234 for(i
=0;i
<ci
->modes
;i
++){
235 int mapnum
=ci
->mode_param
[i
]->mapping
;
236 int maptype
=ci
->map_type
[mapnum
];
237 b
->mode
[i
]=_mapping_P
[maptype
]->look(v
,ci
->mode_param
[i
],
238 ci
->map_param
[mapnum
]);
243 int vorbis_synthesis_restart(vorbis_dsp_state
*v
){
244 vorbis_info
*vi
=v
->vi
;
245 codec_setup_info
*ci
;
248 if(!v
->backend_state
)return -1;
259 ((private_state
*)(v
->backend_state
))->sample_count
=-1;
261 /* indicate to synthesis code that buffer pointers no longer valid
262 (if we're using double pcm buffer) and will need to reset them */
263 v
->reset_pcmb
= true;
264 /* also reset our copy of the double buffer pointers if we have one */
265 if(v
->iram_double_pcm
)
266 for(i
=0;i
<vi
->channels
;i
++)
267 v
->pcm
[i
]=&v
->iram_double_pcm
[i
*v
->pcm_storage
];
272 int vorbis_synthesis_init(vorbis_dsp_state
*v
,vorbis_info
*vi
){
274 vorbis_synthesis_restart(v
);
279 void vorbis_dsp_clear(vorbis_dsp_state
*v
){
282 vorbis_info
*vi
=v
->vi
;
283 codec_setup_info
*ci
=(codec_setup_info
*)(vi
?vi
->codec_setup
:NULL
);
284 private_state
*b
=(private_state
*)v
->backend_state
;
286 if(NULL
== v
->iram_double_pcm
)
288 /* pcm buffer came from oggmalloc rather than iram */
289 for(i
=0;i
<vi
->channels
;i
++)
290 if(v
->pcm
[i
])_ogg_free(v
->pcm
[i
]);
293 /* free mode lookups; these are actually vorbis_look_mapping structs */
295 for(i
=0;i
<ci
->modes
;i
++){
296 int mapnum
=ci
->mode_param
[i
]->mapping
;
297 int maptype
=ci
->map_type
[mapnum
];
298 if(b
&& b
->mode
)_mapping_P
[maptype
]->free_look(b
->mode
[i
]);
303 if(b
->mode
)_ogg_free(b
->mode
);
307 memset(v
,0,sizeof(*v
));
311 /* Unlike in analysis, the window is only partially applied for each
312 block. The time domain envelope is not yet handled at the point of
313 calling (as it relies on the previous block). */
315 int vorbis_synthesis_blockin(vorbis_dsp_state
*v
,vorbis_block
*vb
)
317 int vorbis_synthesis_blockin(vorbis_dsp_state
*v
,vorbis_block
*vb
){
318 vorbis_info
*vi
=v
->vi
;
319 codec_setup_info
*ci
=(codec_setup_info
*)vi
->codec_setup
;
320 private_state
*b
=v
->backend_state
;
322 bool iram_pcm_doublebuffer
= (NULL
!= v
->iram_double_pcm
);
324 if(v
->pcm_current
>v
->pcm_returned
&& v
->pcm_returned
!=-1)return(OV_EINVAL
);
330 if((v
->sequence
==-1)||
331 (v
->sequence
+1 != vb
->sequence
)){
332 v
->granulepos
=-1; /* out of sequence; lose count */
336 v
->sequence
=vb
->sequence
;
337 int n
=ci
->blocksizes
[v
->W
]/2;
338 int ln
=ci
->blocksizes
[v
->lW
]/2;
340 if(LIKELY(vb
->pcm
)){ /* no pcm to process if vorbis_synthesis_trackonly
341 was called on block */
343 int n0
=ci
->blocksizes
[0]/2;
344 int n1
=ci
->blocksizes
[1]/2;
346 if(iram_pcm_doublebuffer
)
352 prevCenter
= v
->centerW
;
353 v
->centerW
= n1
- v
->centerW
;
356 /* overlap/add PCM */
357 /* nb nothing to overlap with on first block so don't bother */
358 if(LIKELY(v
->pcm_returned
!=-1))
360 for(j
=0;j
<vi
->channels
;j
++)
362 ogg_int32_t
*pcm
=v
->pcm
[j
]+prevCenter
;
363 ogg_int32_t
*p
=vb
->pcm
[j
];
365 /* the overlap/add section */
368 /* large/large or small/small */
369 vect_add_right_left(pcm
,p
,n
);
375 vect_add_right_left(pcm
+ (n1
-n0
)/2, p
, n0
);
382 vect_add_left_right(p
,pcm
,n0
);
388 /* the copy section */
389 if(iram_pcm_doublebuffer
)
391 /* just flip the pointers over as we have a double buffer in iram */
394 v
->pcm
[0]=vb
->pcm
[0];
397 v
->pcm
[1]=vb
->pcm
[1];
402 for(j
=0;j
<vi
->channels
;j
++)
404 /* at best only vb->pcm is in iram, and that's where we do the
405 synthesis, so we copy out the right-hand subframe of last
406 synthesis into (noniram) local buffer so we can still do
408 vect_copy(v
->pcm
[j
]+v
->centerW
, vb
->pcm
[j
]+n
, n
);
412 /* deal with initial packet state; we do this using the explicit
413 pcm_returned==-1 flag otherwise we're sensitive to first block
414 being short or long */
416 if(v
->pcm_returned
==-1){
421 v
->pcm_current
=(n
+ln
)/2;
426 /* track the frame number... This is for convenience, but also
427 making sure our last packet doesn't end with added padding. If
428 the last packet is partial, the number of samples we'll have to
429 return will be past the vb->granulepos.
431 This is not foolproof! It will be confused if we begin
432 decoding at the last page after a seek or hole. In that case,
433 we don't have a starting point to judge where the last frame
434 is. For this reason, vorbisfile will always try to make sure
435 it reads the last two marked pages in proper sequence */
437 if(b
->sample_count
==-1){
440 b
->sample_count
+=(n
+ln
)/2;
443 if(v
->granulepos
==-1){
444 if(vb
->granulepos
!=-1){ /* only set if we have a position to set to */
446 v
->granulepos
=vb
->granulepos
;
448 /* is this a short page? */
449 if(b
->sample_count
>v
->granulepos
){
450 /* corner case; if this is both the first and last audio page,
451 then spec says the end is cut, not beginning */
454 /* no preceeding granulepos; assume we started at zero (we'd
455 have to in a short single-page stream) */
456 /* granulepos could be -1 due to a seek, but that would result
457 in a long coun`t, not short count */
459 v
->pcm_current
-=(b
->sample_count
-v
->granulepos
);
461 /* trim the beginning */
462 v
->pcm_returned
+=(b
->sample_count
-v
->granulepos
);
463 if(v
->pcm_returned
>v
->pcm_current
)
464 v
->pcm_returned
=v
->pcm_current
;
471 v
->granulepos
+=(n
+ln
)/2;
472 if(vb
->granulepos
!=-1 && v
->granulepos
!=vb
->granulepos
){
474 if(v
->granulepos
>vb
->granulepos
){
475 long extra
=v
->granulepos
-vb
->granulepos
;
479 /* partial last frame. Strip the extra samples off */
480 v
->pcm_current
-=extra
;
481 } /* else {Shouldn't happen *unless* the bitstream is out of
482 spec. Either way, believe the bitstream } */
483 } /* else {Shouldn't happen *unless* the bitstream is out of
484 spec. Either way, believe the bitstream } */
485 v
->granulepos
=vb
->granulepos
;
489 /* Update, cleanup */
491 if(vb
->eofflag
)v
->eofflag
=1;
495 /* pcm==NULL indicates we just want the pending samples, no more */
496 int vorbis_synthesis_pcmout(vorbis_dsp_state
*v
,ogg_int32_t
***pcm
) ICODE_ATTR
;
497 int vorbis_synthesis_pcmout(vorbis_dsp_state
*v
,ogg_int32_t
***pcm
){
498 vorbis_info
*vi
=v
->vi
;
499 if(v
->pcm_returned
>-1 && v
->pcm_returned
<v
->pcm_current
){
502 for(i
=0;i
<vi
->channels
;i
++)
503 v
->pcmret
[i
]=v
->pcmb
[i
]+v
->pcm_returned
;
506 return(v
->pcm_current
-v
->pcm_returned
);
511 int vorbis_synthesis_read(vorbis_dsp_state
*v
,int bytes
){
512 if(bytes
&& v
->pcm_returned
+bytes
>v
->pcm_current
)return(OV_EINVAL
);
513 v
->pcm_returned
+=bytes
;