xref: /aosp_15_r20/external/libopus/src/opus_compare.c (revision a58d3d2adb790c104798cd88c8a3aff4fa8b82cc)
1*a58d3d2aSXin Li /* Copyright (c) 2011-2012 Xiph.Org Foundation, Mozilla Corporation
2*a58d3d2aSXin Li    Written by Jean-Marc Valin and Timothy B. Terriberry */
3*a58d3d2aSXin Li /*
4*a58d3d2aSXin Li    Redistribution and use in source and binary forms, with or without
5*a58d3d2aSXin Li    modification, are permitted provided that the following conditions
6*a58d3d2aSXin Li    are met:
7*a58d3d2aSXin Li 
8*a58d3d2aSXin Li    - Redistributions of source code must retain the above copyright
9*a58d3d2aSXin Li    notice, this list of conditions and the following disclaimer.
10*a58d3d2aSXin Li 
11*a58d3d2aSXin Li    - Redistributions in binary form must reproduce the above copyright
12*a58d3d2aSXin Li    notice, this list of conditions and the following disclaimer in the
13*a58d3d2aSXin Li    documentation and/or other materials provided with the distribution.
14*a58d3d2aSXin Li 
15*a58d3d2aSXin Li    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16*a58d3d2aSXin Li    ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17*a58d3d2aSXin Li    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18*a58d3d2aSXin Li    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
19*a58d3d2aSXin Li    OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20*a58d3d2aSXin Li    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21*a58d3d2aSXin Li    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22*a58d3d2aSXin Li    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23*a58d3d2aSXin Li    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24*a58d3d2aSXin Li    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25*a58d3d2aSXin Li    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*a58d3d2aSXin Li */
27*a58d3d2aSXin Li 
28*a58d3d2aSXin Li #include <stdio.h>
29*a58d3d2aSXin Li #include <stdlib.h>
30*a58d3d2aSXin Li #include <math.h>
31*a58d3d2aSXin Li #include <string.h>
32*a58d3d2aSXin Li 
33*a58d3d2aSXin Li #define OPUS_PI (3.14159265F)
34*a58d3d2aSXin Li 
35*a58d3d2aSXin Li #define OPUS_COSF(_x)        ((float)cos(_x))
36*a58d3d2aSXin Li #define OPUS_SINF(_x)        ((float)sin(_x))
37*a58d3d2aSXin Li 
check_alloc(void * _ptr)38*a58d3d2aSXin Li static void *check_alloc(void *_ptr){
39*a58d3d2aSXin Li   if(_ptr==NULL){
40*a58d3d2aSXin Li     fprintf(stderr,"Out of memory.\n");
41*a58d3d2aSXin Li     exit(EXIT_FAILURE);
42*a58d3d2aSXin Li   }
43*a58d3d2aSXin Li   return _ptr;
44*a58d3d2aSXin Li }
45*a58d3d2aSXin Li 
opus_malloc(size_t _size)46*a58d3d2aSXin Li static void *opus_malloc(size_t _size){
47*a58d3d2aSXin Li   return check_alloc(malloc(_size));
48*a58d3d2aSXin Li }
49*a58d3d2aSXin Li 
opus_realloc(void * _ptr,size_t _size)50*a58d3d2aSXin Li static void *opus_realloc(void *_ptr,size_t _size){
51*a58d3d2aSXin Li   return check_alloc(realloc(_ptr,_size));
52*a58d3d2aSXin Li }
53*a58d3d2aSXin Li 
read_pcm16(float ** _samples,FILE * _fin,int _nchannels)54*a58d3d2aSXin Li static size_t read_pcm16(float **_samples,FILE *_fin,int _nchannels){
55*a58d3d2aSXin Li   unsigned char  buf[1024];
56*a58d3d2aSXin Li   float         *samples;
57*a58d3d2aSXin Li   size_t         nsamples;
58*a58d3d2aSXin Li   size_t         csamples;
59*a58d3d2aSXin Li   size_t         xi;
60*a58d3d2aSXin Li   size_t         nread;
61*a58d3d2aSXin Li   samples=NULL;
62*a58d3d2aSXin Li   nsamples=csamples=0;
63*a58d3d2aSXin Li   for(;;){
64*a58d3d2aSXin Li     nread=fread(buf,2*_nchannels,1024/(2*_nchannels),_fin);
65*a58d3d2aSXin Li     if(nread<=0)break;
66*a58d3d2aSXin Li     if(nsamples+nread>csamples){
67*a58d3d2aSXin Li       do csamples=csamples<<1|1;
68*a58d3d2aSXin Li       while(nsamples+nread>csamples);
69*a58d3d2aSXin Li       samples=(float *)opus_realloc(samples,
70*a58d3d2aSXin Li        _nchannels*csamples*sizeof(*samples));
71*a58d3d2aSXin Li     }
72*a58d3d2aSXin Li     for(xi=0;xi<nread;xi++){
73*a58d3d2aSXin Li       int ci;
74*a58d3d2aSXin Li       for(ci=0;ci<_nchannels;ci++){
75*a58d3d2aSXin Li         int s;
76*a58d3d2aSXin Li         s=buf[2*(xi*_nchannels+ci)+1]<<8|buf[2*(xi*_nchannels+ci)];
77*a58d3d2aSXin Li         s=((s&0xFFFF)^0x8000)-0x8000;
78*a58d3d2aSXin Li         samples[(nsamples+xi)*_nchannels+ci]=s;
79*a58d3d2aSXin Li       }
80*a58d3d2aSXin Li     }
81*a58d3d2aSXin Li     nsamples+=nread;
82*a58d3d2aSXin Li   }
83*a58d3d2aSXin Li   *_samples=(float *)opus_realloc(samples,
84*a58d3d2aSXin Li    _nchannels*nsamples*sizeof(*samples));
85*a58d3d2aSXin Li   return nsamples;
86*a58d3d2aSXin Li }
87*a58d3d2aSXin Li 
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)88*a58d3d2aSXin Li static void band_energy(float *_out,float *_ps,const int *_bands,int _nbands,
89*a58d3d2aSXin Li  const float *_in,int _nchannels,size_t _nframes,int _window_sz,
90*a58d3d2aSXin Li  int _step,int _downsample){
91*a58d3d2aSXin Li   float *window;
92*a58d3d2aSXin Li   float *x;
93*a58d3d2aSXin Li   float *c;
94*a58d3d2aSXin Li   float *s;
95*a58d3d2aSXin Li   size_t xi;
96*a58d3d2aSXin Li   int    xj;
97*a58d3d2aSXin Li   int    ps_sz;
98*a58d3d2aSXin Li   window=(float *)opus_malloc((3+_nchannels)*_window_sz*sizeof(*window));
99*a58d3d2aSXin Li   c=window+_window_sz;
100*a58d3d2aSXin Li   s=c+_window_sz;
101*a58d3d2aSXin Li   x=s+_window_sz;
102*a58d3d2aSXin Li   ps_sz=_window_sz/2;
103*a58d3d2aSXin Li   for(xj=0;xj<_window_sz;xj++){
104*a58d3d2aSXin Li     window[xj]=0.5F-0.5F*OPUS_COSF((2*OPUS_PI/(_window_sz-1))*xj);
105*a58d3d2aSXin Li   }
106*a58d3d2aSXin Li   for(xj=0;xj<_window_sz;xj++){
107*a58d3d2aSXin Li     c[xj]=OPUS_COSF((2*OPUS_PI/_window_sz)*xj);
108*a58d3d2aSXin Li   }
109*a58d3d2aSXin Li   for(xj=0;xj<_window_sz;xj++){
110*a58d3d2aSXin Li     s[xj]=OPUS_SINF((2*OPUS_PI/_window_sz)*xj);
111*a58d3d2aSXin Li   }
112*a58d3d2aSXin Li   for(xi=0;xi<_nframes;xi++){
113*a58d3d2aSXin Li     int ci;
114*a58d3d2aSXin Li     int xk;
115*a58d3d2aSXin Li     int bi;
116*a58d3d2aSXin Li     for(ci=0;ci<_nchannels;ci++){
117*a58d3d2aSXin Li       for(xk=0;xk<_window_sz;xk++){
118*a58d3d2aSXin Li         x[ci*_window_sz+xk]=window[xk]*_in[(xi*_step+xk)*_nchannels+ci];
119*a58d3d2aSXin Li       }
120*a58d3d2aSXin Li     }
121*a58d3d2aSXin Li     for(bi=xj=0;bi<_nbands;bi++){
122*a58d3d2aSXin Li       float p[2]={0};
123*a58d3d2aSXin Li       for(;xj<_bands[bi+1];xj++){
124*a58d3d2aSXin Li         for(ci=0;ci<_nchannels;ci++){
125*a58d3d2aSXin Li           float re;
126*a58d3d2aSXin Li           float im;
127*a58d3d2aSXin Li           int   ti;
128*a58d3d2aSXin Li           ti=0;
129*a58d3d2aSXin Li           re=im=0;
130*a58d3d2aSXin Li           for(xk=0;xk<_window_sz;xk++){
131*a58d3d2aSXin Li             re+=c[ti]*x[ci*_window_sz+xk];
132*a58d3d2aSXin Li             im-=s[ti]*x[ci*_window_sz+xk];
133*a58d3d2aSXin Li             ti+=xj;
134*a58d3d2aSXin Li             if(ti>=_window_sz)ti-=_window_sz;
135*a58d3d2aSXin Li           }
136*a58d3d2aSXin Li           re*=_downsample;
137*a58d3d2aSXin Li           im*=_downsample;
138*a58d3d2aSXin Li           _ps[(xi*ps_sz+xj)*_nchannels+ci]=re*re+im*im+100000;
139*a58d3d2aSXin Li           p[ci]+=_ps[(xi*ps_sz+xj)*_nchannels+ci];
140*a58d3d2aSXin Li         }
141*a58d3d2aSXin Li       }
142*a58d3d2aSXin Li       if(_out){
143*a58d3d2aSXin Li         _out[(xi*_nbands+bi)*_nchannels]=p[0]/(_bands[bi+1]-_bands[bi]);
144*a58d3d2aSXin Li         if(_nchannels==2){
145*a58d3d2aSXin Li           _out[(xi*_nbands+bi)*_nchannels+1]=p[1]/(_bands[bi+1]-_bands[bi]);
146*a58d3d2aSXin Li         }
147*a58d3d2aSXin Li       }
148*a58d3d2aSXin Li     }
149*a58d3d2aSXin Li   }
150*a58d3d2aSXin Li   free(window);
151*a58d3d2aSXin Li }
152*a58d3d2aSXin Li 
153*a58d3d2aSXin Li #define NBANDS (21)
154*a58d3d2aSXin Li #define NFREQS (240)
155*a58d3d2aSXin Li 
156*a58d3d2aSXin Li /*Bands on which we compute the pseudo-NMR (Bark-derived
157*a58d3d2aSXin Li   CELT bands).*/
158*a58d3d2aSXin Li static const int BANDS[NBANDS+1]={
159*a58d3d2aSXin Li   0,2,4,6,8,10,12,14,16,20,24,28,32,40,48,56,68,80,96,120,156,200
160*a58d3d2aSXin Li };
161*a58d3d2aSXin Li 
162*a58d3d2aSXin Li #define TEST_WIN_SIZE (480)
163*a58d3d2aSXin Li #define TEST_WIN_STEP (120)
164*a58d3d2aSXin Li 
main(int _argc,const char ** _argv)165*a58d3d2aSXin Li int main(int _argc,const char **_argv){
166*a58d3d2aSXin Li   FILE    *fin1;
167*a58d3d2aSXin Li   FILE    *fin2;
168*a58d3d2aSXin Li   float   *x;
169*a58d3d2aSXin Li   float   *y;
170*a58d3d2aSXin Li   float   *xb;
171*a58d3d2aSXin Li   float   *X;
172*a58d3d2aSXin Li   float   *Y;
173*a58d3d2aSXin Li   double    err;
174*a58d3d2aSXin Li   float    Q;
175*a58d3d2aSXin Li   size_t   xlength;
176*a58d3d2aSXin Li   size_t   ylength;
177*a58d3d2aSXin Li   size_t   nframes;
178*a58d3d2aSXin Li   size_t   xi;
179*a58d3d2aSXin Li   int      ci;
180*a58d3d2aSXin Li   int      xj;
181*a58d3d2aSXin Li   int      bi;
182*a58d3d2aSXin Li   int      nchannels;
183*a58d3d2aSXin Li   unsigned rate;
184*a58d3d2aSXin Li   int      downsample;
185*a58d3d2aSXin Li   int      ybands;
186*a58d3d2aSXin Li   int      yfreqs;
187*a58d3d2aSXin Li   int      max_compare;
188*a58d3d2aSXin Li   if(_argc<3||_argc>6){
189*a58d3d2aSXin Li     fprintf(stderr,"Usage: %s [-s] [-r rate2] <file1.sw> <file2.sw>\n",
190*a58d3d2aSXin Li      _argv[0]);
191*a58d3d2aSXin Li     return EXIT_FAILURE;
192*a58d3d2aSXin Li   }
193*a58d3d2aSXin Li   nchannels=1;
194*a58d3d2aSXin Li   if(strcmp(_argv[1],"-s")==0){
195*a58d3d2aSXin Li     nchannels=2;
196*a58d3d2aSXin Li     _argv++;
197*a58d3d2aSXin Li   }
198*a58d3d2aSXin Li   rate=48000;
199*a58d3d2aSXin Li   ybands=NBANDS;
200*a58d3d2aSXin Li   yfreqs=NFREQS;
201*a58d3d2aSXin Li   downsample=1;
202*a58d3d2aSXin Li   if(strcmp(_argv[1],"-r")==0){
203*a58d3d2aSXin Li     rate=atoi(_argv[2]);
204*a58d3d2aSXin Li     if(rate!=8000&&rate!=12000&&rate!=16000&&rate!=24000&&rate!=48000){
205*a58d3d2aSXin Li       fprintf(stderr,
206*a58d3d2aSXin Li        "Sampling rate must be 8000, 12000, 16000, 24000, or 48000\n");
207*a58d3d2aSXin Li       return EXIT_FAILURE;
208*a58d3d2aSXin Li     }
209*a58d3d2aSXin Li     downsample=48000/rate;
210*a58d3d2aSXin Li     switch(rate){
211*a58d3d2aSXin Li       case  8000:ybands=13;break;
212*a58d3d2aSXin Li       case 12000:ybands=15;break;
213*a58d3d2aSXin Li       case 16000:ybands=17;break;
214*a58d3d2aSXin Li       case 24000:ybands=19;break;
215*a58d3d2aSXin Li     }
216*a58d3d2aSXin Li     yfreqs=NFREQS/downsample;
217*a58d3d2aSXin Li     _argv+=2;
218*a58d3d2aSXin Li   }
219*a58d3d2aSXin Li   fin1=fopen(_argv[1],"rb");
220*a58d3d2aSXin Li   if(fin1==NULL){
221*a58d3d2aSXin Li     fprintf(stderr,"Error opening '%s'.\n",_argv[1]);
222*a58d3d2aSXin Li     return EXIT_FAILURE;
223*a58d3d2aSXin Li   }
224*a58d3d2aSXin Li   fin2=fopen(_argv[2],"rb");
225*a58d3d2aSXin Li   if(fin2==NULL){
226*a58d3d2aSXin Li     fprintf(stderr,"Error opening '%s'.\n",_argv[2]);
227*a58d3d2aSXin Li     fclose(fin1);
228*a58d3d2aSXin Li     return EXIT_FAILURE;
229*a58d3d2aSXin Li   }
230*a58d3d2aSXin Li   /*Read in the data and allocate scratch space.*/
231*a58d3d2aSXin Li   xlength=read_pcm16(&x,fin1,2);
232*a58d3d2aSXin Li   if(nchannels==1){
233*a58d3d2aSXin Li     for(xi=0;xi<xlength;xi++)x[xi]=.5*(x[2*xi]+x[2*xi+1]);
234*a58d3d2aSXin Li   }
235*a58d3d2aSXin Li   fclose(fin1);
236*a58d3d2aSXin Li   ylength=read_pcm16(&y,fin2,nchannels);
237*a58d3d2aSXin Li   fclose(fin2);
238*a58d3d2aSXin Li   if(xlength!=ylength*downsample){
239*a58d3d2aSXin Li     fprintf(stderr,"Sample counts do not match (%lu!=%lu).\n",
240*a58d3d2aSXin Li      (unsigned long)xlength,(unsigned long)ylength*downsample);
241*a58d3d2aSXin Li     return EXIT_FAILURE;
242*a58d3d2aSXin Li   }
243*a58d3d2aSXin Li   if(xlength<TEST_WIN_SIZE){
244*a58d3d2aSXin Li     fprintf(stderr,"Insufficient sample data (%lu<%i).\n",
245*a58d3d2aSXin Li      (unsigned long)xlength,TEST_WIN_SIZE);
246*a58d3d2aSXin Li     return EXIT_FAILURE;
247*a58d3d2aSXin Li   }
248*a58d3d2aSXin Li   nframes=(xlength-TEST_WIN_SIZE+TEST_WIN_STEP)/TEST_WIN_STEP;
249*a58d3d2aSXin Li   xb=(float *)opus_malloc(nframes*NBANDS*nchannels*sizeof(*xb));
250*a58d3d2aSXin Li   X=(float *)opus_malloc(nframes*NFREQS*nchannels*sizeof(*X));
251*a58d3d2aSXin Li   Y=(float *)opus_malloc(nframes*yfreqs*nchannels*sizeof(*Y));
252*a58d3d2aSXin Li   /*Compute the per-band spectral energy of the original signal
253*a58d3d2aSXin Li      and the error.*/
254*a58d3d2aSXin Li   band_energy(xb,X,BANDS,NBANDS,x,nchannels,nframes,
255*a58d3d2aSXin Li    TEST_WIN_SIZE,TEST_WIN_STEP,1);
256*a58d3d2aSXin Li   free(x);
257*a58d3d2aSXin Li   band_energy(NULL,Y,BANDS,ybands,y,nchannels,nframes,
258*a58d3d2aSXin Li    TEST_WIN_SIZE/downsample,TEST_WIN_STEP/downsample,downsample);
259*a58d3d2aSXin Li   free(y);
260*a58d3d2aSXin Li   for(xi=0;xi<nframes;xi++){
261*a58d3d2aSXin Li     /*Frequency masking (low to high): 10 dB/Bark slope.*/
262*a58d3d2aSXin Li     for(bi=1;bi<NBANDS;bi++){
263*a58d3d2aSXin Li       for(ci=0;ci<nchannels;ci++){
264*a58d3d2aSXin Li         xb[(xi*NBANDS+bi)*nchannels+ci]+=
265*a58d3d2aSXin Li          0.1F*xb[(xi*NBANDS+bi-1)*nchannels+ci];
266*a58d3d2aSXin Li       }
267*a58d3d2aSXin Li     }
268*a58d3d2aSXin Li     /*Frequency masking (high to low): 15 dB/Bark slope.*/
269*a58d3d2aSXin Li     for(bi=NBANDS-1;bi-->0;){
270*a58d3d2aSXin Li       for(ci=0;ci<nchannels;ci++){
271*a58d3d2aSXin Li         xb[(xi*NBANDS+bi)*nchannels+ci]+=
272*a58d3d2aSXin Li          0.03F*xb[(xi*NBANDS+bi+1)*nchannels+ci];
273*a58d3d2aSXin Li       }
274*a58d3d2aSXin Li     }
275*a58d3d2aSXin Li     if(xi>0){
276*a58d3d2aSXin Li       /*Temporal masking: -3 dB/2.5ms slope.*/
277*a58d3d2aSXin Li       for(bi=0;bi<NBANDS;bi++){
278*a58d3d2aSXin Li         for(ci=0;ci<nchannels;ci++){
279*a58d3d2aSXin Li           xb[(xi*NBANDS+bi)*nchannels+ci]+=
280*a58d3d2aSXin Li            0.5F*xb[((xi-1)*NBANDS+bi)*nchannels+ci];
281*a58d3d2aSXin Li         }
282*a58d3d2aSXin Li       }
283*a58d3d2aSXin Li     }
284*a58d3d2aSXin Li     /* Allowing some cross-talk */
285*a58d3d2aSXin Li     if(nchannels==2){
286*a58d3d2aSXin Li       for(bi=0;bi<NBANDS;bi++){
287*a58d3d2aSXin Li         float l,r;
288*a58d3d2aSXin Li         l=xb[(xi*NBANDS+bi)*nchannels+0];
289*a58d3d2aSXin Li         r=xb[(xi*NBANDS+bi)*nchannels+1];
290*a58d3d2aSXin Li         xb[(xi*NBANDS+bi)*nchannels+0]+=0.01F*r;
291*a58d3d2aSXin Li         xb[(xi*NBANDS+bi)*nchannels+1]+=0.01F*l;
292*a58d3d2aSXin Li       }
293*a58d3d2aSXin Li     }
294*a58d3d2aSXin Li 
295*a58d3d2aSXin Li     /* Apply masking */
296*a58d3d2aSXin Li     for(bi=0;bi<ybands;bi++){
297*a58d3d2aSXin Li       for(xj=BANDS[bi];xj<BANDS[bi+1];xj++){
298*a58d3d2aSXin Li         for(ci=0;ci<nchannels;ci++){
299*a58d3d2aSXin Li           X[(xi*NFREQS+xj)*nchannels+ci]+=
300*a58d3d2aSXin Li            0.1F*xb[(xi*NBANDS+bi)*nchannels+ci];
301*a58d3d2aSXin Li           Y[(xi*yfreqs+xj)*nchannels+ci]+=
302*a58d3d2aSXin Li            0.1F*xb[(xi*NBANDS+bi)*nchannels+ci];
303*a58d3d2aSXin Li         }
304*a58d3d2aSXin Li       }
305*a58d3d2aSXin Li     }
306*a58d3d2aSXin Li   }
307*a58d3d2aSXin Li 
308*a58d3d2aSXin Li   /* Average of consecutive frames to make comparison slightly less sensitive */
309*a58d3d2aSXin Li   for(bi=0;bi<ybands;bi++){
310*a58d3d2aSXin Li     for(xj=BANDS[bi];xj<BANDS[bi+1];xj++){
311*a58d3d2aSXin Li       for(ci=0;ci<nchannels;ci++){
312*a58d3d2aSXin Li          float xtmp;
313*a58d3d2aSXin Li          float ytmp;
314*a58d3d2aSXin Li          xtmp = X[xj*nchannels+ci];
315*a58d3d2aSXin Li          ytmp = Y[xj*nchannels+ci];
316*a58d3d2aSXin Li          for(xi=1;xi<nframes;xi++){
317*a58d3d2aSXin Li            float xtmp2;
318*a58d3d2aSXin Li            float ytmp2;
319*a58d3d2aSXin Li            xtmp2 = X[(xi*NFREQS+xj)*nchannels+ci];
320*a58d3d2aSXin Li            ytmp2 = Y[(xi*yfreqs+xj)*nchannels+ci];
321*a58d3d2aSXin Li            X[(xi*NFREQS+xj)*nchannels+ci] += xtmp;
322*a58d3d2aSXin Li            Y[(xi*yfreqs+xj)*nchannels+ci] += ytmp;
323*a58d3d2aSXin Li            xtmp = xtmp2;
324*a58d3d2aSXin Li            ytmp = ytmp2;
325*a58d3d2aSXin Li          }
326*a58d3d2aSXin Li       }
327*a58d3d2aSXin Li     }
328*a58d3d2aSXin Li   }
329*a58d3d2aSXin Li 
330*a58d3d2aSXin Li   /*If working at a lower sampling rate, don't take into account the last
331*a58d3d2aSXin Li      300 Hz to allow for different transition bands.
332*a58d3d2aSXin Li     For 12 kHz, we don't skip anything, because the last band already skips
333*a58d3d2aSXin Li      400 Hz.*/
334*a58d3d2aSXin Li   if(rate==48000)max_compare=BANDS[NBANDS];
335*a58d3d2aSXin Li   else if(rate==12000)max_compare=BANDS[ybands];
336*a58d3d2aSXin Li   else max_compare=BANDS[ybands]-3;
337*a58d3d2aSXin Li   err=0;
338*a58d3d2aSXin Li   for(xi=0;xi<nframes;xi++){
339*a58d3d2aSXin Li     double Ef;
340*a58d3d2aSXin Li     Ef=0;
341*a58d3d2aSXin Li     for(bi=0;bi<ybands;bi++){
342*a58d3d2aSXin Li       double Eb;
343*a58d3d2aSXin Li       Eb=0;
344*a58d3d2aSXin Li       for(xj=BANDS[bi];xj<BANDS[bi+1]&&xj<max_compare;xj++){
345*a58d3d2aSXin Li         for(ci=0;ci<nchannels;ci++){
346*a58d3d2aSXin Li           float re;
347*a58d3d2aSXin Li           float im;
348*a58d3d2aSXin Li           re=Y[(xi*yfreqs+xj)*nchannels+ci]/X[(xi*NFREQS+xj)*nchannels+ci];
349*a58d3d2aSXin Li           im=re-log(re)-1;
350*a58d3d2aSXin Li           /*Make comparison less sensitive around the SILK/CELT cross-over to
351*a58d3d2aSXin Li             allow for mode freedom in the filters.*/
352*a58d3d2aSXin Li           if(xj>=79&&xj<=81)im*=0.1F;
353*a58d3d2aSXin Li           if(xj==80)im*=0.1F;
354*a58d3d2aSXin Li           Eb+=im;
355*a58d3d2aSXin Li         }
356*a58d3d2aSXin Li       }
357*a58d3d2aSXin Li       Eb /= (BANDS[bi+1]-BANDS[bi])*nchannels;
358*a58d3d2aSXin Li       Ef += Eb*Eb;
359*a58d3d2aSXin Li     }
360*a58d3d2aSXin Li     /*Using a fixed normalization value means we're willing to accept slightly
361*a58d3d2aSXin Li        lower quality for lower sampling rates.*/
362*a58d3d2aSXin Li     Ef/=NBANDS;
363*a58d3d2aSXin Li     Ef*=Ef;
364*a58d3d2aSXin Li     err+=Ef*Ef;
365*a58d3d2aSXin Li   }
366*a58d3d2aSXin Li   free(xb);
367*a58d3d2aSXin Li   free(X);
368*a58d3d2aSXin Li   free(Y);
369*a58d3d2aSXin Li   err=pow(err/nframes,1.0/16);
370*a58d3d2aSXin Li   Q=100*(1-0.5*log(1+err)/log(1.13));
371*a58d3d2aSXin Li   if(Q<0){
372*a58d3d2aSXin Li     fprintf(stderr,"Test vector FAILS\n");
373*a58d3d2aSXin Li     fprintf(stderr,"Internal weighted error is %f\n",err);
374*a58d3d2aSXin Li     return EXIT_FAILURE;
375*a58d3d2aSXin Li   }
376*a58d3d2aSXin Li   else{
377*a58d3d2aSXin Li     fprintf(stderr,"Test vector PASSES\n");
378*a58d3d2aSXin Li     fprintf(stderr,
379*a58d3d2aSXin Li      "Opus quality metric: %.1f %% (internal weighted error is %f)\n",Q,err);
380*a58d3d2aSXin Li     return EXIT_SUCCESS;
381*a58d3d2aSXin Li   }
382*a58d3d2aSXin Li }
383