static void floor0_map_lazy_init(vorbis_block *vb, vorbis_info_floor *infoX, vorbis_look_floor0 *look){ if(!look->linearmap[vb->W]){ vorbis_dsp_state *vd=vb->vd; vorbis_info *vi=vd->vi; codec_setup_info *ci=vi->codec_setup; vorbis_info_floor0 *info=(vorbis_info_floor0 *)infoX; int W=vb->W; int n=ci->blocksizes[W]/2,j; /* we choose a scaling constant so that: floor(bark(rate/2-1)*C)=mapped-1 floor(bark(rate/2)*C)=mapped */ float scale=look->ln/toBARK(info->rate/2.f); /* the mapping from a linear scale to a smaller bark scale is straightforward. We do *not* make sure that the linear mapping does not skip bark-scale bins; the decoder simply skips them and the encoder may do what it wishes in filling them. They're necessary in some mapping combinations to keep the scale spacing accurate */ look->linearmap[W]=_ogg_malloc((n+1)*sizeof(**look->linearmap)); for(j=0;j<n;j++){ int val=floor( toBARK((info->rate/2.f)/n*j) *scale); /* bark numbers represent band edges */ if(val>=look->ln)val=look->ln-1; /* guard against the approximation */ look->linearmap[W][j]=val; } look->linearmap[W][j]=-1; look->n[W]=n; } }
VorbisPsy *vorbis_psy_init(int rate, int n) { long i,j,lo=-99,hi=1; VorbisPsy *p = speex_alloc(sizeof(VorbisPsy)); memset(p,0,sizeof(*p)); p->n = n; spx_drft_init(&p->lookup, n); p->bark = speex_alloc(n*sizeof(*p->bark)); p->rate=rate; p->vi = &example_tuning; /* BH4 window */ p->window = speex_alloc(sizeof(*p->window)*n); float a0 = .35875f; float a1 = .48829f; float a2 = .14128f; float a3 = .01168f; for(i=0;i<n;i++) p->window[i] = //a0 - a1*cos(2.*M_PI/n*(i+.5)) + a2*cos(4.*M_PI/n*(i+.5)) - a3*cos(6.*M_PI/n*(i+.5)); sin((i+.5)/n * M_PI)*sin((i+.5)/n * M_PI); /* bark scale lookups */ for(i=0;i<n;i++){ float bark=toBARK(rate/(2*n)*i); for(;lo+p->vi->noisewindowlomin<i && toBARK(rate/(2*n)*lo)<(bark-p->vi->noisewindowlo);lo++); for(;hi<=n && (hi<i+p->vi->noisewindowhimin || toBARK(rate/(2*n)*hi)<(bark+p->vi->noisewindowhi));hi++); p->bark[i]=((lo-1)<<16)+(hi-1); } /* set up rolling noise median */ p->noiseoffset=speex_alloc(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; p->noiseoffset[i]= p->vi->noiseoff[inthalfoc]*(1.-del) + p->vi->noiseoff[inthalfoc+1]*del; } #if 0 _analysis_output_always("noiseoff0",ls,p->noiseoffset,n,1,0,0); #endif return p; }
/* there was no great place to put this.... */ void _analysis_output_always(char *base,int i,float *v,int n,int bark,int dB,ogg_int64_t off){ int j; FILE *of; char buffer[80]; /* if(i==5870){*/ sprintf(buffer,"%s_%d.m",base,i); of=fopen(buffer,"w"); if(!of)perror("failed to open data dump file"); for(j=0;j<n;j++){ if(bark){ float b=toBARK((4000.f*j/n)+.25); fprintf(of,"%f ",b); }else if(off!=0) fprintf(of,"%f ",(double)(j+off)/8000.); else fprintf(of,"%f ",(double)j); if(dB){ float val; if(v[j]==0.) val=-140.; else val=todB(v+j); fprintf(of,"%f\n",val); }else{ fprintf(of,"%f\n",v[j]); } } fclose(of); /* } */ }
void analysis(char *base,int i,float *v,int n,int bark,int dB){ if(noisy){ int j; FILE *of; char buffer[80]; sprintf(buffer,"%s_%d.m",base,i); of=fopen(buffer,"w"); for(j=0;j<n;j++){ if(dB && v[j]==0) fprintf(of,"\n\n"); else{ if(bark) fprintf(of,"%g ",toBARK(22050.f*j/n)); else fprintf(of,"%g ",(float)j); if(dB){ fprintf(of,"%g\n",todB(v+j)); }else{ fprintf(of,"%g\n",v[j]); } } } fclose(of); } }
static void _analysis_output(char *base,int i,float *v,int n,int bark,int dB){ int j; FILE *of; char buffer[80]; sprintf(buffer,"%s_%d.m",base,i); of=fopen(buffer,"w"); if(!of)perror("failed to open data dump file"); for(j=0;j<n;j++){ if(bark){ float b=toBARK((4000.f*j/n)+.25); fprintf(of,"%f ",b); }else fprintf(of,"%f ",(double)j); if(dB){ float val; if(v[j]==0.) val=-140.; else val=todB(v[j]); fprintf(of,"%f\n",val); }else{ fprintf(of,"%f\n",v[j]); } } fclose(of); }
static void floor0_map_lazy_init(vorbis_dsp_state *vd, vorbis_info_floor *infoX, vorbis_look_floor0 *look, unsigned int W) { if(!look->linearcosmap[W]){ vorbis_info *vi=vd->vi; codec_setup_info *ci=vi->codec_setup; vorbis_info_floor0 *info=(vorbis_info_floor0 *)infoX; int n=ci->blocksizes[W]/2,j; ogg_double_t scale=look->ln/toBARK(info->rate/2.f); look->linearcosmap[W]=_ogg_malloc((n+1)*sizeof(**look->linearcosmap)); for(j=0;j<n;j++){ int val=floor( toBARK((info->rate/2.f)/n*j)*scale); if(val>=look->ln) val=look->ln-1; look->linearcosmap[W][j]=2.0f*cos(M_PI/(float)look->ln*(float)val);; } look->linearcosmap[W][j]=-999.0f; look->n[W]=n; } }
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=(float*)_ogg_malloc(n*sizeof(*p->ath)); p->octave=(long*)_ogg_malloc(n*sizeof(*p->octave)); p->bark=(long*)_ogg_malloc(n*sizeof(*p->bark)); p->vi=vi; p->n=n; p->rate=rate; /* AoTuV HF weighting */ p->m_val = 1.; if(rate < 26000) p->m_val = 0; else if(rate < 38000) p->m_val = .94; /* 32kHz */ else if(rate > 46000) p->m_val = 1.275; /* 48kHz */ /* 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=(float**)_ogg_malloc(P_NOISECURVES*sizeof(*p->noiseoffset)); for(i=0;i<P_NOISECURVES;i++) p->noiseoffset[i]=(float*)_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 }
FilterBank *filterbank_new(int banks, spx_word32_t sampling, int len, int type) { FilterBank *bank; spx_word32_t df; spx_word32_t max_mel, mel_interval; int i; int id1; int id2; df = DIV32(SHL32(sampling,15),MULT16_16(2,len)); max_mel = toBARK(EXTRACT16(sampling/2)); mel_interval = PDIV32(max_mel,banks-1); bank = (FilterBank*)speex_alloc(sizeof(FilterBank)); bank->nb_banks = banks; bank->len = len; bank->bank_left = (int*)speex_alloc(len*sizeof(int)); bank->bank_right = (int*)speex_alloc(len*sizeof(int)); bank->filter_left = (spx_word16_t*)speex_alloc(len*sizeof(spx_word16_t)); bank->filter_right = (spx_word16_t*)speex_alloc(len*sizeof(spx_word16_t)); /* Think I can safely disable normalisation that for fixed-point (and probably float as well) */ #ifndef FIXED_POINT bank->scaling = (float*)speex_alloc(banks*sizeof(float)); #endif for (i=0;i<len;i++) { spx_word16_t curr_freq; spx_word32_t mel; spx_word16_t val; curr_freq = EXTRACT16(MULT16_32_P15(i,df)); mel = toBARK(curr_freq); if (mel > max_mel) break; #ifdef FIXED_POINT id1 = DIV32(mel,mel_interval); #else id1 = (int)(floor(mel/mel_interval)); #endif if (id1>banks-2) { id1 = banks-2; val = Q15_ONE; } else { val = DIV32_16(mel - id1*mel_interval,EXTRACT16(PSHR32(mel_interval,15))); } id2 = id1+1; bank->bank_left[i] = id1; bank->filter_left[i] = SUB16(Q15_ONE,val); bank->bank_right[i] = id2; bank->filter_right[i] = val; } /* Think I can safely disable normalisation for fixed-point (and probably float as well) */ #ifndef FIXED_POINT for (i=0;i<bank->nb_banks;i++) bank->scaling[i] = 0; for (i=0;i<bank->len;i++) { int id = bank->bank_left[i]; bank->scaling[id] += bank->filter_left[i]; id = bank->bank_right[i]; bank->scaling[id] += bank->filter_right[i]; } for (i=0;i<bank->nb_banks;i++) bank->scaling[i] = Q15_ONE/(bank->scaling[i]); #endif return bank; }
int main(){ int i; double rate; for(i=64;i<32000;i*=2){ rate=48000.f; fprintf(stderr,"rate=%gHz, block=%d, f(1)=%.2gHz bark(1)=%.2g (of %.2g)\n", rate,i,rate/2 / (i/2),toBARK(rate/2 /(i/2)),toBARK(rate/2)); rate=44100.f; fprintf(stderr,"rate=%gHz, block=%d, f(1)=%.2gHz bark(1)=%.2g (of %.2g)\n", rate,i,rate/2 / (i/2),toBARK(rate/2 /(i/2)),toBARK(rate/2)); rate=32000.f; fprintf(stderr,"rate=%gHz, block=%d, f(1)=%.2gHz bark(1)=%.2g (of %.2g)\n", rate,i,rate/2 / (i/2),toBARK(rate/2 /(i/2)),toBARK(rate/2)); rate=22050.f; fprintf(stderr,"rate=%gHz, block=%d, f(1)=%.2gHz bark(1)=%.2g (of %.2g)\n", rate,i,rate/2 / (i/2),toBARK(rate/2 /(i/2)),toBARK(rate/2)); rate=16000.f; fprintf(stderr,"rate=%gHz, block=%d, f(1)=%.2gHz bark(1)=%.2g (of %.2g)\n", rate,i,rate/2 / (i/2),toBARK(rate/2 /(i/2)),toBARK(rate/2)); rate=11025.f; fprintf(stderr,"rate=%gHz, block=%d, f(1)=%.2gHz bark(1)=%.2g (of %.2g)\n", rate,i,rate/2 / (i/2),toBARK(rate/2 /(i/2)),toBARK(rate/2)); rate=8000.f; fprintf(stderr,"rate=%gHz, block=%d, f(1)=%.2gHz bark(1)=%.2g (of %.2g)\n\n", rate,i,rate/2 / (i/2),toBARK(rate/2 /(i/2)),toBARK(rate/2)); } { float i; int j; for(i=0.,j=0;i<28;i+=1,j++){ fprintf(stderr,"(%d) bark=%f %gHz (%d of 128)\n", j,i,fromBARK(i),(int)(fromBARK(i)/22050.*128.)); } } return(0); }
void _vp_psy_init(vorbis_look_psy *p,vorbis_info_psy *vi, vorbis_info_psy_global *gi,int n,long rate){ long i,j,k,lo=0,hi=0; long maxoc; memset(p,0,sizeof(vorbis_look_psy)); p->eighth_octave_lines=gi->eighth_octave_lines; p->shiftoc=rint(log(gi->eighth_octave_lines*8)/log(2))-1; p->firstoc=toOC(.25f*rate/n)*(1<<(p->shiftoc+1))-gi->eighth_octave_lines; maxoc=toOC((n*.5f-.25f)*rate/n)*(1<<(p->shiftoc+1))+.5f; p->total_octave_lines=maxoc-p->firstoc+1; if(vi->ath) p->ath=_ogg_malloc(n*sizeof(float)); p->octave=_ogg_malloc(n*sizeof(long)); p->bark=_ogg_malloc(n*sizeof(unsigned long)); p->vi=vi; p->n=n; p->rate=rate; /* set up the lookups for a given blocksize and sample rate */ if(vi->ath) set_curve(vi->ath, p->ath,n,rate); 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]=(hi<<16)+lo; } for(i=0;i<n;i++) p->octave[i]=toOC((i*.5f+.25f)*rate/n)*(1<<(p->shiftoc+1))+.5f; p->tonecurves=_ogg_malloc(P_BANDS*sizeof(float **)); p->noisethresh=_ogg_malloc(n*sizeof(float)); p->noiseoffset=_ogg_malloc(n*sizeof(float)); for(i=0;i<P_BANDS;i++) p->tonecurves[i]=_ogg_malloc(P_LEVELS*sizeof(float *)); for(i=0;i<P_BANDS;i++) for(j=0;j<P_LEVELS;j++) p->tonecurves[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); /* value limit the tonal masking curves; the peakatt not only optionally specifies maximum dynamic depth, but also [always] limits the masking curves to a minimum depth */ for(i=0;i<P_BANDS;i+=2) for(j=4;j<P_LEVELS;j+=2) for(k=2;k<EHMER_MAX+2;k++) p->tonecurves[i][j][k]+=vi->tone_masteratt; /* interpolate curves between */ for(i=1;i<P_BANDS;i+=2) for(j=4;j<P_LEVELS;j+=2){ memcpy(p->tonecurves[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;i<P_BANDS;i++) setup_curve(p->tonecurves[i],i,vi->toneatt->block[i]); if(vi->curvelimitp){ /* value limit the tonal masking curves; the peakatt not only optionally specifies maximum dynamic depth, but also [always] limits the masking curves to a minimum depth */ for(i=0;i<P_BANDS;i++) for(j=0;j<P_LEVELS;j++){ for(k=2;k<EHMER_OFFSET+2+vi->curvelimitp;k++) if(p->tonecurves[i][j][k]> vi->peakatt->block[i][j]) p->tonecurves[i][j][k]= vi->peakatt->block[i][j]; else break; } } if(vi->peakattp) /* we limit depth only optionally */ for(i=0;i<P_BANDS;i++) for(j=0;j<P_LEVELS;j++) if(p->tonecurves[i][j][EHMER_OFFSET+2]< vi->peakatt->block[i][j]) p->tonecurves[i][j][EHMER_OFFSET+2]= vi->peakatt->block[i][j]; /* but guarding is mandatory */ for(i=0;i<P_BANDS;i++) for(j=0;j<P_LEVELS;j++) if(p->tonecurves[i][j][EHMER_OFFSET+2]< vi->tone_maxatt) p->tonecurves[i][j][EHMER_OFFSET+2]= vi->tone_maxatt; /* set up rolling noise median */ 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; p->noisethresh[i]=((p->vi->noisethresh[inthalfoc]*(1.-del) + p->vi->noisethresh[inthalfoc+1]*del))*2.f-1.f; p->noiseoffset[i]= p->vi->noiseoff[inthalfoc]*(1.-del) + p->vi->noiseoff[inthalfoc+1]*del; } analysis_noisy=1; _analysis_output("noiseoff",0,p->noiseoffset,n,1,0); _analysis_output("noisethresh",0,p->noisethresh,n,1,0); for(i=0;i<P_LEVELS;i++) _analysis_output("curve_63Hz",i,p->tonecurves[0][i]+2,EHMER_MAX,0,0); for(i=0;i<P_LEVELS;i++) _analysis_output("curve_88Hz",i,p->tonecurves[1][i]+2,EHMER_MAX,0,0); for(i=0;i<P_LEVELS;i++) _analysis_output("curve_125Hz",i,p->tonecurves[2][i]+2,EHMER_MAX,0,0); for(i=0;i<P_LEVELS;i++) _analysis_output("curve_170Hz",i,p->tonecurves[3][i]+2,EHMER_MAX,0,0); for(i=0;i<P_LEVELS;i++) _analysis_output("curve_250Hz",i,p->tonecurves[4][i]+2,EHMER_MAX,0,0); for(i=0;i<P_LEVELS;i++) _analysis_output("curve_350Hz",i,p->tonecurves[5][i]+2,EHMER_MAX,0,0); for(i=0;i<P_LEVELS;i++) _analysis_output("curve_500Hz",i,p->tonecurves[6][i]+2,EHMER_MAX,0,0); for(i=0;i<P_LEVELS;i++) _analysis_output("curve_700Hz",i,p->tonecurves[7][i]+2,EHMER_MAX,0,0); for(i=0;i<P_LEVELS;i++) _analysis_output("curve_1kHz",i,p->tonecurves[8][i]+2,EHMER_MAX,0,0); for(i=0;i<P_LEVELS;i++) _analysis_output("curve_1.4Hz",i,p->tonecurves[9][i]+2,EHMER_MAX,0,0); for(i=0;i<P_LEVELS;i++) _analysis_output("curve_2kHz",i,p->tonecurves[10][i]+2,EHMER_MAX,0,0); for(i=0;i<P_LEVELS;i++) _analysis_output("curve_2.4kHz",i,p->tonecurves[11][i]+2,EHMER_MAX,0,0); for(i=0;i<P_LEVELS;i++) _analysis_output("curve_4kHz",i,p->tonecurves[12][i]+2,EHMER_MAX,0,0); for(i=0;i<P_LEVELS;i++) _analysis_output("curve_5.6kHz",i,p->tonecurves[13][i]+2,EHMER_MAX,0,0); for(i=0;i<P_LEVELS;i++) _analysis_output("curve_8kHz",i,p->tonecurves[14][i]+2,EHMER_MAX,0,0); for(i=0;i<P_LEVELS;i++) _analysis_output("curve_11.5kHz",i,p->tonecurves[15][i]+2,EHMER_MAX,0,0); for(i=0;i<P_LEVELS;i++) _analysis_output("curve_16kHz",i,p->tonecurves[16][i]+2,EHMER_MAX,0,0); analysis_noisy=1; }
static void setup_curve(float **c, int band, float *curveatt_dB){ int i,j; float ath[EHMER_MAX]; float tempc[P_LEVELS][EHMER_MAX]; float *ATH=ATH_Bark_dB_lspconservative; /* just for limiting here */ memcpy(c[0]+2,c[4]+2,sizeof(float)*EHMER_MAX); memcpy(c[2]+2,c[4]+2,sizeof(float)*EHMER_MAX); /* we add back in the ATH to avoid low level curves falling off to -infinity and unneccessarily cutting off high level curves in the curve limiting (last step). But again, remember... a half-band's settings must be valid over the whole band, and it's better to mask too little than too much, so be pessimal. */ for(i=0;i<EHMER_MAX;i++){ float oc_min=band*.5+(i-EHMER_OFFSET)*.125; float oc_max=band*.5+(i-EHMER_OFFSET+1)*.125; float bark=toBARK(fromOC(oc_min)); int ibark=floor(bark); float del=bark-ibark; float ath_min,ath_max; if(ibark<26) ath_min=ATH[ibark]*(1.f-del)+ATH[ibark+1]*del; else ath_min=ATH[25]; bark=toBARK(fromOC(oc_max)); ibark=floor(bark); del=bark-ibark; if(ibark<26) ath_max=ATH[ibark]*(1.f-del)+ATH[ibark+1]*del; else ath_max=ATH[25]; ath[i]=min(ath_min,ath_max); } /* The c array is comes in as dB curves at 20 40 60 80 100 dB. interpolate intermediate dB curves */ for(i=1;i<P_LEVELS;i+=2){ interp_curve(c[i]+2,c[i-1]+2,c[i+1]+2,.5); } /* normalize curves so the driving amplitude is 0dB */ /* make temp curves with the ATH overlayed */ for(i=0;i<P_LEVELS;i++){ attenuate_curve(c[i]+2,curveatt_dB[i]); memcpy(tempc[i],ath,EHMER_MAX*sizeof(float)); attenuate_curve(tempc[i],-i*10.f); max_curve(tempc[i],c[i]+2); } /* 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(tempc[j],tempc[j-1]); min_curve(c[j]+2,tempc[j]); } /* add fenceposts */ for(j=0;j<P_LEVELS;j++){ for(i=0;i<EHMER_OFFSET;i++) if(c[j][i+2]>-200.f)break; c[j][0]=i; for(i=EHMER_MAX-1;i>EHMER_OFFSET+1;i--) if(c[j][i+2]>-200.f) break; c[j][1]=i; } }