Index: webrtc/modules/audio_coding/codecs/opus/opus/src/src/opus_compare.c |
diff --git a/webrtc/modules/audio_coding/codecs/opus/opus/src/src/opus_compare.c b/webrtc/modules/audio_coding/codecs/opus/opus/src/src/opus_compare.c |
new file mode 100644 |
index 0000000000000000000000000000000000000000..06c67d752f7153c191344947d594b3611636c9f8 |
--- /dev/null |
+++ b/webrtc/modules/audio_coding/codecs/opus/opus/src/src/opus_compare.c |
@@ -0,0 +1,379 @@ |
+/* Copyright (c) 2011-2012 Xiph.Org Foundation, Mozilla Corporation |
+ Written by Jean-Marc Valin and Timothy B. Terriberry */ |
+/* |
+ Redistribution and use in source and binary forms, with or without |
+ modification, are permitted provided that the following conditions |
+ are met: |
+ |
+ - Redistributions of source code must retain the above copyright |
+ notice, this list of conditions and the following disclaimer. |
+ |
+ - Redistributions in binary form must reproduce the above copyright |
+ notice, this list of conditions and the following disclaimer in the |
+ documentation and/or other materials provided with the distribution. |
+ |
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER |
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
+*/ |
+ |
+#include <stdio.h> |
+#include <stdlib.h> |
+#include <math.h> |
+#include <string.h> |
+ |
+#define OPUS_PI (3.14159265F) |
+ |
+#define OPUS_COSF(_x) ((float)cos(_x)) |
+#define OPUS_SINF(_x) ((float)sin(_x)) |
+ |
+static void *check_alloc(void *_ptr){ |
+ if(_ptr==NULL){ |
+ fprintf(stderr,"Out of memory.\n"); |
+ exit(EXIT_FAILURE); |
+ } |
+ return _ptr; |
+} |
+ |
+static void *opus_malloc(size_t _size){ |
+ return check_alloc(malloc(_size)); |
+} |
+ |
+static void *opus_realloc(void *_ptr,size_t _size){ |
+ return check_alloc(realloc(_ptr,_size)); |
+} |
+ |
+static size_t read_pcm16(float **_samples,FILE *_fin,int _nchannels){ |
+ unsigned char buf[1024]; |
+ float *samples; |
+ size_t nsamples; |
+ size_t csamples; |
+ size_t xi; |
+ size_t nread; |
+ samples=NULL; |
+ nsamples=csamples=0; |
+ for(;;){ |
+ nread=fread(buf,2*_nchannels,1024/(2*_nchannels),_fin); |
+ if(nread<=0)break; |
+ if(nsamples+nread>csamples){ |
+ do csamples=csamples<<1|1; |
+ while(nsamples+nread>csamples); |
+ samples=(float *)opus_realloc(samples, |
+ _nchannels*csamples*sizeof(*samples)); |
+ } |
+ for(xi=0;xi<nread;xi++){ |
+ int ci; |
+ for(ci=0;ci<_nchannels;ci++){ |
+ int s; |
+ s=buf[2*(xi*_nchannels+ci)+1]<<8|buf[2*(xi*_nchannels+ci)]; |
+ s=((s&0xFFFF)^0x8000)-0x8000; |
+ samples[(nsamples+xi)*_nchannels+ci]=s; |
+ } |
+ } |
+ nsamples+=nread; |
+ } |
+ *_samples=(float *)opus_realloc(samples, |
+ _nchannels*nsamples*sizeof(*samples)); |
+ return nsamples; |
+} |
+ |
+static void band_energy(float *_out,float *_ps,const int *_bands,int _nbands, |
+ const float *_in,int _nchannels,size_t _nframes,int _window_sz, |
+ int _step,int _downsample){ |
+ float *window; |
+ float *x; |
+ float *c; |
+ float *s; |
+ size_t xi; |
+ int xj; |
+ int ps_sz; |
+ window=(float *)opus_malloc((3+_nchannels)*_window_sz*sizeof(*window)); |
+ c=window+_window_sz; |
+ s=c+_window_sz; |
+ x=s+_window_sz; |
+ ps_sz=_window_sz/2; |
+ for(xj=0;xj<_window_sz;xj++){ |
+ window[xj]=0.5F-0.5F*OPUS_COSF((2*OPUS_PI/(_window_sz-1))*xj); |
+ } |
+ for(xj=0;xj<_window_sz;xj++){ |
+ c[xj]=OPUS_COSF((2*OPUS_PI/_window_sz)*xj); |
+ } |
+ for(xj=0;xj<_window_sz;xj++){ |
+ s[xj]=OPUS_SINF((2*OPUS_PI/_window_sz)*xj); |
+ } |
+ for(xi=0;xi<_nframes;xi++){ |
+ int ci; |
+ int xk; |
+ int bi; |
+ for(ci=0;ci<_nchannels;ci++){ |
+ for(xk=0;xk<_window_sz;xk++){ |
+ x[ci*_window_sz+xk]=window[xk]*_in[(xi*_step+xk)*_nchannels+ci]; |
+ } |
+ } |
+ for(bi=xj=0;bi<_nbands;bi++){ |
+ float p[2]={0}; |
+ for(;xj<_bands[bi+1];xj++){ |
+ for(ci=0;ci<_nchannels;ci++){ |
+ float re; |
+ float im; |
+ int ti; |
+ ti=0; |
+ re=im=0; |
+ for(xk=0;xk<_window_sz;xk++){ |
+ re+=c[ti]*x[ci*_window_sz+xk]; |
+ im-=s[ti]*x[ci*_window_sz+xk]; |
+ ti+=xj; |
+ if(ti>=_window_sz)ti-=_window_sz; |
+ } |
+ re*=_downsample; |
+ im*=_downsample; |
+ _ps[(xi*ps_sz+xj)*_nchannels+ci]=re*re+im*im+100000; |
+ p[ci]+=_ps[(xi*ps_sz+xj)*_nchannels+ci]; |
+ } |
+ } |
+ if(_out){ |
+ _out[(xi*_nbands+bi)*_nchannels]=p[0]/(_bands[bi+1]-_bands[bi]); |
+ if(_nchannels==2){ |
+ _out[(xi*_nbands+bi)*_nchannels+1]=p[1]/(_bands[bi+1]-_bands[bi]); |
+ } |
+ } |
+ } |
+ } |
+ free(window); |
+} |
+ |
+#define NBANDS (21) |
+#define NFREQS (240) |
+ |
+/*Bands on which we compute the pseudo-NMR (Bark-derived |
+ CELT bands).*/ |
+static const int BANDS[NBANDS+1]={ |
+ 0,2,4,6,8,10,12,14,16,20,24,28,32,40,48,56,68,80,96,120,156,200 |
+}; |
+ |
+#define TEST_WIN_SIZE (480) |
+#define TEST_WIN_STEP (120) |
+ |
+int main(int _argc,const char **_argv){ |
+ FILE *fin1; |
+ FILE *fin2; |
+ float *x; |
+ float *y; |
+ float *xb; |
+ float *X; |
+ float *Y; |
+ double err; |
+ float Q; |
+ size_t xlength; |
+ size_t ylength; |
+ size_t nframes; |
+ size_t xi; |
+ int ci; |
+ int xj; |
+ int bi; |
+ int nchannels; |
+ unsigned rate; |
+ int downsample; |
+ int ybands; |
+ int yfreqs; |
+ int max_compare; |
+ if(_argc<3||_argc>6){ |
+ fprintf(stderr,"Usage: %s [-s] [-r rate2] <file1.sw> <file2.sw>\n", |
+ _argv[0]); |
+ return EXIT_FAILURE; |
+ } |
+ nchannels=1; |
+ if(strcmp(_argv[1],"-s")==0){ |
+ nchannels=2; |
+ _argv++; |
+ } |
+ rate=48000; |
+ ybands=NBANDS; |
+ yfreqs=NFREQS; |
+ downsample=1; |
+ if(strcmp(_argv[1],"-r")==0){ |
+ rate=atoi(_argv[2]); |
+ if(rate!=8000&&rate!=12000&&rate!=16000&&rate!=24000&&rate!=48000){ |
+ fprintf(stderr, |
+ "Sampling rate must be 8000, 12000, 16000, 24000, or 48000\n"); |
+ return EXIT_FAILURE; |
+ } |
+ downsample=48000/rate; |
+ switch(rate){ |
+ case 8000:ybands=13;break; |
+ case 12000:ybands=15;break; |
+ case 16000:ybands=17;break; |
+ case 24000:ybands=19;break; |
+ } |
+ yfreqs=NFREQS/downsample; |
+ _argv+=2; |
+ } |
+ fin1=fopen(_argv[1],"rb"); |
+ if(fin1==NULL){ |
+ fprintf(stderr,"Error opening '%s'.\n",_argv[1]); |
+ return EXIT_FAILURE; |
+ } |
+ fin2=fopen(_argv[2],"rb"); |
+ if(fin2==NULL){ |
+ fprintf(stderr,"Error opening '%s'.\n",_argv[2]); |
+ fclose(fin1); |
+ return EXIT_FAILURE; |
+ } |
+ /*Read in the data and allocate scratch space.*/ |
+ xlength=read_pcm16(&x,fin1,2); |
+ if(nchannels==1){ |
+ for(xi=0;xi<xlength;xi++)x[xi]=.5*(x[2*xi]+x[2*xi+1]); |
+ } |
+ fclose(fin1); |
+ ylength=read_pcm16(&y,fin2,nchannels); |
+ fclose(fin2); |
+ if(xlength!=ylength*downsample){ |
+ fprintf(stderr,"Sample counts do not match (%lu!=%lu).\n", |
+ (unsigned long)xlength,(unsigned long)ylength*downsample); |
+ return EXIT_FAILURE; |
+ } |
+ if(xlength<TEST_WIN_SIZE){ |
+ fprintf(stderr,"Insufficient sample data (%lu<%i).\n", |
+ (unsigned long)xlength,TEST_WIN_SIZE); |
+ return EXIT_FAILURE; |
+ } |
+ nframes=(xlength-TEST_WIN_SIZE+TEST_WIN_STEP)/TEST_WIN_STEP; |
+ xb=(float *)opus_malloc(nframes*NBANDS*nchannels*sizeof(*xb)); |
+ X=(float *)opus_malloc(nframes*NFREQS*nchannels*sizeof(*X)); |
+ Y=(float *)opus_malloc(nframes*yfreqs*nchannels*sizeof(*Y)); |
+ /*Compute the per-band spectral energy of the original signal |
+ and the error.*/ |
+ band_energy(xb,X,BANDS,NBANDS,x,nchannels,nframes, |
+ TEST_WIN_SIZE,TEST_WIN_STEP,1); |
+ free(x); |
+ band_energy(NULL,Y,BANDS,ybands,y,nchannels,nframes, |
+ TEST_WIN_SIZE/downsample,TEST_WIN_STEP/downsample,downsample); |
+ free(y); |
+ for(xi=0;xi<nframes;xi++){ |
+ /*Frequency masking (low to high): 10 dB/Bark slope.*/ |
+ for(bi=1;bi<NBANDS;bi++){ |
+ for(ci=0;ci<nchannels;ci++){ |
+ xb[(xi*NBANDS+bi)*nchannels+ci]+= |
+ 0.1F*xb[(xi*NBANDS+bi-1)*nchannels+ci]; |
+ } |
+ } |
+ /*Frequency masking (high to low): 15 dB/Bark slope.*/ |
+ for(bi=NBANDS-1;bi-->0;){ |
+ for(ci=0;ci<nchannels;ci++){ |
+ xb[(xi*NBANDS+bi)*nchannels+ci]+= |
+ 0.03F*xb[(xi*NBANDS+bi+1)*nchannels+ci]; |
+ } |
+ } |
+ if(xi>0){ |
+ /*Temporal masking: -3 dB/2.5ms slope.*/ |
+ for(bi=0;bi<NBANDS;bi++){ |
+ for(ci=0;ci<nchannels;ci++){ |
+ xb[(xi*NBANDS+bi)*nchannels+ci]+= |
+ 0.5F*xb[((xi-1)*NBANDS+bi)*nchannels+ci]; |
+ } |
+ } |
+ } |
+ /* Allowing some cross-talk */ |
+ if(nchannels==2){ |
+ for(bi=0;bi<NBANDS;bi++){ |
+ float l,r; |
+ l=xb[(xi*NBANDS+bi)*nchannels+0]; |
+ r=xb[(xi*NBANDS+bi)*nchannels+1]; |
+ xb[(xi*NBANDS+bi)*nchannels+0]+=0.01F*r; |
+ xb[(xi*NBANDS+bi)*nchannels+1]+=0.01F*l; |
+ } |
+ } |
+ |
+ /* Apply masking */ |
+ for(bi=0;bi<ybands;bi++){ |
+ for(xj=BANDS[bi];xj<BANDS[bi+1];xj++){ |
+ for(ci=0;ci<nchannels;ci++){ |
+ X[(xi*NFREQS+xj)*nchannels+ci]+= |
+ 0.1F*xb[(xi*NBANDS+bi)*nchannels+ci]; |
+ Y[(xi*yfreqs+xj)*nchannels+ci]+= |
+ 0.1F*xb[(xi*NBANDS+bi)*nchannels+ci]; |
+ } |
+ } |
+ } |
+ } |
+ |
+ /* Average of consecutive frames to make comparison slightly less sensitive */ |
+ for(bi=0;bi<ybands;bi++){ |
+ for(xj=BANDS[bi];xj<BANDS[bi+1];xj++){ |
+ for(ci=0;ci<nchannels;ci++){ |
+ float xtmp; |
+ float ytmp; |
+ xtmp = X[xj*nchannels+ci]; |
+ ytmp = Y[xj*nchannels+ci]; |
+ for(xi=1;xi<nframes;xi++){ |
+ float xtmp2; |
+ float ytmp2; |
+ xtmp2 = X[(xi*NFREQS+xj)*nchannels+ci]; |
+ ytmp2 = Y[(xi*yfreqs+xj)*nchannels+ci]; |
+ X[(xi*NFREQS+xj)*nchannels+ci] += xtmp; |
+ Y[(xi*yfreqs+xj)*nchannels+ci] += ytmp; |
+ xtmp = xtmp2; |
+ ytmp = ytmp2; |
+ } |
+ } |
+ } |
+ } |
+ |
+ /*If working at a lower sampling rate, don't take into account the last |
+ 300 Hz to allow for different transition bands. |
+ For 12 kHz, we don't skip anything, because the last band already skips |
+ 400 Hz.*/ |
+ if(rate==48000)max_compare=BANDS[NBANDS]; |
+ else if(rate==12000)max_compare=BANDS[ybands]; |
+ else max_compare=BANDS[ybands]-3; |
+ err=0; |
+ for(xi=0;xi<nframes;xi++){ |
+ double Ef; |
+ Ef=0; |
+ for(bi=0;bi<ybands;bi++){ |
+ double Eb; |
+ Eb=0; |
+ for(xj=BANDS[bi];xj<BANDS[bi+1]&&xj<max_compare;xj++){ |
+ for(ci=0;ci<nchannels;ci++){ |
+ float re; |
+ float im; |
+ re=Y[(xi*yfreqs+xj)*nchannels+ci]/X[(xi*NFREQS+xj)*nchannels+ci]; |
+ im=re-log(re)-1; |
+ /*Make comparison less sensitive around the SILK/CELT cross-over to |
+ allow for mode freedom in the filters.*/ |
+ if(xj>=79&&xj<=81)im*=0.1F; |
+ if(xj==80)im*=0.1F; |
+ Eb+=im; |
+ } |
+ } |
+ Eb /= (BANDS[bi+1]-BANDS[bi])*nchannels; |
+ Ef += Eb*Eb; |
+ } |
+ /*Using a fixed normalization value means we're willing to accept slightly |
+ lower quality for lower sampling rates.*/ |
+ Ef/=NBANDS; |
+ Ef*=Ef; |
+ err+=Ef*Ef; |
+ } |
+ err=pow(err/nframes,1.0/16); |
+ Q=100*(1-0.5*log(1+err)/log(1.13)); |
+ if(Q<0){ |
+ fprintf(stderr,"Test vector FAILS\n"); |
+ fprintf(stderr,"Internal weighted error is %f\n",err); |
+ return EXIT_FAILURE; |
+ } |
+ else{ |
+ fprintf(stderr,"Test vector PASSES\n"); |
+ fprintf(stderr, |
+ "Opus quality metric: %.1f %% (internal weighted error is %f)\n",Q,err); |
+ return EXIT_SUCCESS; |
+ } |
+} |