mirror of
				https://github.com/godotengine/godot.git
				synced 2025-11-04 07:31:16 +00:00 
			
		
		
		
	
		
			
	
	
		
			380 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			380 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| 
								 | 
							
								/* 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;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 |