X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=lib%2Fpsy.c;h=35df7e7da649ba1380492aa92952ad9999579f1b;hb=2770566085de55dadf051a737cde61be3dd28a8b;hp=1b9b5fb6c00a634c2074a9edf25d20a21eba4612;hpb=f6246535ae25ac62560acecb35036dd4239a95d5;p=platform%2Fupstream%2Flibvorbis.git diff --git a/lib/psy.c b/lib/psy.c index 1b9b5fb..35df7e7 100644 --- a/lib/psy.c +++ b/lib/psy.c @@ -1,171 +1,723 @@ /******************************************************************** * * - * THIS FILE IS PART OF THE Ogg Vorbis SOFTWARE CODEC SOURCE CODE. * + * THIS FILE IS PART OF THE OggVorbis 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 GNU LESSER/LIBRARY PUBLIC LICENSE, WHICH IS INCLUDED WITH * + * THIS SOURCE. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * * * - * THE OggSQUISH SOURCE CODE IS (C) COPYRIGHT 1994-2000 * - * by Monty and The XIPHOPHORUS Company * + * THE OggVorbis 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.15 2000/02/06 13:39:44 xiphmont Exp $ + last mod: $Id: psy.c,v 1.40 2001/02/02 02:52:34 xiphmont Exp $ ********************************************************************/ #include #include #include -#include #include "vorbis/codec.h" +#include "codec_internal.h" +#include "masking.h" #include "psy.h" +#include "os.h" #include "lpc.h" #include "smallft.h" #include "scales.h" +#include "misc.h" -/* Set up decibel threshhold slopes on a Bark frequency scale */ +#define NEGINF -9999.f -static void set_curve(double *ref,double *c,int n, double crate){ +/* 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)); + _ogg_free(i); + } +} + +vorbis_info_psy *_vi_psy_copy(vorbis_info_psy *i){ + vorbis_info_psy *ret=_ogg_malloc(sizeof(vorbis_info_psy)); + memcpy(ret,i,sizeof(vorbis_info_psy)); + return(ret); +} + +/* Set up decibel threshold 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(float *ref,float *c,int n, float crate){ int i,j=0; for(i=0;ic[i])c[i]=c2[i]; +} + +static void attenuate_curve(float *c,float att){ + int i; + for(i=0;i-200.f)break; + c[j][0]=i; + + for(i=EHMER_MAX-1;i>=0;i--) + if(c[j][i+2]>-200.f) + break; + c[j][1]=i; + + } +} + void _vp_psy_init(vorbis_look_psy *p,vorbis_info_psy *vi,int n,long rate){ - long i; + long i,j; + long maxoc; memset(p,0,sizeof(vorbis_look_psy)); - p->maskthresh=malloc(n*sizeof(double)); - p->barknum=malloc(n*sizeof(double)); + + + p->eighth_octave_lines=vi->eighth_octave_lines; + p->shiftoc=rint(log(vi->eighth_octave_lines*8)/log(2))-1; + + p->firstoc=toOC(.25f*rate/n)*(1<<(p->shiftoc+1))-vi->eighth_octave_lines; + maxoc=toOC((n*.5f-.25f)*rate/n)*(1<<(p->shiftoc+1))+.5f; + p->total_octave_lines=maxoc-p->firstoc+1; + + p->ath=_ogg_malloc(n*sizeof(float)); + p->octave=_ogg_malloc(n*sizeof(int)); + p->bark=_ogg_malloc(n*sizeof(float)); 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(vi->maskthresh, p->maskthresh, n,rate); + /* Vorbis max sample rate is currently limited by 26 Bark (54kHz) */ + set_curve(ATH_Bark_dB, p->ath,n,rate); + for(i=0;ibark[i]=toBARK(rate/(2*n)*i); for(i=0;ibarknum[i]=toBARK(rate/2.*i/n); + p->octave[i]=toOC((i*.5f+.25f)*rate/n)*(1<<(p->shiftoc+1))+.5f; -#ifdef ANALYSIS - { - int j; - FILE *out; - char buffer[80]; - - sprintf(buffer,"mask_threshhold_%d.m",n); - out=fopen(buffer,"w+"); - for(j=0;jmaskthresh[j]); - fclose(out); + p->tonecurves=_ogg_malloc(P_BANDS*sizeof(float **)); + p->noisemedian=_ogg_malloc(n*sizeof(float)); + p->noiseoffset=_ogg_malloc(n*sizeof(float)); + p->peakatt=_ogg_malloc(P_BANDS*sizeof(float *)); + for(i=0;itonecurves[i]=_ogg_malloc(P_LEVELS*sizeof(float *)); + p->peakatt[i]=_ogg_malloc(P_LEVELS*sizeof(float)); } -#endif + for(i=0;itonecurves[i][j]=_ogg_malloc((EHMER_MAX+2)*sizeof(float)); + } + + /* OK, yeah, this was a silly way to do it */ + memcpy(p->tonecurves[0][4]+2,tone_125_40dB_SL,sizeof(float)*EHMER_MAX); + memcpy(p->tonecurves[0][6]+2,tone_125_60dB_SL,sizeof(float)*EHMER_MAX); + memcpy(p->tonecurves[0][8]+2,tone_125_80dB_SL,sizeof(float)*EHMER_MAX); + memcpy(p->tonecurves[0][10]+2,tone_125_100dB_SL,sizeof(float)*EHMER_MAX); + + memcpy(p->tonecurves[2][4]+2,tone_125_40dB_SL,sizeof(float)*EHMER_MAX); + memcpy(p->tonecurves[2][6]+2,tone_125_60dB_SL,sizeof(float)*EHMER_MAX); + memcpy(p->tonecurves[2][8]+2,tone_125_80dB_SL,sizeof(float)*EHMER_MAX); + memcpy(p->tonecurves[2][10]+2,tone_125_100dB_SL,sizeof(float)*EHMER_MAX); + + memcpy(p->tonecurves[4][4]+2,tone_250_40dB_SL,sizeof(float)*EHMER_MAX); + memcpy(p->tonecurves[4][6]+2,tone_250_60dB_SL,sizeof(float)*EHMER_MAX); + memcpy(p->tonecurves[4][8]+2,tone_250_80dB_SL,sizeof(float)*EHMER_MAX); + memcpy(p->tonecurves[4][10]+2,tone_250_100dB_SL,sizeof(float)*EHMER_MAX); + + memcpy(p->tonecurves[6][4]+2,tone_500_40dB_SL,sizeof(float)*EHMER_MAX); + memcpy(p->tonecurves[6][6]+2,tone_500_60dB_SL,sizeof(float)*EHMER_MAX); + memcpy(p->tonecurves[6][8]+2,tone_500_80dB_SL,sizeof(float)*EHMER_MAX); + memcpy(p->tonecurves[6][10]+2,tone_500_100dB_SL,sizeof(float)*EHMER_MAX); + + memcpy(p->tonecurves[8][4]+2,tone_1000_40dB_SL,sizeof(float)*EHMER_MAX); + memcpy(p->tonecurves[8][6]+2,tone_1000_60dB_SL,sizeof(float)*EHMER_MAX); + memcpy(p->tonecurves[8][8]+2,tone_1000_80dB_SL,sizeof(float)*EHMER_MAX); + memcpy(p->tonecurves[8][10]+2,tone_1000_100dB_SL,sizeof(float)*EHMER_MAX); + + memcpy(p->tonecurves[10][4]+2,tone_2000_40dB_SL,sizeof(float)*EHMER_MAX); + memcpy(p->tonecurves[10][6]+2,tone_2000_60dB_SL,sizeof(float)*EHMER_MAX); + memcpy(p->tonecurves[10][8]+2,tone_2000_80dB_SL,sizeof(float)*EHMER_MAX); + memcpy(p->tonecurves[10][10]+2,tone_2000_100dB_SL,sizeof(float)*EHMER_MAX); + + memcpy(p->tonecurves[12][4]+2,tone_4000_40dB_SL,sizeof(float)*EHMER_MAX); + memcpy(p->tonecurves[12][6]+2,tone_4000_60dB_SL,sizeof(float)*EHMER_MAX); + memcpy(p->tonecurves[12][8]+2,tone_4000_80dB_SL,sizeof(float)*EHMER_MAX); + memcpy(p->tonecurves[12][10]+2,tone_4000_100dB_SL,sizeof(float)*EHMER_MAX); + + memcpy(p->tonecurves[14][4]+2,tone_8000_40dB_SL,sizeof(float)*EHMER_MAX); + memcpy(p->tonecurves[14][6]+2,tone_8000_60dB_SL,sizeof(float)*EHMER_MAX); + memcpy(p->tonecurves[14][8]+2,tone_8000_80dB_SL,sizeof(float)*EHMER_MAX); + memcpy(p->tonecurves[14][10]+2,tone_8000_100dB_SL,sizeof(float)*EHMER_MAX); + + memcpy(p->tonecurves[16][4]+2,tone_8000_40dB_SL,sizeof(float)*EHMER_MAX); + memcpy(p->tonecurves[16][6]+2,tone_8000_60dB_SL,sizeof(float)*EHMER_MAX); + memcpy(p->tonecurves[16][8]+2,tone_8000_80dB_SL,sizeof(float)*EHMER_MAX); + memcpy(p->tonecurves[16][10]+2,tone_8000_100dB_SL,sizeof(float)*EHMER_MAX); + + /* interpolate curves between */ + for(i=1;itonecurves[i][j]+2,p->tonecurves[i-1][j]+2,EHMER_MAX*sizeof(float)); + /*interp_curve(p->tonecurves[i][j], + p->tonecurves[i-1][j], + p->tonecurves[i+1][j],.5);*/ + min_curve(p->tonecurves[i][j]+2,p->tonecurves[i+1][j]+2); + } + + /* set up the final curves */ + for(i=0;itonecurves[i],i,vi->toneatt[i]); + + /* set up attenuation levels */ + for(i=0;ipeakatt[i][j]=p->vi->peakatt[i][j]; + } + + /* set up rolling noise median */ + for(i=0;i=P_BANDS-1)halfoc=P_BANDS-1; + inthalfoc=(int)halfoc; + del=halfoc-inthalfoc; + + p->noisemedian[i]= + p->vi->noisemedian[inthalfoc*2]*(1.-del) + + p->vi->noisemedian[inthalfoc*2+2]*del; + p->noiseoffset[i]= + p->vi->noisemedian[inthalfoc*2+1]*(1.-del) + + p->vi->noisemedian[inthalfoc*2+3]*del; + } + /*_analysis_output("mediancurve",0,p->noisemedian,n,0,0);*/ } void _vp_psy_clear(vorbis_look_psy *p){ + int i,j; if(p){ - if(p->maskthresh)free(p->maskthresh); - if(p->barknum)free(p->barknum); + if(p->ath)_ogg_free(p->ath); + if(p->octave)_ogg_free(p->octave); + if(p->bark)_ogg_free(p->bark); + if(p->tonecurves){ + for(i=0;itonecurves[i][j]); + } + _ogg_free(p->tonecurves[i]); + _ogg_free(p->peakatt[i]); + } + _ogg_free(p->tonecurves); + _ogg_free(p->noisemedian); + _ogg_free(p->noiseoffset); + _ogg_free(p->peakatt); + } memset(p,0,sizeof(vorbis_look_psy)); } } -/* Masking curve: linear rolloff on a Bark/dB scale, attenuated by - maskthresh */ -/* right now, floor==mask */ -void _vp_mask_floor(vorbis_look_psy *p,double *f, double *mask,double *floor){ - int n=p->n; - double hroll=p->vi->hrolldB; - double lroll=p->vi->lrolldB; - double curmask=todB(f[0])+p->maskthresh[0]; - double curoc=0.; - long i; +/* octave/(8*eighth_octave_lines) x scale and dB y scale */ +static void seed_curve(float *seed, + float **curves, + float amp, + int oc,int n,int linesper,float dBoffset){ + int i; + long seedptr; + float *posts,*curve; + + int choice=(int)((amp+dBoffset)*.1f); + choice=max(choice,0); + choice=min(choice,P_LEVELS-1); + posts=curves[choice]; + curve=posts+2; + seedptr=oc+(posts[0]-16)*linesper-(linesper>>1); + + for(i=posts[0];i0){ + float lin=amp+curve[i]; + if(seed[seedptr]=n)break; + } +} + +static void seed_peak(float *seed, + float *att, + float amp, + int oc, + int linesper, + float dBoffset){ + long seedptr; + + int choice=(int)((amp+dBoffset)*.1f); + choice=max(choice,0); + choice=min(choice,P_LEVELS-1); + seedptr=oc-(linesper>>1); + + amp+=att[choice]; + if(seed[seedptr]vi; + long n=p->n,i; + float dBoffset=vi->max_curve_dB-specmax; + + /* prime the working vector with peak values */ + + for(i=0;ioctave[i]; + while(i+1octave[i+1]==oc){ + i++; + if(f[i]>max)max=f[i]; + } + + if(max>flr[i]){ + oc=oc>>p->shiftoc; + if(oc>=P_BANDS)oc=P_BANDS-1; + if(oc<0)oc=0; + if(vi->tonemaskp) + seed_curve(minseed, + curves[oc], + max, + p->octave[i]-p->firstoc, + p->total_octave_lines, + p->eighth_octave_lines, + dBoffset); + if(vi->peakattp) + seed_peak(maxseed, + att[oc], + max, + p->octave[i]-p->firstoc, + p->eighth_octave_lines, + dBoffset); + } + } +} + +static void bound_loop(vorbis_look_psy *p, + float *f, + float *seeds, + float *flr, + float att){ + long n=p->n,i; + + long off=(p->eighth_octave_lines>>1)+p->firstoc; + long *ocp=p->octave; + + for(i=0;imaskthresh[i]; - double newoc=p->barknum[i]; - double roll=curmask-(newoc-curoc)*hroll; - double troll; - if(newmask>roll){ - roll=curmask=newmask; - curoc=newoc; + if(stack<2){ + posstack[stack]=i; + ampstack[stack++]=seeds[i]; + }else{ + while(1){ + if(seeds[i]1 && ampstack[stack-1]<=ampstack[stack-2] && + imaskthresh[n-1]; - curoc=p->barknum[n-1]; - for(i=n-1;i>=0;i--){ - double newmask=todB(f[i])+p->maskthresh[i]; - double newoc=p->barknum[i]; - double roll=curmask-(curoc-newoc)*lroll; - double troll; - if(newmask>roll){ - roll=curmask=newmask; - curoc=newoc; + } + + /* the stack now contains only the positions that are relevant. Scan + 'em straight through */ + + for(i=0;iampstack[i]){ + endpos=posstack[i+1]; + }else{ + endpos=posstack[i]+linesper+1; /* +1 is important, else bin 0 is + discarded in short frames */ } - troll=fromdB(roll); - if(mask[i]n)endpos=n; + for(;postotal_octave_lines; + int linesper=p->eighth_octave_lines; + long linpos=0; + long pos; -/* modifies the pcm vector, returns book membership in aux */ + seed_chase(minseed,linesper,n); /* for masking */ + seed_chase(maxseed,linesper,n); /* for peak att */ + + pos=p->octave[0]-p->firstoc-(linesper>>1); + while(linpos+1n){ + float min=minseed[pos]; + float max=maxseed[pos]; + long end=((p->octave[linpos]+p->octave[linpos+1])>>1)-p->firstoc; + while(pos+1<=end){ + pos++; + if((minseed[pos]>NEGINF && minseed[pos]max)max=maxseed[pos]; + } + if(maxfirstoc; + for(;linposn && p->octave[linpos]<=end;linpos++) + if(flr[linpos]total_octave_lines-1]; + float max=maxseed[p->total_octave_lines-1]; + if(maxn;linpos++) + if(flr[linpos]15)value=15; - if(value<-15)value=-15; - pcm[i]=value; + memset(radix,0,sizeof(radix)); + + for(i=0;iLASTBIN)bin=LASTBIN; + if(bin<0)bin=0; + radix[bin]++; + if(binLASTBIN)bin=LASTBIN; + if(bin<0)bin=0; + radix[bin]--; + if(bincountbelow && median>0){ + median--; + countabove-=radix[median]; + countbelow+=radix[median]; + } + + while(threshi<(countbelow-radix[median]) && + mediann; + float localmax=NEGINF; + static int seq=0; + + float *minseed=alloca(sizeof(float)*p->total_octave_lines); + float *maxseed=alloca(sizeof(float)*p->total_octave_lines); + for(i=0;itotal_octave_lines;i++)minseed[i]=maxseed[i]=NEGINF; + + /* go to dB scale. Also find the highest peak so we know the limits */ for(i=0;ilocalmax)localmax=fft[i]; + } + if(specmaxvi->noisemaskp){ + bark_noise_median(n,p->bark,mdct,flr, + p->vi->noisewindowlo, + p->vi->noisewindowhi, + p->vi->noisewindowlomin, + p->vi->noisewindowhimin, + p->noisemedian, + p->noiseoffset); + /* suppress any noise curve > specmax+p->vi->noisemaxsupp */ + for(i=0;ispecmax+p->vi->noisemaxsupp) + flr[i]=specmax+p->vi->noisemaxsupp; + _analysis_output("noise",seq,flr,n,0,0); + }else{ + for(i=0;ivi->athp){ + float att=localmax+p->vi->ath_adjatt; + if(attvi->ath_maxatt)att=p->vi->ath_maxatt; + + for(i=0;iath[i]+att; + if(av>flr[i])flr[i]=av; + } + } + + _analysis_output("ath",seq,flr,n,0,0); + + /* tone/peak masking */ + + /* XXX apply decay to the fft here */ + + seed_loop(p,p->tonecurves,p->peakatt,fft,flr,minseed,maxseed,specmax); + bound_loop(p,mdct,maxseed,flr,p->vi->bound_att_dB); + _analysis_output("minseed",seq,minseed,p->total_octave_lines,0,0); + _analysis_output("maxseed",seq,maxseed,p->total_octave_lines,0,0); + max_seeds(p,minseed,maxseed,flr); + _analysis_output("final",seq,flr,n,0,0); + + /* doing this here is clean, but we need to find a faster way to do + it than to just tack it on */ + + for(i=0;i=flr[i])break; + if(i==n)for(i=0;in*sizeof(float)); + int j; + + /* subtract the floor */ + for(j=0;jn;j++){ + if(flr[j]<=0) + work[j]=0.f; + else + work[j]=f[j]/flr[j]; } + + memcpy(f,work,p->n*sizeof(float)); } + +float _vp_ampmax_decay(float amp,vorbis_dsp_state *vd){ + vorbis_info *vi=vd->vi; + codec_setup_info *ci=vi->codec_setup; + int n=ci->blocksizes[vd->W]/2; + float secs=(float)n/vi->rate; + + amp+=secs*ci->ampmax_att_per_sec; + if(amp<-9999)amp=-9999; + return(amp); +} + + +