LCOV - code coverage report
Current view: top level - media/libvorbis/lib - vorbis_envelope.c (source / functions) Hit Total Coverage
Test: output.info Lines: 0 172 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 6 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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$
      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.13