LCOV - code coverage report
Current view: directory - media/libvorbis/lib - vorbis_envelope.c (source / functions) Found Hit Coverage
Test: app.info Lines: 172 0 0.0 %
Date: 2012-06-02 Functions: 6 0 0.0 %

       1                 : /********************************************************************
       2                 :  *                                                                  *
       3                 :  * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE.   *
       4                 :  * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
       5                 :  * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
       6                 :  * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
       7                 :  *                                                                  *
       8                 :  * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009             *
       9                 :  * by the Xiph.Org Foundation http://www.xiph.org/                  *
      10                 :  *                                                                  *
      11                 :  ********************************************************************
      12                 : 
      13                 :  function: PCM data envelope analysis
      14                 :  last mod: $Id: envelope.c 16227 2009-07-08 06:58:46Z xiphmont $
      15                 : 
      16                 :  ********************************************************************/
      17                 : 
      18                 : #include <stdlib.h>
      19                 : #include <string.h>
      20                 : #include <stdio.h>
      21                 : #include <math.h>
      22                 : #include <ogg/ogg.h>
      23                 : #include "vorbis/codec.h"
      24                 : #include "codec_internal.h"
      25                 : 
      26                 : #include "os.h"
      27                 : #include "scales.h"
      28                 : #include "envelope.h"
      29                 : #include "mdct.h"
      30                 : #include "misc.h"
      31                 : 
      32               0 : void _ve_envelope_init(envelope_lookup *e,vorbis_info *vi){
      33               0 :   codec_setup_info *ci=vi->codec_setup;
      34               0 :   vorbis_info_psy_global *gi=&ci->psy_g_param;
      35               0 :   int ch=vi->channels;
      36                 :   int i,j;
      37               0 :   int n=e->winlength=128;
      38               0 :   e->searchstep=64; /* not random */
      39                 : 
      40               0 :   e->minenergy=gi->preecho_minenergy;
      41               0 :   e->ch=ch;
      42               0 :   e->storage=128;
      43               0 :   e->cursor=ci->blocksizes[1]/2;
      44               0 :   e->mdct_win=_ogg_calloc(n,sizeof(*e->mdct_win));
      45               0 :   mdct_init(&e->mdct,n);
      46                 : 
      47               0 :   for(i=0;i<n;i++){
      48               0 :     e->mdct_win[i]=sin(i/(n-1.)*M_PI);
      49               0 :     e->mdct_win[i]*=e->mdct_win[i];
      50                 :   }
      51                 : 
      52                 :   /* magic follows */
      53               0 :   e->band[0].begin=2;  e->band[0].end=4;
      54               0 :   e->band[1].begin=4;  e->band[1].end=5;
      55               0 :   e->band[2].begin=6;  e->band[2].end=6;
      56               0 :   e->band[3].begin=9;  e->band[3].end=8;
      57               0 :   e->band[4].begin=13;  e->band[4].end=8;
      58               0 :   e->band[5].begin=17;  e->band[5].end=8;
      59               0 :   e->band[6].begin=22;  e->band[6].end=8;
      60                 : 
      61               0 :   for(j=0;j<VE_BANDS;j++){
      62               0 :     n=e->band[j].end;
      63               0 :     e->band[j].window=_ogg_malloc(n*sizeof(*e->band[0].window));
      64               0 :     for(i=0;i<n;i++){
      65               0 :       e->band[j].window[i]=sin((i+.5)/n*M_PI);
      66               0 :       e->band[j].total+=e->band[j].window[i];
      67                 :     }
      68               0 :     e->band[j].total=1./e->band[j].total;
      69                 :   }
      70                 : 
      71               0 :   e->filter=_ogg_calloc(VE_BANDS*ch,sizeof(*e->filter));
      72               0 :   e->mark=_ogg_calloc(e->storage,sizeof(*e->mark));
      73                 : 
      74               0 : }
      75                 : 
      76               0 : void _ve_envelope_clear(envelope_lookup *e){
      77                 :   int i;
      78               0 :   mdct_clear(&e->mdct);
      79               0 :   for(i=0;i<VE_BANDS;i++)
      80               0 :     _ogg_free(e->band[i].window);
      81               0 :   _ogg_free(e->mdct_win);
      82               0 :   _ogg_free(e->filter);
      83               0 :   _ogg_free(e->mark);
      84               0 :   memset(e,0,sizeof(*e));
      85               0 : }
      86                 : 
      87                 : /* fairly straight threshhold-by-band based until we find something
      88                 :    that works better and isn't patented. */
      89                 : 
      90               0 : static int _ve_amp(envelope_lookup *ve,
      91                 :                    vorbis_info_psy_global *gi,
      92                 :                    float *data,
      93                 :                    envelope_band *bands,
      94                 :                    envelope_filter_state *filters){
      95               0 :   long n=ve->winlength;
      96               0 :   int ret=0;
      97                 :   long i,j;
      98                 :   float decay;
      99                 : 
     100                 :   /* we want to have a 'minimum bar' for energy, else we're just
     101                 :      basing blocks on quantization noise that outweighs the signal
     102                 :      itself (for low power signals) */
     103                 : 
     104               0 :   float minV=ve->minenergy;
     105               0 :   float *vec=alloca(n*sizeof(*vec));
     106                 : 
     107                 :   /* stretch is used to gradually lengthen the number of windows
     108                 :      considered prevoius-to-potential-trigger */
     109               0 :   int stretch=max(VE_MINSTRETCH,ve->stretch/2);
     110               0 :   float penalty=gi->stretch_penalty-(ve->stretch/2-VE_MINSTRETCH);
     111               0 :   if(penalty<0.f)penalty=0.f;
     112               0 :   if(penalty>gi->stretch_penalty)penalty=gi->stretch_penalty;
     113                 : 
     114                 :   /*_analysis_output_always("lpcm",seq2,data,n,0,0,
     115                 :     totalshift+pos*ve->searchstep);*/
     116                 : 
     117                 :  /* window and transform */
     118               0 :   for(i=0;i<n;i++)
     119               0 :     vec[i]=data[i]*ve->mdct_win[i];
     120               0 :   mdct_forward(&ve->mdct,vec,vec);
     121                 : 
     122                 :   /*_analysis_output_always("mdct",seq2,vec,n/2,0,1,0); */
     123                 : 
     124                 :   /* near-DC spreading function; this has nothing to do with
     125                 :      psychoacoustics, just sidelobe leakage and window size */
     126                 :   {
     127               0 :     float temp=vec[0]*vec[0]+.7*vec[1]*vec[1]+.2*vec[2]*vec[2];
     128               0 :     int ptr=filters->nearptr;
     129                 : 
     130                 :     /* the accumulation is regularly refreshed from scratch to avoid
     131                 :        floating point creep */
     132               0 :     if(ptr==0){
     133               0 :       decay=filters->nearDC_acc=filters->nearDC_partialacc+temp;
     134               0 :       filters->nearDC_partialacc=temp;
     135                 :     }else{
     136               0 :       decay=filters->nearDC_acc+=temp;
     137               0 :       filters->nearDC_partialacc+=temp;
     138                 :     }
     139               0 :     filters->nearDC_acc-=filters->nearDC[ptr];
     140               0 :     filters->nearDC[ptr]=temp;
     141                 : 
     142               0 :     decay*=(1./(VE_NEARDC+1));
     143               0 :     filters->nearptr++;
     144               0 :     if(filters->nearptr>=VE_NEARDC)filters->nearptr=0;
     145               0 :     decay=todB(&decay)*.5-15.f;
     146                 :   }
     147                 : 
     148                 :   /* perform spreading and limiting, also smooth the spectrum.  yes,
     149                 :      the MDCT results in all real coefficients, but it still *behaves*
     150                 :      like real/imaginary pairs */
     151               0 :   for(i=0;i<n/2;i+=2){
     152               0 :     float val=vec[i]*vec[i]+vec[i+1]*vec[i+1];
     153               0 :     val=todB(&val)*.5f;
     154               0 :     if(val<decay)val=decay;
     155               0 :     if(val<minV)val=minV;
     156               0 :     vec[i>>1]=val;
     157               0 :     decay-=8.;
     158                 :   }
     159                 : 
     160                 :   /*_analysis_output_always("spread",seq2++,vec,n/4,0,0,0);*/
     161                 : 
     162                 :   /* perform preecho/postecho triggering by band */
     163               0 :   for(j=0;j<VE_BANDS;j++){
     164               0 :     float acc=0.;
     165                 :     float valmax,valmin;
     166                 : 
     167                 :     /* accumulate amplitude */
     168               0 :     for(i=0;i<bands[j].end;i++)
     169               0 :       acc+=vec[i+bands[j].begin]*bands[j].window[i];
     170                 : 
     171               0 :     acc*=bands[j].total;
     172                 : 
     173                 :     /* convert amplitude to delta */
     174                 :     {
     175               0 :       int p,this=filters[j].ampptr;
     176               0 :       float postmax,postmin,premax=-99999.f,premin=99999.f;
     177                 : 
     178               0 :       p=this;
     179               0 :       p--;
     180               0 :       if(p<0)p+=VE_AMP;
     181               0 :       postmax=max(acc,filters[j].ampbuf[p]);
     182               0 :       postmin=min(acc,filters[j].ampbuf[p]);
     183                 : 
     184               0 :       for(i=0;i<stretch;i++){
     185               0 :         p--;
     186               0 :         if(p<0)p+=VE_AMP;
     187               0 :         premax=max(premax,filters[j].ampbuf[p]);
     188               0 :         premin=min(premin,filters[j].ampbuf[p]);
     189                 :       }
     190                 : 
     191               0 :       valmin=postmin-premin;
     192               0 :       valmax=postmax-premax;
     193                 : 
     194                 :       /*filters[j].markers[pos]=valmax;*/
     195               0 :       filters[j].ampbuf[this]=acc;
     196               0 :       filters[j].ampptr++;
     197               0 :       if(filters[j].ampptr>=VE_AMP)filters[j].ampptr=0;
     198                 :     }
     199                 : 
     200                 :     /* look at min/max, decide trigger */
     201               0 :     if(valmax>gi->preecho_thresh[j]+penalty){
     202               0 :       ret|=1;
     203               0 :       ret|=4;
     204                 :     }
     205               0 :     if(valmin<gi->postecho_thresh[j]-penalty)ret|=2;
     206                 :   }
     207                 : 
     208               0 :   return(ret);
     209                 : }
     210                 : 
     211                 : #if 0
     212                 : static int seq=0;
     213                 : static ogg_int64_t totalshift=-1024;
     214                 : #endif
     215                 : 
     216               0 : long _ve_envelope_search(vorbis_dsp_state *v){
     217               0 :   vorbis_info *vi=v->vi;
     218               0 :   codec_setup_info *ci=vi->codec_setup;
     219               0 :   vorbis_info_psy_global *gi=&ci->psy_g_param;
     220               0 :   envelope_lookup *ve=((private_state *)(v->backend_state))->ve;
     221                 :   long i,j;
     222                 : 
     223               0 :   int first=ve->current/ve->searchstep;
     224               0 :   int last=v->pcm_current/ve->searchstep-VE_WIN;
     225               0 :   if(first<0)first=0;
     226                 : 
     227                 :   /* make sure we have enough storage to match the PCM */
     228               0 :   if(last+VE_WIN+VE_POST>ve->storage){
     229               0 :     ve->storage=last+VE_WIN+VE_POST; /* be sure */
     230               0 :     ve->mark=_ogg_realloc(ve->mark,ve->storage*sizeof(*ve->mark));
     231                 :   }
     232                 : 
     233               0 :   for(j=first;j<last;j++){
     234               0 :     int ret=0;
     235                 : 
     236               0 :     ve->stretch++;
     237               0 :     if(ve->stretch>VE_MAXSTRETCH*2)
     238               0 :       ve->stretch=VE_MAXSTRETCH*2;
     239                 : 
     240               0 :     for(i=0;i<ve->ch;i++){
     241               0 :       float *pcm=v->pcm[i]+ve->searchstep*(j);
     242               0 :       ret|=_ve_amp(ve,gi,pcm,ve->band,ve->filter+i*VE_BANDS);
     243                 :     }
     244                 : 
     245               0 :     ve->mark[j+VE_POST]=0;
     246               0 :     if(ret&1){
     247               0 :       ve->mark[j]=1;
     248               0 :       ve->mark[j+1]=1;
     249                 :     }
     250                 : 
     251               0 :     if(ret&2){
     252               0 :       ve->mark[j]=1;
     253               0 :       if(j>0)ve->mark[j-1]=1;
     254                 :     }
     255                 : 
     256               0 :     if(ret&4)ve->stretch=-1;
     257                 :   }
     258                 : 
     259               0 :   ve->current=last*ve->searchstep;
     260                 : 
     261                 :   {
     262               0 :     long centerW=v->centerW;
     263               0 :     long testW=
     264               0 :       centerW+
     265               0 :       ci->blocksizes[v->W]/4+
     266               0 :       ci->blocksizes[1]/2+
     267               0 :       ci->blocksizes[0]/4;
     268                 : 
     269               0 :     j=ve->cursor;
     270                 : 
     271               0 :     while(j<ve->current-(ve->searchstep)){/* account for postecho
     272                 :                                              working back one window */
     273               0 :       if(j>=testW)return(1);
     274                 : 
     275               0 :       ve->cursor=j;
     276                 : 
     277               0 :       if(ve->mark[j/ve->searchstep]){
     278               0 :         if(j>centerW){
     279                 : 
     280                 : #if 0
     281                 :           if(j>ve->curmark){
     282                 :             float *marker=alloca(v->pcm_current*sizeof(*marker));
     283                 :             int l,m;
     284                 :             memset(marker,0,sizeof(*marker)*v->pcm_current);
     285                 :             fprintf(stderr,"mark! seq=%d, cursor:%fs time:%fs\n",
     286                 :                     seq,
     287                 :                     (totalshift+ve->cursor)/44100.,
     288                 :                     (totalshift+j)/44100.);
     289                 :             _analysis_output_always("pcmL",seq,v->pcm[0],v->pcm_current,0,0,totalshift);
     290                 :             _analysis_output_always("pcmR",seq,v->pcm[1],v->pcm_current,0,0,totalshift);
     291                 : 
     292                 :             _analysis_output_always("markL",seq,v->pcm[0],j,0,0,totalshift);
     293                 :             _analysis_output_always("markR",seq,v->pcm[1],j,0,0,totalshift);
     294                 : 
     295                 :             for(m=0;m<VE_BANDS;m++){
     296                 :               char buf[80];
     297                 :               sprintf(buf,"delL%d",m);
     298                 :               for(l=0;l<last;l++)marker[l*ve->searchstep]=ve->filter[m].markers[l]*.1;
     299                 :               _analysis_output_always(buf,seq,marker,v->pcm_current,0,0,totalshift);
     300                 :             }
     301                 : 
     302                 :             for(m=0;m<VE_BANDS;m++){
     303                 :               char buf[80];
     304                 :               sprintf(buf,"delR%d",m);
     305                 :               for(l=0;l<last;l++)marker[l*ve->searchstep]=ve->filter[m+VE_BANDS].markers[l]*.1;
     306                 :               _analysis_output_always(buf,seq,marker,v->pcm_current,0,0,totalshift);
     307                 :             }
     308                 : 
     309                 :             for(l=0;l<last;l++)marker[l*ve->searchstep]=ve->mark[l]*.4;
     310                 :             _analysis_output_always("mark",seq,marker,v->pcm_current,0,0,totalshift);
     311                 : 
     312                 : 
     313                 :             seq++;
     314                 : 
     315                 :           }
     316                 : #endif
     317                 : 
     318               0 :           ve->curmark=j;
     319               0 :           if(j>=testW)return(1);
     320               0 :           return(0);
     321                 :         }
     322                 :       }
     323               0 :       j+=ve->searchstep;
     324                 :     }
     325                 :   }
     326                 : 
     327               0 :   return(-1);
     328                 : }
     329                 : 
     330               0 : int _ve_envelope_mark(vorbis_dsp_state *v){
     331               0 :   envelope_lookup *ve=((private_state *)(v->backend_state))->ve;
     332               0 :   vorbis_info *vi=v->vi;
     333               0 :   codec_setup_info *ci=vi->codec_setup;
     334               0 :   long centerW=v->centerW;
     335               0 :   long beginW=centerW-ci->blocksizes[v->W]/4;
     336               0 :   long endW=centerW+ci->blocksizes[v->W]/4;
     337               0 :   if(v->W){
     338               0 :     beginW-=ci->blocksizes[v->lW]/4;
     339               0 :     endW+=ci->blocksizes[v->nW]/4;
     340                 :   }else{
     341               0 :     beginW-=ci->blocksizes[0]/4;
     342               0 :     endW+=ci->blocksizes[0]/4;
     343                 :   }
     344                 : 
     345               0 :   if(ve->curmark>=beginW && ve->curmark<endW)return(1);
     346                 :   {
     347               0 :     long first=beginW/ve->searchstep;
     348               0 :     long last=endW/ve->searchstep;
     349                 :     long i;
     350               0 :     for(i=first;i<last;i++)
     351               0 :       if(ve->mark[i])return(1);
     352                 :   }
     353               0 :   return(0);
     354                 : }
     355                 : 
     356               0 : void _ve_envelope_shift(envelope_lookup *e,long shift){
     357               0 :   int smallsize=e->current/e->searchstep+VE_POST; /* adjust for placing marks
     358                 :                                                      ahead of ve->current */
     359               0 :   int smallshift=shift/e->searchstep;
     360                 : 
     361               0 :   memmove(e->mark,e->mark+smallshift,(smallsize-smallshift)*sizeof(*e->mark));
     362                 : 
     363                 : #if 0
     364                 :   for(i=0;i<VE_BANDS*e->ch;i++)
     365                 :     memmove(e->filter[i].markers,
     366                 :             e->filter[i].markers+smallshift,
     367                 :             (1024-smallshift)*sizeof(*(*e->filter).markers));
     368                 :   totalshift+=shift;
     369                 : #endif
     370                 : 
     371               0 :   e->current-=shift;
     372               0 :   if(e->curmark>=0)
     373               0 :     e->curmark-=shift;
     374               0 :   e->cursor-=shift;
     375               0 : }

Generated by: LCOV version 1.7