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 + -
显示快捷键?