123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298 |
- /********************************************************************
- * *
- * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
- * *
- * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
- * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
- * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
- * *
- * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2003 *
- * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
- * *
- ********************************************************************
- function: PCM data vector blocking, windowing and dis/reassembly
- ********************************************************************/
- #include <stdlib.h>
- #include "ogg.h"
- #include "mdct.h"
- #include "ivorbiscodec.h"
- #include "codec_internal.h"
- #include "misc.h"
- #include "window_lookup.h"
- int vorbis_dsp_restart(vorbis_dsp_state *v){
- if(!v)return -1;
- {
- vorbis_info *vi=v->vi;
- codec_setup_info *ci;
-
- if(!vi)return -1;
- ci=vi->codec_setup;
- if(!ci)return -1;
-
- v->out_end=-1;
- v->out_begin=-1;
- v->granulepos=-1;
- v->sequence=-1;
- v->sample_count=-1;
- }
- return 0;
- }
- vorbis_dsp_state *vorbis_dsp_create(vorbis_info *vi){
- int i;
- vorbis_dsp_state *v=_ogg_calloc(1,sizeof(*v));
- codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
- v->vi=vi;
-
- v->work=(ogg_int32_t **)_ogg_malloc(vi->channels*sizeof(*v->work));
- v->mdctright=(ogg_int32_t **)_ogg_malloc(vi->channels*sizeof(*v->mdctright));
- for(i=0;i<vi->channels;i++){
- v->work[i]=(ogg_int32_t *)_ogg_calloc(1,(ci->blocksizes[1]>>1)*
- sizeof(*v->work[i]));
- v->mdctright[i]=(ogg_int32_t *)_ogg_calloc(1,(ci->blocksizes[1]>>2)*
- sizeof(*v->mdctright[i]));
- }
- v->lW=0; /* previous window size */
- v->W=0; /* current window size */
- vorbis_dsp_restart(v);
- return v;
- }
- void vorbis_dsp_destroy(vorbis_dsp_state *v){
- int i;
- if(v){
- vorbis_info *vi=v->vi;
- if(v->work){
- for(i=0;i<vi->channels;i++)
- if(v->work[i])_ogg_free(v->work[i]);
- _ogg_free(v->work);
- }
- if(v->mdctright){
- for(i=0;i<vi->channels;i++)
- if(v->mdctright[i])_ogg_free(v->mdctright[i]);
- _ogg_free(v->mdctright);
- }
- _ogg_free(v);
- }
- }
- static LOOKUP_T *_vorbis_window(int left){
- switch(left){
- case 32:
- return vwin64;
- case 64:
- return vwin128;
- case 128:
- return vwin256;
- case 256:
- return vwin512;
- case 512:
- return vwin1024;
- case 1024:
- return vwin2048;
- case 2048:
- return vwin4096;
- #ifndef LIMIT_TO_64kHz
- case 4096:
- return vwin8192;
- #endif
- default:
- return(0);
- }
- }
- /* pcm==0 indicates we just want the pending samples, no more */
- int vorbis_dsp_pcmout(vorbis_dsp_state *v,ogg_int16_t *pcm,int samples){
- vorbis_info *vi=v->vi;
- codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
- if(v->out_begin>-1 && v->out_begin<v->out_end){
- int n=v->out_end-v->out_begin;
- if(pcm){
- int i;
- if(n>samples)n=samples;
- for(i=0;i<vi->channels;i++)
- mdct_unroll_lap(ci->blocksizes[0],ci->blocksizes[1],
- v->lW,v->W,v->work[i],v->mdctright[i],
- _vorbis_window(ci->blocksizes[0]>>1),
- _vorbis_window(ci->blocksizes[1]>>1),
- pcm+i,vi->channels,
- v->out_begin,v->out_begin+n);
- }
- return(n);
- }
- return(0);
- }
- int vorbis_dsp_read(vorbis_dsp_state *v,int s){
- if(s && v->out_begin+s>v->out_end)return(OV_EINVAL);
- v->out_begin+=s;
- return(0);
- }
- long vorbis_packet_blocksize(vorbis_info *vi,ogg_packet *op){
- codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
- oggpack_buffer opb;
- int mode;
- int modebits=0;
- int v=ci->modes;
-
- oggpack_readinit(&opb,op->packet);
- /* Check the packet type */
- if(oggpack_read(&opb,1)!=0){
- /* Oops. This is not an audio data packet */
- return(OV_ENOTAUDIO);
- }
- while(v>1){
- modebits++;
- v>>=1;
- }
- /* read our mode and pre/post windowsize */
- mode=oggpack_read(&opb,modebits);
- if(mode==-1)return(OV_EBADPACKET);
- return(ci->blocksizes[ci->mode_param[mode].blockflag]);
- }
- static int ilog(ogg_uint32_t v){
- int ret=0;
- if(v)--v;
- while(v){
- ret++;
- v>>=1;
- }
- return(ret);
- }
- int vorbis_dsp_synthesis(vorbis_dsp_state *vd,ogg_packet *op,int decodep){
- vorbis_info *vi=vd->vi;
- codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
- int mode,i;
- oggpack_readinit(&vd->opb,op->packet);
- /* Check the packet type */
- if(oggpack_read(&vd->opb,1)!=0){
- /* Oops. This is not an audio data packet */
- return OV_ENOTAUDIO ;
- }
- /* read our mode and pre/post windowsize */
- mode=oggpack_read(&vd->opb,ilog(ci->modes));
- if(mode==-1 || mode>=ci->modes) return OV_EBADPACKET;
- /* shift information we still need from last window */
- vd->lW=vd->W;
- vd->W=ci->mode_param[mode].blockflag;
- for(i=0;i<vi->channels;i++)
- mdct_shift_right(ci->blocksizes[vd->lW],vd->work[i],vd->mdctright[i]);
-
- if(vd->W){
- int temp;
- oggpack_read(&vd->opb,1);
- temp=oggpack_read(&vd->opb,1);
- if(temp==-1) return OV_EBADPACKET;
- }
-
- /* packet decode and portions of synthesis that rely on only this block */
- if(decodep){
- mapping_inverse(vd,ci->map_param+ci->mode_param[mode].mapping);
- if(vd->out_begin==-1){
- vd->out_begin=0;
- vd->out_end=0;
- }else{
- vd->out_begin=0;
- vd->out_end=ci->blocksizes[vd->lW]/4+ci->blocksizes[vd->W]/4;
- }
- }
- /* track the frame number... This is for convenience, but also
- making sure our last packet doesn't end with added padding.
-
- This is not foolproof! It will be confused if we begin
- decoding at the last page after a seek or hole. In that case,
- we don't have a starting point to judge where the last frame
- is. For this reason, vorbisfile will always try to make sure
- it reads the last two marked pages in proper sequence */
-
- /* if we're out of sequence, dump granpos tracking until we sync back up */
- if(vd->sequence==-1 || vd->sequence+1 != op->packetno-3){
- /* out of sequence; lose count */
- vd->granulepos=-1;
- vd->sample_count=-1;
- }
-
- vd->sequence=op->packetno;
- vd->sequence=vd->sequence-3;
-
- if(vd->sample_count==-1){
- vd->sample_count=0;
- }else{
- vd->sample_count+=
- ci->blocksizes[vd->lW]/4+ci->blocksizes[vd->W]/4;
- }
-
- if(vd->granulepos==-1){
- if(op->granulepos!=-1){ /* only set if we have a
- position to set to */
-
- vd->granulepos=op->granulepos;
-
- /* is this a short page? */
- if(vd->sample_count>vd->granulepos){
- /* corner case; if this is both the first and last audio page,
- then spec says the end is cut, not beginning */
- if(op->e_o_s){
- /* trim the end */
- /* no preceeding granulepos; assume we started at zero (we'd
- have to in a short single-page stream) */
- /* granulepos could be -1 due to a seek, but that would result
- in a long coun t, not short count */
-
- vd->out_end-=vd->sample_count-vd->granulepos;
- }else{
- /* trim the beginning */
- vd->out_begin+=vd->sample_count-vd->granulepos;
- if(vd->out_begin>vd->out_end)
- vd->out_begin=vd->out_end;
- }
-
- }
-
- }
- }else{
- vd->granulepos+=
- ci->blocksizes[vd->lW]/4+ci->blocksizes[vd->W]/4;
- if(op->granulepos!=-1 && vd->granulepos!=op->granulepos){
-
- if(vd->granulepos>op->granulepos){
- long extra=vd->granulepos-op->granulepos;
-
- if(extra)
- if(op->e_o_s){
- /* partial last frame. Strip the extra samples off */
- vd->out_end-=extra;
- } /* else {Shouldn't happen *unless* the bitstream is out of
- spec. Either way, believe the bitstream } */
- } /* else {Shouldn't happen *unless* the bitstream is out of
- spec. Either way, believe the bitstream } */
- vd->granulepos=op->granulepos;
- }
- }
- return(0);
- }
|