psy.c
来自「在x86平台上运行不可信任代码的sandbox。」· C语言 代码 · 共 1,149 行 · 第 1/2 页
C
1,149 行
/******************************************************************** * * * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * * * * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002 * * by the XIPHOPHORUS Company http://www.xiph.org/ * * * ******************************************************************** function: psychoacoustics not including preecho last mod: $Id: psy.c 1919 2005-07-24 14:18:04Z baford $ ********************************************************************/#include <stdlib.h>#include <math.h>#include <string.h>#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"#define NEGINF -9999.fstatic double stereo_threshholds[]={0.0, .5, 1.0, 1.5, 2.5, 4.5, 8.5, 16.5, 9e10};vorbis_look_psy_global *_vp_global_look(vorbis_info *vi){ codec_setup_info *ci=vi->codec_setup; vorbis_info_psy_global *gi=&ci->psy_g_param; vorbis_look_psy_global *look=_ogg_calloc(1,sizeof(*look)); look->channels=vi->channels; look->ampmax=-9999.; look->gi=gi; return(look);}void _vp_global_free(vorbis_look_psy_global *look){ if(look){ memset(look,0,sizeof(*look)); _ogg_free(look); }}void _vi_gpsy_free(vorbis_info_psy_global *i){ if(i){ memset(i,0,sizeof(*i)); _ogg_free(i); }}void _vi_psy_free(vorbis_info_psy *i){ if(i){ memset(i,0,sizeof(*i)); _ogg_free(i); }}static void min_curve(float *c, float *c2){ int i; for(i=0;i<EHMER_MAX;i++)if(c2[i]<c[i])c[i]=c2[i];}static void max_curve(float *c, float *c2){ int i; for(i=0;i<EHMER_MAX;i++)if(c2[i]>c[i])c[i]=c2[i];}static void attenuate_curve(float *c,float att){ int i; for(i=0;i<EHMER_MAX;i++) c[i]+=att;}static float ***setup_tone_curves(float curveatt_dB[P_BANDS],float binHz,int n, float center_boost, float center_decay_rate){ int i,j,k,m; float ath[EHMER_MAX]; float workc[P_BANDS][P_LEVELS][EHMER_MAX]; float athc[P_LEVELS][EHMER_MAX]; float *brute_buffer=alloca(n*sizeof(*brute_buffer)); float ***ret=_ogg_malloc(sizeof(*ret)*P_BANDS); memset(workc,0,sizeof(workc)); for(i=0;i<P_BANDS;i++){ /* we add back in the ATH to avoid low level curves falling off to -infinity and unnecessarily cutting off high level curves in the curve limiting (last step). */ /* A half-band's settings must be valid over the whole band, and it's better to mask too little than too much */ int ath_offset=i*4; for(j=0;j<EHMER_MAX;j++){ float min=999.; for(k=0;k<4;k++) if(j+k+ath_offset<MAX_ATH){ if(min>ATH[j+k+ath_offset])min=ATH[j+k+ath_offset]; }else{ if(min>ATH[MAX_ATH-1])min=ATH[MAX_ATH-1]; } ath[j]=min; } /* copy curves into working space, replicate the 50dB curve to 30 and 40, replicate the 100dB curve to 110 */ for(j=0;j<6;j++) memcpy(workc[i][j+2],tonemasks[i][j],EHMER_MAX*sizeof(*tonemasks[i][j])); memcpy(workc[i][0],tonemasks[i][0],EHMER_MAX*sizeof(*tonemasks[i][0])); memcpy(workc[i][1],tonemasks[i][0],EHMER_MAX*sizeof(*tonemasks[i][0])); /* apply centered curve boost/decay */ for(j=0;j<P_LEVELS;j++){ for(k=0;k<EHMER_MAX;k++){ float adj=center_boost+abs(EHMER_OFFSET-k)*center_decay_rate; if(adj<0. && center_boost>0)adj=0.; if(adj>0. && center_boost<0)adj=0.; workc[i][j][k]+=adj; } } /* normalize curves so the driving amplitude is 0dB */ /* make temp curves with the ATH overlayed */ for(j=0;j<P_LEVELS;j++){ attenuate_curve(workc[i][j],curveatt_dB[i]+100.-(j<2?2:j)*10.-P_LEVEL_0); memcpy(athc[j],ath,EHMER_MAX*sizeof(**athc)); attenuate_curve(athc[j],+100.-j*10.f-P_LEVEL_0); max_curve(athc[j],workc[i][j]); } /* Now limit the louder curves. the idea is this: We don't know what the playback attenuation will be; 0dB SL moves every time the user twiddles the volume knob. So that means we have to use a single 'most pessimal' curve for all masking amplitudes, right? Wrong. The *loudest* sound can be in (we assume) a range of ...+100dB] SL. However, sounds 20dB down will be in a range ...+80], 40dB down is from ...+60], etc... */ for(j=1;j<P_LEVELS;j++){ min_curve(athc[j],athc[j-1]); min_curve(workc[i][j],athc[j]); } } for(i=0;i<P_BANDS;i++){ int hi_curve,lo_curve,bin; ret[i]=_ogg_malloc(sizeof(**ret)*P_LEVELS); /* low frequency curves are measured with greater resolution than the MDCT/FFT will actually give us; we want the curve applied to the tone data to be pessimistic and thus apply the minimum masking possible for a given bin. That means that a single bin could span more than one octave and that the curve will be a composite of multiple octaves. It also may mean that a single bin may span > an eighth of an octave and that the eighth octave values may also be composited. */ /* which octave curves will we be compositing? */ bin=floor(fromOC(i*.5)/binHz); lo_curve= ceil(toOC(bin*binHz+1)*2); hi_curve= floor(toOC((bin+1)*binHz)*2); if(lo_curve>i)lo_curve=i; if(lo_curve<0)lo_curve=0; if(hi_curve>=P_BANDS)hi_curve=P_BANDS-1; for(m=0;m<P_LEVELS;m++){ ret[i][m]=_ogg_malloc(sizeof(***ret)*(EHMER_MAX+2)); for(j=0;j<n;j++)brute_buffer[j]=999.; /* render the curve into bins, then pull values back into curve. The point is that any inherent subsampling aliasing results in a safe minimum */ for(k=lo_curve;k<=hi_curve;k++){ int l=0; for(j=0;j<EHMER_MAX;j++){ int lo_bin= fromOC(j*.125+k*.5-2.0625)/binHz; int hi_bin= fromOC(j*.125+k*.5-1.9375)/binHz+1; if(lo_bin<0)lo_bin=0; if(lo_bin>n)lo_bin=n; if(lo_bin<l)l=lo_bin; if(hi_bin<0)hi_bin=0; if(hi_bin>n)hi_bin=n; for(;l<hi_bin && l<n;l++) if(brute_buffer[l]>workc[k][m][j]) brute_buffer[l]=workc[k][m][j]; } for(;l<n;l++) if(brute_buffer[l]>workc[k][m][EHMER_MAX-1]) brute_buffer[l]=workc[k][m][EHMER_MAX-1]; } /* be equally paranoid about being valid up to next half ocatve */ if(i+1<P_BANDS){ int l=0; k=i+1; for(j=0;j<EHMER_MAX;j++){ int lo_bin= fromOC(j*.125+i*.5-2.0625)/binHz; int hi_bin= fromOC(j*.125+i*.5-1.9375)/binHz+1; if(lo_bin<0)lo_bin=0; if(lo_bin>n)lo_bin=n; if(lo_bin<l)l=lo_bin; if(hi_bin<0)hi_bin=0; if(hi_bin>n)hi_bin=n; for(;l<hi_bin && l<n;l++) if(brute_buffer[l]>workc[k][m][j]) brute_buffer[l]=workc[k][m][j]; } for(;l<n;l++) if(brute_buffer[l]>workc[k][m][EHMER_MAX-1]) brute_buffer[l]=workc[k][m][EHMER_MAX-1]; } for(j=0;j<EHMER_MAX;j++){ int bin=fromOC(j*.125+i*.5-2.)/binHz; if(bin<0){ ret[i][m][j+2]=-999.; }else{ if(bin>=n){ ret[i][m][j+2]=-999.; }else{ ret[i][m][j+2]=brute_buffer[bin]; } } } /* add fenceposts */ for(j=0;j<EHMER_OFFSET;j++) if(ret[i][m][j+2]>-200.f)break; ret[i][m][0]=j; for(j=EHMER_MAX-1;j>EHMER_OFFSET+1;j--) if(ret[i][m][j+2]>-200.f) break; ret[i][m][1]=j; } } return(ret);}void _vp_psy_init(vorbis_look_psy *p,vorbis_info_psy *vi, vorbis_info_psy_global *gi,int n,long rate){ long i,j,lo=-99,hi=1; long maxoc; memset(p,0,sizeof(*p)); p->eighth_octave_lines=gi->eighth_octave_lines; p->shiftoc=rint(log(gi->eighth_octave_lines*8.f)/log(2.f))-1; p->firstoc=toOC(.25f*rate*.5/n)*(1<<(p->shiftoc+1))-gi->eighth_octave_lines; maxoc=toOC((n+.25f)*rate*.5/n)*(1<<(p->shiftoc+1))+.5f; p->total_octave_lines=maxoc-p->firstoc+1; p->ath=_ogg_malloc(n*sizeof(*p->ath)); p->octave=_ogg_malloc(n*sizeof(*p->octave)); p->bark=_ogg_malloc(n*sizeof(*p->bark)); p->vi=vi; p->n=n; p->rate=rate; /* set up the lookups for a given blocksize and sample rate */ for(i=0,j=0;i<MAX_ATH-1;i++){ int endpos=rint(fromOC((i+1)*.125-2.)*2*n/rate); float base=ATH[i]; if(j<endpos){ float delta=(ATH[i+1]-base)/(endpos-j); for(;j<endpos && j<n;j++){ p->ath[j]=base+100.; base+=delta; } } } for(i=0;i<n;i++){ float bark=toBARK(rate/(2*n)*i); for(;lo+vi->noisewindowlomin<i && toBARK(rate/(2*n)*lo)<(bark-vi->noisewindowlo);lo++); for(;hi<=n && (hi<i+vi->noisewindowhimin || toBARK(rate/(2*n)*hi)<(bark+vi->noisewindowhi));hi++); p->bark[i]=((lo-1)<<16)+(hi-1); } for(i=0;i<n;i++) p->octave[i]=toOC((i+.25f)*.5*rate/n)*(1<<(p->shiftoc+1))+.5f; p->tonecurves=setup_tone_curves(vi->toneatt,rate*.5/n,n, vi->tone_centerboost,vi->tone_decay); /* set up rolling noise median */ p->noiseoffset=_ogg_malloc(P_NOISECURVES*sizeof(*p->noiseoffset)); for(i=0;i<P_NOISECURVES;i++) p->noiseoffset[i]=_ogg_malloc(n*sizeof(**p->noiseoffset)); for(i=0;i<n;i++){ float halfoc=toOC((i+.5)*rate/(2.*n))*2.; int inthalfoc; float del; if(halfoc<0)halfoc=0; if(halfoc>=P_BANDS-1)halfoc=P_BANDS-1; inthalfoc=(int)halfoc; del=halfoc-inthalfoc; for(j=0;j<P_NOISECURVES;j++) p->noiseoffset[j][i]= p->vi->noiseoff[j][inthalfoc]*(1.-del) + p->vi->noiseoff[j][inthalfoc+1]*del; }#if 0 { static int ls=0; _analysis_output_always("noiseoff0",ls,p->noiseoffset[0],n,1,0,0); _analysis_output_always("noiseoff1",ls,p->noiseoffset[1],n,1,0,0); _analysis_output_always("noiseoff2",ls++,p->noiseoffset[2],n,1,0,0); }#endif}void _vp_psy_clear(vorbis_look_psy *p){ int i,j; if(p){ 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;i<P_BANDS;i++){ for(j=0;j<P_LEVELS;j++){ _ogg_free(p->tonecurves[i][j]); } _ogg_free(p->tonecurves[i]); } _ogg_free(p->tonecurves); } if(p->noiseoffset){ for(i=0;i<P_NOISECURVES;i++){ _ogg_free(p->noiseoffset[i]); } _ogg_free(p->noiseoffset); } memset(p,0,sizeof(*p)); }}/* octave/(8*eighth_octave_lines) x scale and dB y scale */static void seed_curve(float *seed, const float **curves, float amp, int oc, int n, int linesper,float dBoffset){ int i,post1; int seedptr; const float *posts,*curve; int choice=(int)((amp+dBoffset-P_LEVEL_0)*.1f); choice=max(choice,0); choice=min(choice,P_LEVELS-1); posts=curves[choice]; curve=posts+2; post1=(int)posts[1]; seedptr=oc+(posts[0]-EHMER_OFFSET)*linesper-(linesper>>1); for(i=posts[0];i<post1;i++){ if(seedptr>0){ float lin=amp+curve[i]; if(seed[seedptr]<lin)seed[seedptr]=lin; } seedptr+=linesper; if(seedptr>=n)break; }}static void seed_loop(vorbis_look_psy *p, const float ***curves, const float *f, const float *flr, float *seed, float specmax){ vorbis_info_psy *vi=p->vi; long n=p->n,i; float dBoffset=vi->max_curve_dB-specmax; /* prime the working vector with peak values */ for(i=0;i<n;i++){ float max=f[i]; long oc=p->octave[i]; while(i+1<n && p->octave[i+1]==oc){ i++; if(f[i]>max)max=f[i]; } if(max+6.f>flr[i]){ oc=oc>>p->shiftoc; if(oc>=P_BANDS)oc=P_BANDS-1; if(oc<0)oc=0; seed_curve(seed, curves[oc], max, p->octave[i]-p->firstoc, p->total_octave_lines, p->eighth_octave_lines, dBoffset); } }}static void seed_chase(float *seeds, int linesper, long n){ long *posstack=alloca(n*sizeof(*posstack)); float *ampstack=alloca(n*sizeof(*ampstack)); long stack=0; long pos=0; long i; for(i=0;i<n;i++){ if(stack<2){ posstack[stack]=i; ampstack[stack++]=seeds[i]; }else{ while(1){ if(seeds[i]<ampstack[stack-1]){ posstack[stack]=i; ampstack[stack++]=seeds[i]; break; }else{ if(i<posstack[stack-1]+linesper){ if(stack>1 && ampstack[stack-1]<=ampstack[stack-2] && i<posstack[stack-2]+linesper){ /* we completely overlap, making stack-1 irrelevant. pop it */ stack--; continue; } } posstack[stack]=i; ampstack[stack++]=seeds[i]; break; } } } } /* the stack now contains only the positions that are relevant. Scan 'em straight through */ for(i=0;i<stack;i++){ long endpos; if(i<stack-1 && ampstack[i+1]>ampstack[i]){ endpos=posstack[i+1]; }else{ endpos=posstack[i]+linesper+1; /* +1 is important, else bin 0 is discarded in short frames */ } if(endpos>n)endpos=n; for(;pos<endpos;pos++) seeds[pos]=ampstack[i]; } /* there. Linear time. I now remember this was on a problem set I had in Grad Skool... I didn't solve it at the time ;-) */}/* bleaugh, this is more complicated than it needs to be */#include<stdio.h>static void max_seeds(vorbis_look_psy *p, float *seed, float *flr){ long n=p->total_octave_lines; int linesper=p->eighth_octave_lines; long linpos=0; long pos; seed_chase(seed,linesper,n); /* for masking */ pos=p->octave[0]-p->firstoc-(linesper>>1); while(linpos+1<p->n){ float minV=seed[pos]; long end=((p->octave[linpos]+p->octave[linpos+1])>>1)-p->firstoc; if(minV>p->vi->tone_abs_limit)minV=p->vi->tone_abs_limit; while(pos+1<=end){ pos++; if((seed[pos]>NEGINF && seed[pos]<minV) || minV==NEGINF) minV=seed[pos]; } end=pos+p->firstoc; for(;linpos<p->n && p->octave[linpos]<=end;linpos++) if(flr[linpos]<minV)flr[linpos]=minV; } { float minV=seed[p->total_octave_lines-1]; for(;linpos<p->n;linpos++) if(flr[linpos]<minV)flr[linpos]=minV; } }static void bark_noise_hybridmp(int n,const long *b, const float *f, float *noise, const float offset, const int fixed){ float *N=alloca(n*sizeof(*N)); float *X=alloca(n*sizeof(*N)); float *XX=alloca(n*sizeof(*N)); float *Y=alloca(n*sizeof(*N)); float *XY=alloca(n*sizeof(*N)); float tN, tX, tXX, tY, tXY; int i; int lo, hi; float R, A, B, D; float w, x, y; tN = tX = tXX = tY = tXY = 0.f; y = f[0] + offset; if (y < 1.f) y = 1.f; w = y * y * .5; tN += w; tX += w; tY += w * y; N[0] = tN; X[0] = tX; XX[0] = tXX; Y[0] = tY; XY[0] = tXY; for (i = 1, x = 1.f; i < n; i++, x += 1.f) { y = f[i] + offset; if (y < 1.f) y = 1.f; w = y * y;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?