#include #include #include #include #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=_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] \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;xi0;){ for(ci=0;ci0){ /*Temporal masking: -3 dB/2.5ms slope.*/ for(bi=0;bi=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; } }