123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047 |
- /********************************************************************
- * *
- * THIS FILE IS PART OF THE OggVorbis SOFTWARE 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 SOURCE CODE IS (C) COPYRIGHT 1994-2015 *
- * by the Xiph.Org Foundation https://xiph.org/ *
- * *
- ********************************************************************
- function: PCM data vector blocking, windowing and dis/reassembly
- Handle windowing, overlap-add, etc of the PCM vectors. This is made
- more amusing by Vorbis' current two allowed block sizes.
- ********************************************************************/
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <ogg/ogg.h>
- #include "vorbis/codec.h"
- #include "codec_internal.h"
- #include "window.h"
- #include "mdct.h"
- #include "lpc.h"
- #include "registry.h"
- #include "misc.h"
- /* pcm accumulator examples (not exhaustive):
- <-------------- lW ---------------->
- <--------------- W ---------------->
- : .....|..... _______________ |
- : .''' | '''_--- | |\ |
- :.....''' |_____--- '''......| | \_______|
- :.................|__________________|_______|__|______|
- |<------ Sl ------>| > Sr < |endW
- |beginSl |endSl | |endSr
- |beginW |endlW |beginSr
- |< lW >|
- <--------------- W ---------------->
- | | .. ______________ |
- | | ' `/ | ---_ |
- |___.'___/`. | ---_____|
- |_______|__|_______|_________________|
- | >|Sl|< |<------ Sr ----->|endW
- | | |endSl |beginSr |endSr
- |beginW | |endlW
- mult[0] |beginSl mult[n]
- <-------------- lW ----------------->
- |<--W-->|
- : .............. ___ | |
- : .''' |`/ \ | |
- :.....''' |/`....\|...|
- :.........................|___|___|___|
- |Sl |Sr |endW
- | | |endSr
- | |beginSr
- | |endSl
- |beginSl
- |beginW
- */
- /* block abstraction setup *********************************************/
- #ifndef WORD_ALIGN
- #define WORD_ALIGN 8
- #endif
- int vorbis_block_init(vorbis_dsp_state *v, vorbis_block *vb){
- int i;
- memset(vb,0,sizeof(*vb));
- vb->vd=v;
- vb->localalloc=0;
- vb->localstore=NULL;
- if(v->analysisp){
- vorbis_block_internal *vbi=
- vb->internal=_ogg_calloc(1,sizeof(vorbis_block_internal));
- vbi->ampmax=-9999;
- for(i=0;i<PACKETBLOBS;i++){
- if(i==PACKETBLOBS/2){
- vbi->packetblob[i]=&vb->opb;
- }else{
- vbi->packetblob[i]=
- _ogg_calloc(1,sizeof(oggpack_buffer));
- }
- oggpack_writeinit(vbi->packetblob[i]);
- }
- }
- return(0);
- }
- void *_vorbis_block_alloc(vorbis_block *vb,long bytes){
- bytes=(bytes+(WORD_ALIGN-1)) & ~(WORD_ALIGN-1);
- if(bytes+vb->localtop>vb->localalloc){
- /* can't just _ogg_realloc... there are outstanding pointers */
- if(vb->localstore){
- struct alloc_chain *link=_ogg_malloc(sizeof(*link));
- vb->totaluse+=vb->localtop;
- link->next=vb->reap;
- link->ptr=vb->localstore;
- vb->reap=link;
- }
- /* highly conservative */
- vb->localalloc=bytes;
- vb->localstore=_ogg_malloc(vb->localalloc);
- vb->localtop=0;
- }
- {
- void *ret=(void *)(((char *)vb->localstore)+vb->localtop);
- vb->localtop+=bytes;
- return ret;
- }
- }
- /* reap the chain, pull the ripcord */
- void _vorbis_block_ripcord(vorbis_block *vb){
- /* reap the chain */
- struct alloc_chain *reap=vb->reap;
- while(reap){
- struct alloc_chain *next=reap->next;
- _ogg_free(reap->ptr);
- memset(reap,0,sizeof(*reap));
- _ogg_free(reap);
- reap=next;
- }
- /* consolidate storage */
- if(vb->totaluse){
- vb->localstore=_ogg_realloc(vb->localstore,vb->totaluse+vb->localalloc);
- vb->localalloc+=vb->totaluse;
- vb->totaluse=0;
- }
- /* pull the ripcord */
- vb->localtop=0;
- vb->reap=NULL;
- }
- int vorbis_block_clear(vorbis_block *vb){
- int i;
- vorbis_block_internal *vbi=vb->internal;
- _vorbis_block_ripcord(vb);
- if(vb->localstore)_ogg_free(vb->localstore);
- if(vbi){
- for(i=0;i<PACKETBLOBS;i++){
- oggpack_writeclear(vbi->packetblob[i]);
- if(i!=PACKETBLOBS/2)_ogg_free(vbi->packetblob[i]);
- }
- _ogg_free(vbi);
- }
- memset(vb,0,sizeof(*vb));
- return(0);
- }
- /* Analysis side code, but directly related to blocking. Thus it's
- here and not in analysis.c (which is for analysis transforms only).
- The init is here because some of it is shared */
- static int _vds_shared_init(vorbis_dsp_state *v,vorbis_info *vi,int encp){
- int i;
- codec_setup_info *ci=vi->codec_setup;
- private_state *b=NULL;
- int hs;
- if(ci==NULL||
- ci->modes<=0||
- ci->blocksizes[0]<64||
- ci->blocksizes[1]<ci->blocksizes[0]){
- return 1;
- }
- hs=ci->halfrate_flag;
- memset(v,0,sizeof(*v));
- b=v->backend_state=_ogg_calloc(1,sizeof(*b));
- v->vi=vi;
- b->modebits=ov_ilog(ci->modes-1);
- b->transform[0]=_ogg_calloc(VI_TRANSFORMB,sizeof(*b->transform[0]));
- b->transform[1]=_ogg_calloc(VI_TRANSFORMB,sizeof(*b->transform[1]));
- /* MDCT is tranform 0 */
- b->transform[0][0]=_ogg_calloc(1,sizeof(mdct_lookup));
- b->transform[1][0]=_ogg_calloc(1,sizeof(mdct_lookup));
- mdct_init(b->transform[0][0],ci->blocksizes[0]>>hs);
- mdct_init(b->transform[1][0],ci->blocksizes[1]>>hs);
- /* Vorbis I uses only window type 0 */
- /* note that the correct computation below is technically:
- b->window[0]=ov_ilog(ci->blocksizes[0]-1)-6;
- b->window[1]=ov_ilog(ci->blocksizes[1]-1)-6;
- but since blocksizes are always powers of two,
- the below is equivalent.
- */
- b->window[0]=ov_ilog(ci->blocksizes[0])-7;
- b->window[1]=ov_ilog(ci->blocksizes[1])-7;
- if(encp){ /* encode/decode differ here */
- /* analysis always needs an fft */
- drft_init(&b->fft_look[0],ci->blocksizes[0]);
- drft_init(&b->fft_look[1],ci->blocksizes[1]);
- /* finish the codebooks */
- if(!ci->fullbooks){
- ci->fullbooks=_ogg_calloc(ci->books,sizeof(*ci->fullbooks));
- for(i=0;i<ci->books;i++)
- vorbis_book_init_encode(ci->fullbooks+i,ci->book_param[i]);
- }
- b->psy=_ogg_calloc(ci->psys,sizeof(*b->psy));
- for(i=0;i<ci->psys;i++){
- _vp_psy_init(b->psy+i,
- ci->psy_param[i],
- &ci->psy_g_param,
- ci->blocksizes[ci->psy_param[i]->blockflag]/2,
- vi->rate);
- }
- v->analysisp=1;
- }else{
- /* finish the codebooks */
- if(!ci->fullbooks){
- ci->fullbooks=_ogg_calloc(ci->books,sizeof(*ci->fullbooks));
- for(i=0;i<ci->books;i++){
- if(ci->book_param[i]==NULL)
- goto abort_books;
- if(vorbis_book_init_decode(ci->fullbooks+i,ci->book_param[i]))
- goto abort_books;
- /* decode codebooks are now standalone after init */
- vorbis_staticbook_destroy(ci->book_param[i]);
- ci->book_param[i]=NULL;
- }
- }
- }
- /* initialize the storage vectors. blocksize[1] is small for encode,
- but the correct size for decode */
- v->pcm_storage=ci->blocksizes[1];
- v->pcm=_ogg_malloc(vi->channels*sizeof(*v->pcm));
- v->pcmret=_ogg_malloc(vi->channels*sizeof(*v->pcmret));
- {
- int i;
- for(i=0;i<vi->channels;i++)
- v->pcm[i]=_ogg_calloc(v->pcm_storage,sizeof(*v->pcm[i]));
- }
- /* all 1 (large block) or 0 (small block) */
- /* explicitly set for the sake of clarity */
- v->lW=0; /* previous window size */
- v->W=0; /* current window size */
- /* all vector indexes */
- v->centerW=ci->blocksizes[1]/2;
- v->pcm_current=v->centerW;
- /* initialize all the backend lookups */
- b->flr=_ogg_calloc(ci->floors,sizeof(*b->flr));
- b->residue=_ogg_calloc(ci->residues,sizeof(*b->residue));
- for(i=0;i<ci->floors;i++)
- b->flr[i]=_floor_P[ci->floor_type[i]]->
- look(v,ci->floor_param[i]);
- for(i=0;i<ci->residues;i++)
- b->residue[i]=_residue_P[ci->residue_type[i]]->
- look(v,ci->residue_param[i]);
- return 0;
- abort_books:
- for(i=0;i<ci->books;i++){
- if(ci->book_param[i]!=NULL){
- vorbis_staticbook_destroy(ci->book_param[i]);
- ci->book_param[i]=NULL;
- }
- }
- vorbis_dsp_clear(v);
- return -1;
- }
- /* arbitrary settings and spec-mandated numbers get filled in here */
- int vorbis_analysis_init(vorbis_dsp_state *v,vorbis_info *vi){
- private_state *b=NULL;
- if(_vds_shared_init(v,vi,1))return 1;
- b=v->backend_state;
- b->psy_g_look=_vp_global_look(vi);
- /* Initialize the envelope state storage */
- b->ve=_ogg_calloc(1,sizeof(*b->ve));
- _ve_envelope_init(b->ve,vi);
- vorbis_bitrate_init(vi,&b->bms);
- /* compressed audio packets start after the headers
- with sequence number 3 */
- v->sequence=3;
- return(0);
- }
- void vorbis_dsp_clear(vorbis_dsp_state *v){
- int i;
- if(v){
- vorbis_info *vi=v->vi;
- codec_setup_info *ci=(vi?vi->codec_setup:NULL);
- private_state *b=v->backend_state;
- if(b){
- if(b->ve){
- _ve_envelope_clear(b->ve);
- _ogg_free(b->ve);
- }
- if(b->transform[0]){
- mdct_clear(b->transform[0][0]);
- _ogg_free(b->transform[0][0]);
- _ogg_free(b->transform[0]);
- }
- if(b->transform[1]){
- mdct_clear(b->transform[1][0]);
- _ogg_free(b->transform[1][0]);
- _ogg_free(b->transform[1]);
- }
- if(b->flr){
- if(ci)
- for(i=0;i<ci->floors;i++)
- _floor_P[ci->floor_type[i]]->
- free_look(b->flr[i]);
- _ogg_free(b->flr);
- }
- if(b->residue){
- if(ci)
- for(i=0;i<ci->residues;i++)
- _residue_P[ci->residue_type[i]]->
- free_look(b->residue[i]);
- _ogg_free(b->residue);
- }
- if(b->psy){
- if(ci)
- for(i=0;i<ci->psys;i++)
- _vp_psy_clear(b->psy+i);
- _ogg_free(b->psy);
- }
- if(b->psy_g_look)_vp_global_free(b->psy_g_look);
- vorbis_bitrate_clear(&b->bms);
- drft_clear(&b->fft_look[0]);
- drft_clear(&b->fft_look[1]);
- }
- if(v->pcm){
- if(vi)
- for(i=0;i<vi->channels;i++)
- if(v->pcm[i])_ogg_free(v->pcm[i]);
- _ogg_free(v->pcm);
- if(v->pcmret)_ogg_free(v->pcmret);
- }
- if(b){
- /* free header, header1, header2 */
- if(b->header)_ogg_free(b->header);
- if(b->header1)_ogg_free(b->header1);
- if(b->header2)_ogg_free(b->header2);
- _ogg_free(b);
- }
- memset(v,0,sizeof(*v));
- }
- }
- float **vorbis_analysis_buffer(vorbis_dsp_state *v, int vals){
- int i;
- vorbis_info *vi=v->vi;
- private_state *b=v->backend_state;
- /* free header, header1, header2 */
- if(b->header)_ogg_free(b->header);b->header=NULL;
- if(b->header1)_ogg_free(b->header1);b->header1=NULL;
- if(b->header2)_ogg_free(b->header2);b->header2=NULL;
- /* Do we have enough storage space for the requested buffer? If not,
- expand the PCM (and envelope) storage */
- if(v->pcm_current+vals>=v->pcm_storage){
- v->pcm_storage=v->pcm_current+vals*2;
- for(i=0;i<vi->channels;i++){
- v->pcm[i]=_ogg_realloc(v->pcm[i],v->pcm_storage*sizeof(*v->pcm[i]));
- }
- }
- for(i=0;i<vi->channels;i++)
- v->pcmret[i]=v->pcm[i]+v->pcm_current;
- return(v->pcmret);
- }
- static void _preextrapolate_helper(vorbis_dsp_state *v){
- int i;
- int order=16;
- float *lpc=alloca(order*sizeof(*lpc));
- float *work=alloca(v->pcm_current*sizeof(*work));
- long j;
- v->preextrapolate=1;
- if(v->pcm_current-v->centerW>order*2){ /* safety */
- for(i=0;i<v->vi->channels;i++){
- /* need to run the extrapolation in reverse! */
- for(j=0;j<v->pcm_current;j++)
- work[j]=v->pcm[i][v->pcm_current-j-1];
- /* prime as above */
- vorbis_lpc_from_data(work,lpc,v->pcm_current-v->centerW,order);
- #if 0
- if(v->vi->channels==2){
- if(i==0)
- _analysis_output("predataL",0,work,v->pcm_current-v->centerW,0,0,0);
- else
- _analysis_output("predataR",0,work,v->pcm_current-v->centerW,0,0,0);
- }else{
- _analysis_output("predata",0,work,v->pcm_current-v->centerW,0,0,0);
- }
- #endif
- /* run the predictor filter */
- vorbis_lpc_predict(lpc,work+v->pcm_current-v->centerW-order,
- order,
- work+v->pcm_current-v->centerW,
- v->centerW);
- for(j=0;j<v->pcm_current;j++)
- v->pcm[i][v->pcm_current-j-1]=work[j];
- }
- }
- }
- /* call with val<=0 to set eof */
- int vorbis_analysis_wrote(vorbis_dsp_state *v, int vals){
- vorbis_info *vi=v->vi;
- codec_setup_info *ci=vi->codec_setup;
- if(vals<=0){
- int order=32;
- int i;
- float *lpc=alloca(order*sizeof(*lpc));
- /* if it wasn't done earlier (very short sample) */
- if(!v->preextrapolate)
- _preextrapolate_helper(v);
- /* We're encoding the end of the stream. Just make sure we have
- [at least] a few full blocks of zeroes at the end. */
- /* actually, we don't want zeroes; that could drop a large
- amplitude off a cliff, creating spread spectrum noise that will
- suck to encode. Extrapolate for the sake of cleanliness. */
- vorbis_analysis_buffer(v,ci->blocksizes[1]*3);
- v->eofflag=v->pcm_current;
- v->pcm_current+=ci->blocksizes[1]*3;
- for(i=0;i<vi->channels;i++){
- if(v->eofflag>order*2){
- /* extrapolate with LPC to fill in */
- long n;
- /* make a predictor filter */
- n=v->eofflag;
- if(n>ci->blocksizes[1])n=ci->blocksizes[1];
- vorbis_lpc_from_data(v->pcm[i]+v->eofflag-n,lpc,n,order);
- /* run the predictor filter */
- vorbis_lpc_predict(lpc,v->pcm[i]+v->eofflag-order,order,
- v->pcm[i]+v->eofflag,v->pcm_current-v->eofflag);
- }else{
- /* not enough data to extrapolate (unlikely to happen due to
- guarding the overlap, but bulletproof in case that
- assumtion goes away). zeroes will do. */
- memset(v->pcm[i]+v->eofflag,0,
- (v->pcm_current-v->eofflag)*sizeof(*v->pcm[i]));
- }
- }
- }else{
- if(v->pcm_current+vals>v->pcm_storage)
- return(OV_EINVAL);
- v->pcm_current+=vals;
- /* we may want to reverse extrapolate the beginning of a stream
- too... in case we're beginning on a cliff! */
- /* clumsy, but simple. It only runs once, so simple is good. */
- if(!v->preextrapolate && v->pcm_current-v->centerW>ci->blocksizes[1])
- _preextrapolate_helper(v);
- }
- return(0);
- }
- /* do the deltas, envelope shaping, pre-echo and determine the size of
- the next block on which to continue analysis */
- int vorbis_analysis_blockout(vorbis_dsp_state *v,vorbis_block *vb){
- int i;
- vorbis_info *vi=v->vi;
- codec_setup_info *ci=vi->codec_setup;
- private_state *b=v->backend_state;
- vorbis_look_psy_global *g=b->psy_g_look;
- long beginW=v->centerW-ci->blocksizes[v->W]/2,centerNext;
- vorbis_block_internal *vbi=(vorbis_block_internal *)vb->internal;
- /* check to see if we're started... */
- if(!v->preextrapolate)return(0);
- /* check to see if we're done... */
- if(v->eofflag==-1)return(0);
- /* By our invariant, we have lW, W and centerW set. Search for
- the next boundary so we can determine nW (the next window size)
- which lets us compute the shape of the current block's window */
- /* we do an envelope search even on a single blocksize; we may still
- be throwing more bits at impulses, and envelope search handles
- marking impulses too. */
- {
- long bp=_ve_envelope_search(v);
- if(bp==-1){
- if(v->eofflag==0)return(0); /* not enough data currently to search for a
- full long block */
- v->nW=0;
- }else{
- if(ci->blocksizes[0]==ci->blocksizes[1])
- v->nW=0;
- else
- v->nW=bp;
- }
- }
- centerNext=v->centerW+ci->blocksizes[v->W]/4+ci->blocksizes[v->nW]/4;
- {
- /* center of next block + next block maximum right side. */
- long blockbound=centerNext+ci->blocksizes[v->nW]/2;
- if(v->pcm_current<blockbound)return(0); /* not enough data yet;
- although this check is
- less strict that the
- _ve_envelope_search,
- the search is not run
- if we only use one
- block size */
- }
- /* fill in the block. Note that for a short window, lW and nW are *short*
- regardless of actual settings in the stream */
- _vorbis_block_ripcord(vb);
- vb->lW=v->lW;
- vb->W=v->W;
- vb->nW=v->nW;
- if(v->W){
- if(!v->lW || !v->nW){
- vbi->blocktype=BLOCKTYPE_TRANSITION;
- /*fprintf(stderr,"-");*/
- }else{
- vbi->blocktype=BLOCKTYPE_LONG;
- /*fprintf(stderr,"_");*/
- }
- }else{
- if(_ve_envelope_mark(v)){
- vbi->blocktype=BLOCKTYPE_IMPULSE;
- /*fprintf(stderr,"|");*/
- }else{
- vbi->blocktype=BLOCKTYPE_PADDING;
- /*fprintf(stderr,".");*/
- }
- }
- vb->vd=v;
- vb->sequence=v->sequence++;
- vb->granulepos=v->granulepos;
- vb->pcmend=ci->blocksizes[v->W];
- /* copy the vectors; this uses the local storage in vb */
- /* this tracks 'strongest peak' for later psychoacoustics */
- /* moved to the global psy state; clean this mess up */
- if(vbi->ampmax>g->ampmax)g->ampmax=vbi->ampmax;
- g->ampmax=_vp_ampmax_decay(g->ampmax,v);
- vbi->ampmax=g->ampmax;
- vb->pcm=_vorbis_block_alloc(vb,sizeof(*vb->pcm)*vi->channels);
- vbi->pcmdelay=_vorbis_block_alloc(vb,sizeof(*vbi->pcmdelay)*vi->channels);
- for(i=0;i<vi->channels;i++){
- vbi->pcmdelay[i]=
- _vorbis_block_alloc(vb,(vb->pcmend+beginW)*sizeof(*vbi->pcmdelay[i]));
- memcpy(vbi->pcmdelay[i],v->pcm[i],(vb->pcmend+beginW)*sizeof(*vbi->pcmdelay[i]));
- vb->pcm[i]=vbi->pcmdelay[i]+beginW;
- /* before we added the delay
- vb->pcm[i]=_vorbis_block_alloc(vb,vb->pcmend*sizeof(*vb->pcm[i]));
- memcpy(vb->pcm[i],v->pcm[i]+beginW,ci->blocksizes[v->W]*sizeof(*vb->pcm[i]));
- */
- }
- /* handle eof detection: eof==0 means that we've not yet received EOF
- eof>0 marks the last 'real' sample in pcm[]
- eof<0 'no more to do'; doesn't get here */
- if(v->eofflag){
- if(v->centerW>=v->eofflag){
- v->eofflag=-1;
- vb->eofflag=1;
- return(1);
- }
- }
- /* advance storage vectors and clean up */
- {
- int new_centerNext=ci->blocksizes[1]/2;
- int movementW=centerNext-new_centerNext;
- if(movementW>0){
- _ve_envelope_shift(b->ve,movementW);
- v->pcm_current-=movementW;
- for(i=0;i<vi->channels;i++)
- memmove(v->pcm[i],v->pcm[i]+movementW,
- v->pcm_current*sizeof(*v->pcm[i]));
- v->lW=v->W;
- v->W=v->nW;
- v->centerW=new_centerNext;
- if(v->eofflag){
- v->eofflag-=movementW;
- if(v->eofflag<=0)v->eofflag=-1;
- /* do not add padding to end of stream! */
- if(v->centerW>=v->eofflag){
- v->granulepos+=movementW-(v->centerW-v->eofflag);
- }else{
- v->granulepos+=movementW;
- }
- }else{
- v->granulepos+=movementW;
- }
- }
- }
- /* done */
- return(1);
- }
- int vorbis_synthesis_restart(vorbis_dsp_state *v){
- vorbis_info *vi=v->vi;
- codec_setup_info *ci;
- int hs;
- if(!v->backend_state)return -1;
- if(!vi)return -1;
- ci=vi->codec_setup;
- if(!ci)return -1;
- hs=ci->halfrate_flag;
- v->centerW=ci->blocksizes[1]>>(hs+1);
- v->pcm_current=v->centerW>>hs;
- v->pcm_returned=-1;
- v->granulepos=-1;
- v->sequence=-1;
- v->eofflag=0;
- ((private_state *)(v->backend_state))->sample_count=-1;
- return(0);
- }
- int vorbis_synthesis_init(vorbis_dsp_state *v,vorbis_info *vi){
- if(_vds_shared_init(v,vi,0)){
- vorbis_dsp_clear(v);
- return 1;
- }
- vorbis_synthesis_restart(v);
- return 0;
- }
- /* Unlike in analysis, the window is only partially applied for each
- block. The time domain envelope is not yet handled at the point of
- calling (as it relies on the previous block). */
- int vorbis_synthesis_blockin(vorbis_dsp_state *v,vorbis_block *vb){
- vorbis_info *vi=v->vi;
- codec_setup_info *ci=vi->codec_setup;
- private_state *b=v->backend_state;
- int hs=ci->halfrate_flag;
- int i,j;
- if(!vb)return(OV_EINVAL);
- if(v->pcm_current>v->pcm_returned && v->pcm_returned!=-1)return(OV_EINVAL);
- v->lW=v->W;
- v->W=vb->W;
- v->nW=-1;
- if((v->sequence==-1)||
- (v->sequence+1 != vb->sequence)){
- v->granulepos=-1; /* out of sequence; lose count */
- b->sample_count=-1;
- }
- v->sequence=vb->sequence;
- if(vb->pcm){ /* no pcm to process if vorbis_synthesis_trackonly
- was called on block */
- int n=ci->blocksizes[v->W]>>(hs+1);
- int n0=ci->blocksizes[0]>>(hs+1);
- int n1=ci->blocksizes[1]>>(hs+1);
- int thisCenter;
- int prevCenter;
- v->glue_bits+=vb->glue_bits;
- v->time_bits+=vb->time_bits;
- v->floor_bits+=vb->floor_bits;
- v->res_bits+=vb->res_bits;
- if(v->centerW){
- thisCenter=n1;
- prevCenter=0;
- }else{
- thisCenter=0;
- prevCenter=n1;
- }
- /* v->pcm is now used like a two-stage double buffer. We don't want
- to have to constantly shift *or* adjust memory usage. Don't
- accept a new block until the old is shifted out */
- for(j=0;j<vi->channels;j++){
- /* the overlap/add section */
- if(v->lW){
- if(v->W){
- /* large/large */
- const float *w=_vorbis_window_get(b->window[1]-hs);
- float *pcm=v->pcm[j]+prevCenter;
- float *p=vb->pcm[j];
- for(i=0;i<n1;i++)
- pcm[i]=pcm[i]*w[n1-i-1] + p[i]*w[i];
- }else{
- /* large/small */
- const float *w=_vorbis_window_get(b->window[0]-hs);
- float *pcm=v->pcm[j]+prevCenter+n1/2-n0/2;
- float *p=vb->pcm[j];
- for(i=0;i<n0;i++)
- pcm[i]=pcm[i]*w[n0-i-1] +p[i]*w[i];
- }
- }else{
- if(v->W){
- /* small/large */
- const float *w=_vorbis_window_get(b->window[0]-hs);
- float *pcm=v->pcm[j]+prevCenter;
- float *p=vb->pcm[j]+n1/2-n0/2;
- for(i=0;i<n0;i++)
- pcm[i]=pcm[i]*w[n0-i-1] +p[i]*w[i];
- for(;i<n1/2+n0/2;i++)
- pcm[i]=p[i];
- }else{
- /* small/small */
- const float *w=_vorbis_window_get(b->window[0]-hs);
- float *pcm=v->pcm[j]+prevCenter;
- float *p=vb->pcm[j];
- for(i=0;i<n0;i++)
- pcm[i]=pcm[i]*w[n0-i-1] +p[i]*w[i];
- }
- }
- /* the copy section */
- {
- float *pcm=v->pcm[j]+thisCenter;
- float *p=vb->pcm[j]+n;
- for(i=0;i<n;i++)
- pcm[i]=p[i];
- }
- }
- if(v->centerW)
- v->centerW=0;
- else
- v->centerW=n1;
- /* deal with initial packet state; we do this using the explicit
- pcm_returned==-1 flag otherwise we're sensitive to first block
- being short or long */
- if(v->pcm_returned==-1){
- v->pcm_returned=thisCenter;
- v->pcm_current=thisCenter;
- }else{
- v->pcm_returned=prevCenter;
- v->pcm_current=prevCenter+
- ((ci->blocksizes[v->lW]/4+
- ci->blocksizes[v->W]/4)>>hs);
- }
- }
- /* track the frame number... This is for convenience, but also
- making sure our last packet doesn't end with added padding. If
- the last packet is partial, the number of samples we'll have to
- return will be past the vb->granulepos.
- 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(b->sample_count==-1){
- b->sample_count=0;
- }else{
- b->sample_count+=ci->blocksizes[v->lW]/4+ci->blocksizes[v->W]/4;
- }
- if(v->granulepos==-1){
- if(vb->granulepos!=-1){ /* only set if we have a position to set to */
- v->granulepos=vb->granulepos;
- /* is this a short page? */
- if(b->sample_count>v->granulepos){
- /* corner case; if this is both the first and last audio page,
- then spec says the end is cut, not beginning */
- long extra=b->sample_count-vb->granulepos;
- /* we use ogg_int64_t for granule positions because a
- uint64 isn't universally available. Unfortunately,
- that means granposes can be 'negative' and result in
- extra being negative */
- if(extra<0)
- extra=0;
- if(vb->eofflag){
- /* trim the end */
- /* no preceding 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 count, not short count */
- /* Guard against corrupt/malicious frames that set EOP and
- a backdated granpos; don't rewind more samples than we
- actually have */
- if(extra > (v->pcm_current - v->pcm_returned)<<hs)
- extra = (v->pcm_current - v->pcm_returned)<<hs;
- v->pcm_current-=extra>>hs;
- }else{
- /* trim the beginning */
- v->pcm_returned+=extra>>hs;
- if(v->pcm_returned>v->pcm_current)
- v->pcm_returned=v->pcm_current;
- }
- }
- }
- }else{
- v->granulepos+=ci->blocksizes[v->lW]/4+ci->blocksizes[v->W]/4;
- if(vb->granulepos!=-1 && v->granulepos!=vb->granulepos){
- if(v->granulepos>vb->granulepos){
- long extra=v->granulepos-vb->granulepos;
- if(extra)
- if(vb->eofflag){
- /* partial last frame. Strip the extra samples off */
- /* Guard against corrupt/malicious frames that set EOP and
- a backdated granpos; don't rewind more samples than we
- actually have */
- if(extra > (v->pcm_current - v->pcm_returned)<<hs)
- extra = (v->pcm_current - v->pcm_returned)<<hs;
- /* we use ogg_int64_t for granule positions because a
- uint64 isn't universally available. Unfortunately,
- that means granposes can be 'negative' and result in
- extra being negative */
- if(extra<0)
- extra=0;
- v->pcm_current-=extra>>hs;
- } /* 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 } */
- v->granulepos=vb->granulepos;
- }
- }
- /* Update, cleanup */
- if(vb->eofflag)v->eofflag=1;
- return(0);
- }
- /* pcm==NULL indicates we just want the pending samples, no more */
- int vorbis_synthesis_pcmout(vorbis_dsp_state *v,float ***pcm){
- vorbis_info *vi=v->vi;
- if(v->pcm_returned>-1 && v->pcm_returned<v->pcm_current){
- if(pcm){
- int i;
- for(i=0;i<vi->channels;i++)
- v->pcmret[i]=v->pcm[i]+v->pcm_returned;
- *pcm=v->pcmret;
- }
- return(v->pcm_current-v->pcm_returned);
- }
- return(0);
- }
- int vorbis_synthesis_read(vorbis_dsp_state *v,int n){
- if(n && v->pcm_returned+n>v->pcm_current)return(OV_EINVAL);
- v->pcm_returned+=n;
- return(0);
- }
- /* intended for use with a specific vorbisfile feature; we want access
- to the [usually synthetic/postextrapolated] buffer and lapping at
- the end of a decode cycle, specifically, a half-short-block worth.
- This funtion works like pcmout above, except it will also expose
- this implicit buffer data not normally decoded. */
- int vorbis_synthesis_lapout(vorbis_dsp_state *v,float ***pcm){
- vorbis_info *vi=v->vi;
- codec_setup_info *ci=vi->codec_setup;
- int hs=ci->halfrate_flag;
- int n=ci->blocksizes[v->W]>>(hs+1);
- int n0=ci->blocksizes[0]>>(hs+1);
- int n1=ci->blocksizes[1]>>(hs+1);
- int i,j;
- if(v->pcm_returned<0)return 0;
- /* our returned data ends at pcm_returned; because the synthesis pcm
- buffer is a two-fragment ring, that means our data block may be
- fragmented by buffering, wrapping or a short block not filling
- out a buffer. To simplify things, we unfragment if it's at all
- possibly needed. Otherwise, we'd need to call lapout more than
- once as well as hold additional dsp state. Opt for
- simplicity. */
- /* centerW was advanced by blockin; it would be the center of the
- *next* block */
- if(v->centerW==n1){
- /* the data buffer wraps; swap the halves */
- /* slow, sure, small */
- for(j=0;j<vi->channels;j++){
- float *p=v->pcm[j];
- for(i=0;i<n1;i++){
- float temp=p[i];
- p[i]=p[i+n1];
- p[i+n1]=temp;
- }
- }
- v->pcm_current-=n1;
- v->pcm_returned-=n1;
- v->centerW=0;
- }
- /* solidify buffer into contiguous space */
- if((v->lW^v->W)==1){
- /* long/short or short/long */
- for(j=0;j<vi->channels;j++){
- float *s=v->pcm[j];
- float *d=v->pcm[j]+(n1-n0)/2;
- for(i=(n1+n0)/2-1;i>=0;--i)
- d[i]=s[i];
- }
- v->pcm_returned+=(n1-n0)/2;
- v->pcm_current+=(n1-n0)/2;
- }else{
- if(v->lW==0){
- /* short/short */
- for(j=0;j<vi->channels;j++){
- float *s=v->pcm[j];
- float *d=v->pcm[j]+n1-n0;
- for(i=n0-1;i>=0;--i)
- d[i]=s[i];
- }
- v->pcm_returned+=n1-n0;
- v->pcm_current+=n1-n0;
- }
- }
- if(pcm){
- int i;
- for(i=0;i<vi->channels;i++)
- v->pcmret[i]=v->pcm[i]+v->pcm_returned;
- *pcm=v->pcmret;
- }
- return(n1+n-v->pcm_returned);
- }
- const float *vorbis_window(vorbis_dsp_state *v,int W){
- vorbis_info *vi=v->vi;
- codec_setup_info *ci=vi->codec_setup;
- int hs=ci->halfrate_flag;
- private_state *b=v->backend_state;
- if(b->window[W]-1<0)return NULL;
- return _vorbis_window_get(b->window[W]-hs);
- }
|