examples/sfexamples/oggvorbiscodec/src/tremor/block.c

00001 /********************************************************************
00002  *                                                                  *
00003  * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE.   *
00004  *                                                                  *
00005  * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
00006  * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
00007  * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
00008  *                                                                  *
00009  * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002    *
00010  * BY THE Xiph.Org FOUNDATION http://www.xiph.org/                  *
00011  *                                                                  *
00012  ********************************************************************
00013 
00014  function: PCM data vector blocking, windowing and dis/reassembly
00015 
00016  ********************************************************************/
00017 
00018 #include <stdio.h>
00019 #include <stdlib.h>
00020 #include <string.h>
00021 #include "ogg.h"
00022 #include "ivorbiscodec.h"
00023 #include "codec_internal.h"
00024 
00025 #include "window.h"
00026 #include "registry.h"
00027 #include "misc.h"
00028 
00029 static int ilog(unsigned int v){
00030   int ret=0;
00031   if(v)--v;
00032   while(v){
00033     ret++;
00034     v>>=1;
00035   }
00036   return(ret);
00037 }
00038 
00039 /* pcm accumulator examples (not exhaustive):
00040 
00041  <-------------- lW ---------------->
00042                    <--------------- W ---------------->
00043 :            .....|.....       _______________         |
00044 :        .'''     |     '''_---      |       |\        |
00045 :.....'''         |_____--- '''......|       | \_______|
00046 :.................|__________________|_______|__|______|
00047                   |<------ Sl ------>|      > Sr <     |endW
00048                   |beginSl           |endSl  |  |endSr   
00049                   |beginW            |endlW  |beginSr
00050 
00051 
00052                       |< lW >|       
00053                    <--------------- W ---------------->
00054                   |   |  ..  ______________            |
00055                   |   | '  `/        |     ---_        |
00056                   |___.'___/`.       |         ---_____| 
00057                   |_______|__|_______|_________________|
00058                   |      >|Sl|<      |<------ Sr ----->|endW
00059                   |       |  |endSl  |beginSr          |endSr
00060                   |beginW |  |endlW                     
00061                   mult[0] |beginSl                     mult[n]
00062 
00063  <-------------- lW ----------------->
00064                           |<--W-->|                               
00065 :            ..............  ___  |   |                    
00066 :        .'''             |`/   \ |   |                       
00067 :.....'''                 |/`....\|...|                    
00068 :.........................|___|___|___|                  
00069                           |Sl |Sr |endW    
00070                           |   |   |endSr
00071                           |   |beginSr
00072                           |   |endSl
00073                           |beginSl
00074                           |beginW
00075 */
00076 
00077 /* block abstraction setup *********************************************/
00078 
00079 #ifndef WORD_ALIGN
00080 #define WORD_ALIGN 8
00081 #endif
00082 
00083 int vorbis_block_init(vorbis_dsp_state *v, vorbis_block *vb){
00084   memset(vb,0,sizeof(*vb));
00085   vb->vd=v;
00086   vb->localalloc=0;
00087   vb->localstore=NULL;
00088   
00089   return(0);
00090 }
00091 
00092 void *_vorbis_block_alloc(vorbis_block *vb,long bytes){
00093   bytes=(bytes+(WORD_ALIGN-1)) & ~(WORD_ALIGN-1);
00094   if(bytes+vb->localtop>vb->localalloc){
00095     /* can't just _ogg_realloc... there are outstanding pointers */
00096     if(vb->localstore){
00097       struct alloc_chain *link=(struct alloc_chain *)_ogg_malloc(sizeof(*link));
00098       vb->totaluse+=vb->localtop;
00099       link->next=vb->reap;
00100       link->ptr=vb->localstore;
00101       vb->reap=link;
00102     }
00103     /* highly conservative */
00104     vb->localalloc=bytes;
00105     vb->localstore=_ogg_malloc(vb->localalloc);
00106     vb->localtop=0;
00107   }
00108   {
00109     void *ret=(void *)(((char *)vb->localstore)+vb->localtop);
00110     vb->localtop+=bytes;
00111     return ret;
00112   }
00113 }
00114 
00115 /* reap the chain, pull the ripcord */
00116 void _vorbis_block_ripcord(vorbis_block *vb){
00117   /* reap the chain */
00118   struct alloc_chain *reap=vb->reap;
00119   while(reap){
00120     struct alloc_chain *next=reap->next;
00121     _ogg_free(reap->ptr);
00122     memset(reap,0,sizeof(*reap));
00123     _ogg_free(reap);
00124     reap=next;
00125   }
00126   /* consolidate storage */
00127   if(vb->totaluse){
00128     vb->localstore=_ogg_realloc(vb->localstore,vb->totaluse+vb->localalloc);
00129     vb->localalloc+=vb->totaluse;
00130     vb->totaluse=0;
00131   }
00132 
00133   /* pull the ripcord */
00134   vb->localtop=0;
00135   vb->reap=NULL;
00136 }
00137 
00138 int vorbis_block_clear(vorbis_block *vb){
00139   _vorbis_block_ripcord(vb);
00140   if(vb->localstore)_ogg_free(vb->localstore);
00141 
00142   memset(vb,0,sizeof(*vb));
00143   return(0);
00144 }
00145 
00146 static int _vds_init(vorbis_dsp_state *v,vorbis_info *vi){
00147   int i;
00148   codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
00149   private_state *b=NULL;
00150 
00151   memset(v,0,sizeof(*v));
00152   b=(private_state *)(v->backend_state=_ogg_calloc(1,sizeof(*b)));
00153 
00154   v->vi=vi;
00155   b->modebits=ilog(ci->modes);
00156 
00157   /* Vorbis I uses only window type 0 */
00158   b->window[0]=_vorbis_window(0,ci->blocksizes[0]/2);
00159   b->window[1]=_vorbis_window(0,ci->blocksizes[1]/2);
00160 
00161   /* finish the codebooks */
00162   if(!ci->fullbooks){
00163     ci->fullbooks=(codebook *)_ogg_calloc(ci->books,sizeof(*ci->fullbooks));
00164     for(i=0;i<ci->books;i++){
00165       vorbis_book_init_decode(ci->fullbooks+i,ci->book_param[i]);
00166       /* decode codebooks are now standalone after init */
00167       vorbis_staticbook_destroy(ci->book_param[i]);
00168       ci->book_param[i]=NULL;
00169     }
00170   }
00171 
00172   v->pcm_storage=ci->blocksizes[1];
00173   v->pcm=(ogg_int32_t **)_ogg_malloc(vi->channels*sizeof(*v->pcm));
00174   v->pcmret=(ogg_int32_t **)_ogg_malloc(vi->channels*sizeof(*v->pcmret));
00175   for(i=0;i<vi->channels;i++)
00176     v->pcm[i]=(ogg_int32_t *)_ogg_calloc(v->pcm_storage,sizeof(*v->pcm[i]));
00177 
00178   /* all 1 (large block) or 0 (small block) */
00179   /* explicitly set for the sake of clarity */
00180   v->lW=0; /* previous window size */
00181   v->W=0;  /* current window size */
00182 
00183   /* initialize all the mapping/backend lookups */
00184   b->mode=(vorbis_look_mapping **)_ogg_calloc(ci->modes,sizeof(*b->mode));
00185   for(i=0;i<ci->modes;i++){
00186     int mapnum=ci->mode_param[i]->mapping;
00187     int maptype=ci->map_type[mapnum];
00188     b->mode[i]=_mapping_P[maptype]->look(v,ci->mode_param[i],
00189                                          ci->map_param[mapnum]);
00190   }
00191   return(0);
00192 }
00193 
00194 int vorbis_synthesis_restart(vorbis_dsp_state *v){
00195   vorbis_info *vi=v->vi;
00196   codec_setup_info *ci;
00197 
00198   if(!v->backend_state)return -1;
00199   if(!vi)return -1;
00200   ci=(codec_setup_info*)vi->codec_setup;
00201   if(!ci)return -1;
00202 
00203   v->centerW=ci->blocksizes[1]/2;
00204   v->pcm_current=v->centerW;
00205   
00206   v->pcm_returned=-1;
00207   v->granulepos=-1;
00208   v->sequence=-1;
00209   ((private_state *)(v->backend_state))->sample_count=-1;
00210 
00211   return(0);
00212 }
00213 
00214 int vorbis_synthesis_init(vorbis_dsp_state *v,vorbis_info *vi){
00215   _vds_init(v,vi);
00216   vorbis_synthesis_restart(v);
00217 
00218   return(0);
00219 }
00220 
00221 void vorbis_dsp_clear(vorbis_dsp_state *v){
00222   int i;
00223   if(v){
00224     vorbis_info *vi=v->vi;
00225     codec_setup_info *ci=(codec_setup_info *)(vi?vi->codec_setup:NULL);
00226     private_state *b=(private_state *)v->backend_state;
00227 
00228     if(v->pcm){
00229       for(i=0;i<vi->channels;i++)
00230         if(v->pcm[i])_ogg_free(v->pcm[i]);
00231       _ogg_free(v->pcm);
00232       if(v->pcmret)_ogg_free(v->pcmret);
00233     }
00234 
00235     /* free mode lookups; these are actually vorbis_look_mapping structs */
00236     if(ci){
00237       for(i=0;i<ci->modes;i++){
00238         int mapnum=ci->mode_param[i]->mapping;
00239         int maptype=ci->map_type[mapnum];
00240         if(b && b->mode)_mapping_P[maptype]->free_look(b->mode[i]);
00241       }
00242     }
00243 
00244     if(b){
00245       if(b->mode)_ogg_free(b->mode);    
00246       _ogg_free(b);
00247     }
00248     
00249     memset(v,0,sizeof(*v));
00250   }
00251 }
00252 
00253 /* Unlike in analysis, the window is only partially applied for each
00254    block.  The time domain envelope is not yet handled at the point of
00255    calling (as it relies on the previous block). */
00256 
00257 int vorbis_synthesis_blockin(vorbis_dsp_state *v,vorbis_block *vb){
00258   vorbis_info *vi=v->vi;
00259   codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
00260   private_state *b=(private_state*)v->backend_state;
00261   int i,j;
00262 
00263   if(v->pcm_current>v->pcm_returned  && v->pcm_returned!=-1)return(OV_EINVAL);
00264 
00265   v->lW=v->W;
00266   v->W=vb->W;
00267   v->nW=-1;
00268 
00269   if((v->sequence==-1)||
00270      (v->sequence+1 != vb->sequence)){
00271     v->granulepos=-1; /* out of sequence; lose count */
00272     b->sample_count=-1;
00273   }
00274 
00275   v->sequence=vb->sequence;
00276   
00277   if(vb->pcm){  /* no pcm to process if vorbis_synthesis_trackonly 
00278                    was called on block */
00279     int n=ci->blocksizes[v->W]/2;
00280     int n0=ci->blocksizes[0]/2;
00281     int n1=ci->blocksizes[1]/2;
00282     
00283     int thisCenter;
00284     int prevCenter;
00285     
00286     if(v->centerW){
00287       thisCenter=n1;
00288       prevCenter=0;
00289     }else{
00290       thisCenter=0;
00291       prevCenter=n1;
00292     }
00293     
00294     /* v->pcm is now used like a two-stage double buffer.  We don't want
00295        to have to constantly shift *or* adjust memory usage.  Don't
00296        accept a new block until the old is shifted out */
00297     
00298     /* overlap/add PCM */
00299     
00300     for(j=0;j<vi->channels;j++){
00301       /* the overlap/add section */
00302       if(v->lW){
00303         if(v->W){
00304           /* large/large */
00305           ogg_int32_t *pcm=v->pcm[j]+prevCenter;
00306           ogg_int32_t *p=vb->pcm[j];
00307           for(i=0;i<n1;i++)
00308             pcm[i]+=p[i];
00309         }else{
00310           /* large/small */
00311           ogg_int32_t *pcm=v->pcm[j]+prevCenter+n1/2-n0/2;
00312           ogg_int32_t *p=vb->pcm[j];
00313           for(i=0;i<n0;i++)
00314             pcm[i]+=p[i];
00315         }
00316       }else{
00317         if(v->W){
00318           /* small/large */
00319           ogg_int32_t *pcm=v->pcm[j]+prevCenter;
00320           ogg_int32_t *p=vb->pcm[j]+n1/2-n0/2;
00321           for(i=0;i<n0;i++)
00322             pcm[i]+=p[i];
00323           for(;i<n1/2+n0/2;i++)
00324             pcm[i]=p[i];
00325         }else{
00326           /* small/small */
00327           ogg_int32_t *pcm=v->pcm[j]+prevCenter;
00328           ogg_int32_t *p=vb->pcm[j];
00329           for(i=0;i<n0;i++)
00330             pcm[i]+=p[i];
00331         }
00332       }
00333       
00334       /* the copy section */
00335       {
00336         ogg_int32_t *pcm=v->pcm[j]+thisCenter;
00337         ogg_int32_t *p=vb->pcm[j]+n;
00338         for(i=0;i<n;i++)
00339           pcm[i]=p[i];
00340       }
00341     }
00342     
00343     if(v->centerW)
00344       v->centerW=0;
00345     else
00346       v->centerW=n1;
00347     
00348     /* deal with initial packet state; we do this using the explicit
00349        pcm_returned==-1 flag otherwise we're sensitive to first block
00350        being short or long */
00351 
00352     if(v->pcm_returned==-1){
00353       v->pcm_returned=thisCenter;
00354       v->pcm_current=thisCenter;
00355     }else{
00356       v->pcm_returned=prevCenter;
00357       v->pcm_current=prevCenter+
00358         ci->blocksizes[v->lW]/4+
00359         ci->blocksizes[v->W]/4;
00360     }
00361 
00362   }
00363     
00364   /* track the frame number... This is for convenience, but also
00365      making sure our last packet doesn't end with added padding.  If
00366      the last packet is partial, the number of samples we'll have to
00367      return will be past the vb->granulepos.
00368      
00369      This is not foolproof!  It will be confused if we begin
00370      decoding at the last page after a seek or hole.  In that case,
00371      we don't have a starting point to judge where the last frame
00372      is.  For this reason, vorbisfile will always try to make sure
00373      it reads the last two marked pages in proper sequence */
00374   
00375   if(b->sample_count==-1){
00376     b->sample_count=0;
00377   }else{
00378     b->sample_count+=ci->blocksizes[v->lW]/4+ci->blocksizes[v->W]/4;
00379   }
00380     
00381   if(v->granulepos==-1){
00382     if(vb->granulepos!=-1){ /* only set if we have a position to set to */
00383       
00384       v->granulepos=vb->granulepos;
00385       
00386       /* is this a short page? */
00387       if(b->sample_count>v->granulepos){
00388         /* corner case; if this is both the first and last audio page,
00389            then spec says the end is cut, not beginning */
00390         if(vb->eofflag){
00391           /* trim the end */
00392           /* no preceeding granulepos; assume we started at zero (we'd
00393              have to in a short single-page stream) */
00394           /* granulepos could be -1 due to a seek, but that would result
00395              in a long coun`t, not short count */
00396           
00397           v->pcm_current-=(b->sample_count-v->granulepos);
00398         }else{
00399           /* trim the beginning */
00400           v->pcm_returned+=(b->sample_count-v->granulepos);
00401           if(v->pcm_returned>v->pcm_current)
00402             v->pcm_returned=v->pcm_current;
00403         }
00404         
00405       }
00406       
00407     }
00408   }else{
00409     v->granulepos+=ci->blocksizes[v->lW]/4+ci->blocksizes[v->W]/4;
00410     if(vb->granulepos!=-1 && v->granulepos!=vb->granulepos){
00411       
00412       if(v->granulepos>vb->granulepos){
00413         long extra=v->granulepos-vb->granulepos;
00414         
00415         if(extra)
00416           if(vb->eofflag){
00417             /* partial last frame.  Strip the extra samples off */
00418             v->pcm_current-=extra;
00419           } /* else {Shouldn't happen *unless* the bitstream is out of
00420                spec.  Either way, believe the bitstream } */
00421       } /* else {Shouldn't happen *unless* the bitstream is out of
00422            spec.  Either way, believe the bitstream } */
00423       v->granulepos=vb->granulepos;
00424     }
00425   }
00426   
00427   /* Update, cleanup */
00428   
00429   if(vb->eofflag)v->eofflag=1;
00430   return(0);
00431 }
00432 
00433 /* pcm==NULL indicates we just want the pending samples, no more */
00434 int vorbis_synthesis_pcmout(vorbis_dsp_state *v,ogg_int32_t ***pcm){
00435   vorbis_info *vi=v->vi;
00436   if(v->pcm_returned>-1 && v->pcm_returned<v->pcm_current){
00437     if(pcm){
00438       int i;
00439       for(i=0;i<vi->channels;i++)
00440         v->pcmret[i]=v->pcm[i]+v->pcm_returned;
00441       *pcm=v->pcmret;
00442     }
00443     return(v->pcm_current-v->pcm_returned);
00444   }
00445   return(0);
00446 }
00447 
00448 int vorbis_synthesis_read(vorbis_dsp_state *v,int bytes){
00449   if(bytes && v->pcm_returned+bytes>v->pcm_current)return(OV_EINVAL);
00450   v->pcm_returned+=bytes;
00451   return(0);
00452 }
00453 

Generated by  doxygen 1.6.2