/******************************************************************** * * * THIS FILE IS PART OF THE Ogg Vorbis SOFTWARE CODEC SOURCE CODE. * * USE, DISTRIBUTION AND REPRODUCTION OF THIS SOURCE IS GOVERNED BY * * THE GNU PUBLIC LICENSE 2, WHICH IS INCLUDED WITH THIS SOURCE. * * PLEASE READ THESE TERMS DISTRIBUTING. * * * * THE OggSQUISH SOURCE CODE IS (C) COPYRIGHT 1994-2000 * * by Monty and The XIPHOPHORUS Company * * http://www.xiph.org/ * * * ******************************************************************** function: psychoacoustics not including preecho last mod: $Id: psy.c,v 1.24 2000/08/15 09:09:43 xiphmont Exp $ ********************************************************************/ #include #include #include #include "vorbis/codec.h" #include "masking.h" #include "psy.h" #include "os.h" #include "lpc.h" #include "smallft.h" #include "scales.h" #include "misc.h" /* Why Bark scale for encoding but not masking computation? Because masking has a strong harmonic dependancy */ /* the beginnings of real psychoacoustic infrastructure. This is still not tightly tuned */ void _vi_psy_free(vorbis_info_psy *i){ if(i){ memset(i,0,sizeof(vorbis_info_psy)); free(i); } } /* Set up decibel threshhold slopes on a Bark frequency scale */ /* ATH is the only bit left on a Bark scale. No reason to change it right now */ static void set_curve(double *ref,double *c,int n, double crate){ int i,j=0; for(i=0;ic[i])c[i]=c2[i]; } static void attenuate_curve(double *c,double att){ int i; for(i=0;i0;i--){ for(j=0;jath=malloc(n*sizeof(double)); p->octave=malloc(n*sizeof(int)); p->bark=malloc(n*sizeof(double)); p->vi=vi; p->n=n; /* set up the lookups for a given blocksize and sample rate */ /* Vorbis max sample rate is limited by 26 Bark (54kHz) */ set_curve(ATH_Bark_dB, p->ath,n,rate); for(i=0;iath[i]=fromdB(p->ath[i]); for(i=0;ibark[i]=toBARK(rate/(2*n)*i); for(i=0;i=P_BANDS)oc=P_BANDS-1; p->octave[i]=oc; } p->tonecurves=malloc(P_BANDS*sizeof(double **)); p->noiseatt=malloc(P_BANDS*sizeof(double **)); p->peakatt=malloc(P_BANDS*sizeof(double *)); for(i=0;itonecurves[i]=malloc(P_LEVELS*sizeof(double *)); p->noiseatt[i]=malloc(P_LEVELS*sizeof(double)); p->peakatt[i]=malloc(P_LEVELS*sizeof(double)); } for(i=0;itonecurves[i][j]=malloc(EHMER_MAX*sizeof(double)); } /* OK, yeah, this was a silly way to do it */ memcpy(p->tonecurves[0][4],tone_125_40dB_SL,sizeof(double)*EHMER_MAX); memcpy(p->tonecurves[0][6],tone_125_60dB_SL,sizeof(double)*EHMER_MAX); memcpy(p->tonecurves[0][8],tone_125_80dB_SL,sizeof(double)*EHMER_MAX); memcpy(p->tonecurves[0][10],tone_125_100dB_SL,sizeof(double)*EHMER_MAX); memcpy(p->tonecurves[2][4],tone_125_40dB_SL,sizeof(double)*EHMER_MAX); memcpy(p->tonecurves[2][6],tone_125_60dB_SL,sizeof(double)*EHMER_MAX); memcpy(p->tonecurves[2][8],tone_125_80dB_SL,sizeof(double)*EHMER_MAX); memcpy(p->tonecurves[2][10],tone_125_100dB_SL,sizeof(double)*EHMER_MAX); memcpy(p->tonecurves[4][4],tone_250_40dB_SL,sizeof(double)*EHMER_MAX); memcpy(p->tonecurves[4][6],tone_250_60dB_SL,sizeof(double)*EHMER_MAX); memcpy(p->tonecurves[4][8],tone_250_80dB_SL,sizeof(double)*EHMER_MAX); memcpy(p->tonecurves[4][10],tone_250_100dB_SL,sizeof(double)*EHMER_MAX); memcpy(p->tonecurves[6][4],tone_500_40dB_SL,sizeof(double)*EHMER_MAX); memcpy(p->tonecurves[6][6],tone_500_60dB_SL,sizeof(double)*EHMER_MAX); memcpy(p->tonecurves[6][8],tone_500_80dB_SL,sizeof(double)*EHMER_MAX); memcpy(p->tonecurves[6][10],tone_500_100dB_SL,sizeof(double)*EHMER_MAX); memcpy(p->tonecurves[8][4],tone_1000_40dB_SL,sizeof(double)*EHMER_MAX); memcpy(p->tonecurves[8][6],tone_1000_60dB_SL,sizeof(double)*EHMER_MAX); memcpy(p->tonecurves[8][8],tone_1000_80dB_SL,sizeof(double)*EHMER_MAX); memcpy(p->tonecurves[8][10],tone_1000_100dB_SL,sizeof(double)*EHMER_MAX); memcpy(p->tonecurves[10][4],tone_2000_40dB_SL,sizeof(double)*EHMER_MAX); memcpy(p->tonecurves[10][6],tone_2000_60dB_SL,sizeof(double)*EHMER_MAX); memcpy(p->tonecurves[10][8],tone_2000_80dB_SL,sizeof(double)*EHMER_MAX); memcpy(p->tonecurves[10][10],tone_2000_100dB_SL,sizeof(double)*EHMER_MAX); memcpy(p->tonecurves[12][4],tone_4000_40dB_SL,sizeof(double)*EHMER_MAX); memcpy(p->tonecurves[12][6],tone_4000_60dB_SL,sizeof(double)*EHMER_MAX); memcpy(p->tonecurves[12][8],tone_4000_80dB_SL,sizeof(double)*EHMER_MAX); memcpy(p->tonecurves[12][10],tone_4000_100dB_SL,sizeof(double)*EHMER_MAX); memcpy(p->tonecurves[14][4],tone_8000_40dB_SL,sizeof(double)*EHMER_MAX); memcpy(p->tonecurves[14][6],tone_8000_60dB_SL,sizeof(double)*EHMER_MAX); memcpy(p->tonecurves[14][8],tone_8000_80dB_SL,sizeof(double)*EHMER_MAX); memcpy(p->tonecurves[14][10],tone_8000_100dB_SL,sizeof(double)*EHMER_MAX); memcpy(p->tonecurves[16][4],tone_8000_40dB_SL,sizeof(double)*EHMER_MAX); memcpy(p->tonecurves[16][6],tone_8000_60dB_SL,sizeof(double)*EHMER_MAX); memcpy(p->tonecurves[16][8],tone_8000_80dB_SL,sizeof(double)*EHMER_MAX); memcpy(p->tonecurves[16][10],tone_8000_100dB_SL,sizeof(double)*EHMER_MAX); /* interpolate curves between */ for(i=1;itonecurves[i][j],p->tonecurves[i-1][j],EHMER_MAX*sizeof(double)); /*interp_curve(p->tonecurves[i][j], p->tonecurves[i-1][j], p->tonecurves[i+1][j],.5);*/ min_curve(p->tonecurves[i][j],p->tonecurves[i+1][j]); /*min_curve(p->tonecurves[i][j],p->tonecurves[i-1][j]);*/ } /*for(i=0;itonecurves[i][j],p->tonecurves[i+1][j]);*/ /* set up the final curves */ for(i=0;itonecurves[i],i,vi->toneatt[i]); /* set up attenuation levels */ for(i=0;ipeakatt[i][j]=fromdB(p->vi->peakatt[i][j]); p->noiseatt[i][j]=fromdB(p->vi->noiseatt[i][j]); } } void _vp_psy_clear(vorbis_look_psy *p){ int i,j; if(p){ if(p->ath)free(p->ath); if(p->octave)free(p->octave); if(p->tonecurves){ for(i=0;itonecurves[i][j]); } free(p->noiseatt[i]); free(p->tonecurves[i]); free(p->peakatt[i]); } free(p->tonecurves); free(p->noiseatt); free(p->peakatt); } memset(p,0,sizeof(vorbis_look_psy)); } } static void compute_decay_fixed(vorbis_look_psy *p,double *f, double *decay, int n){ /* handle decay */ int i; double decscale=fromdB(p->vi->decay_coeff*n); double attscale=1./fromdB(p->vi->attack_coeff); static int frameno=0; for(i=0;iattscale) decay[i]=fabs(f[i]/attscale); else decay[i]=val; }else{ decay[i]=fabs(f[i]/attscale); } if(pre>f[i])f[i]=pre; } } static long _eights[EHMER_MAX+1]={ 981,1069,1166,1272, 1387,1512,1649,1798, 1961,2139,2332,2543, 2774,3025,3298,3597, 3922,4277,4664,5087, 5547,6049,6597,7194, 7845,8555,9329,10173, 11094,12098,13193,14387, 15689,17109,18658,20347, 22188,24196,26386,28774, 31379,34219,37316,40693, 44376,48393,52772,57549, 62757,68437,74631,81386, 88752,96785,105545,115097, 125515}; static int seed_curve(double *flr, double **curves, double amp,double specmax, int x,int n,double specatt, int maxEH){ int i; double *curve; /* make this attenuation adjustable */ int choice=(int)((todB(amp)-specmax+specatt)/10.+.5); choice=max(choice,0); choice=min(choice,P_LEVELS-1); for(i=maxEH;i>=0;i--) if(((x*_eights[i])>>12)=0;i--) if(curve[i]>0.)break; for(;i>=0;i--){ double lin=curve[i]; if(lin>0.){ double *fp=flr+((x*_eights[i])>>12); lin*=amp; if(*fp>12; /* make this attenuation adjustable */ int choice=rint((todB(amp)-specmax+specatt)/10.+.5); if(choice<0)choice=0; if(choice>=P_LEVELS)choice=P_LEVELS-1; if(prevxvi; long n=p->n,i; int maxEH=EHMER_MAX-1; /* prime the working vector with peak values */ /* Use the 125 Hz curve up to 125 Hz and 8kHz curve after 8kHz. */ for(i=0;iflr[i]) maxEH=seed_curve(seeds,curves[p->octave[i]], f[i],specmax,i,n,vi->max_curve_dB,maxEH); } static void seed_att(vorbis_look_psy *p, double **att, double *f, double *flr, double specmax){ vorbis_info_psy *vi=p->vi; long n=p->n,i; for(i=0;iflr[i]) seed_peak(flr,att[p->octave[i]],f[i], specmax,i,n,vi->max_curve_dB); } static void seed_point(vorbis_look_psy *p, double **att, double *f, double *flr, double specmax){ vorbis_info_psy *vi=p->vi; long n=p->n,i; for(i=0;imax_curve_dB)/10.+.5); double lin; if(choice<0)choice=0; if(choice>=P_LEVELS)choice=P_LEVELS-1; lin=att[p->octave[i]][choice]*f[i]; if(flr[i]n,i,j; long *posstack=alloca(n*sizeof(long)); double *ampstack=alloca(n*sizeof(double)); long stack=0; for(i=0;i1 && ampstack[stack-1]ampstack[i]){ endpos=posstack[i+1]; }else{ endpos=posstack[i]*1.0905077080+1; /* +1 is important, else bin 0 is discarded in short frames */ } if(endpos>n)endpos=n; for(j=pos;jn); int i,n=p->n; double specmax=0.; double *seed=alloca(sizeof(double)*p->n); double *seed2=alloca(sizeof(double)*p->n); memset(flr,0,n*sizeof(double)); /* noise masking */ if(p->vi->noisemaskp){ memset(seed,0,n*sizeof(double)); bark_noise(n,p->bark,f,seed); seed_point(p,p->noiseatt,seed,flr,specmax); } /* smooth the data is that's called for ********************************/ for(i=0;ivi->smoothp){ /* compute power^.5 of three neighboring bins to smooth for peaks that get split twixt bins/peaks that nail the bin. This evens out treatment as we're not doing additive masking any longer. */ double acc=smooth[0]*smooth[0]+smooth[1]*smooth[1]; double prev=smooth[0]; smooth[0]=sqrt(acc); for(i=1;ispecmax)specmax=smooth[i]; } specmax=todB(specmax); /* set the ATH (floating below specmax by a specified att) */ if(p->vi->athp){ double att=specmax+p->vi->ath_adjatt; if(attvi->ath_maxatt)att=p->vi->ath_maxatt; att=fromdB(att); for(i=0;iath[i]*att; if(av>flr[i])flr[i]=av; } } /* peak attenuation ******/ if(p->vi->peakattp){ memset(seed,0,n*sizeof(double)); seed_att(p,p->peakatt,smooth,seed,specmax); max_seeds(p,seed,flr); } /* tone masking */ if(p->vi->tonemaskp){ memset(seed,0,n*sizeof(double)); memset(seed2,0,n*sizeof(double)); seed_generic(p,p->tonecurves,smooth,flr,seed2,specmax); max_seeds(p,seed2,seed2); for(i=0;itonecurves,smooth,seed2,seed,specmax); max_seeds(p,seed,seed); if(p->vi->decayp) compute_decay_fixed(p,seed,decay,n); for(i=0;in*sizeof(double)); int i,j,addcount=0; /* subtract the floor */ for(j=0;jn;j++){ if(flr[j]<=0) work[j]=0.; else work[j]=f[j]/flr[j]; } memcpy(f,work,p->n*sizeof(double)); }