From 4cdd96c18b937c0b930fd80b1938b771fefa2238 Mon Sep 17 00:00:00 2001 From: Monty Date: Fri, 29 Mar 2002 07:10:40 +0000 Subject: [PATCH] Lots more preecho tuning after detailed feedback from Juha (JohnV). I think I pass all his test cases now. General behavior is much tighter, less hacked, even yet a bit faster. Monty svn path=/trunk/vorbis/; revision=3197 --- examples/encoder_example.c | 4 +- lib/analysis.c | 9 +- lib/block.c | 10 +- lib/envelope.c | 283 +++++++++++++++++++++++++-------------------- lib/envelope.h | 24 ++-- lib/mapping0.c | 10 +- lib/modes/psych_44.h | 20 ++-- lib/psy.h | 8 +- lib/scales.h | 6 +- 9 files changed, 213 insertions(+), 161 deletions(-) diff --git a/examples/encoder_example.c b/examples/encoder_example.c index 8006170..e2ea935 100644 --- a/examples/encoder_example.c +++ b/examples/encoder_example.c @@ -11,7 +11,7 @@ ******************************************************************** function: simple example encoder - last mod: $Id: encoder_example.c,v 1.39 2002/03/24 21:03:59 xiphmont Exp $ + last mod: $Id: encoder_example.c,v 1.40 2002/03/29 07:10:38 xiphmont Exp $ ********************************************************************/ @@ -97,7 +97,7 @@ int main(){ /* (quality mode .4: 44kHz stereo coupled, roughly 128kbps VBR) */ vorbis_info_init(&vi); - vorbis_encode_init_vbr(&vi,2,44100,.0); /* max compression */ + vorbis_encode_init_vbr(&vi,2,44100,.4); /* add a comment */ vorbis_comment_init(&vc); diff --git a/lib/analysis.c b/lib/analysis.c index c75ef1b..7fd1d9b 100644 --- a/lib/analysis.c +++ b/lib/analysis.c @@ -11,7 +11,7 @@ ******************************************************************** function: single-block PCM analysis mode dispatch - last mod: $Id: analysis.c,v 1.50 2002/03/24 21:04:00 xiphmont Exp $ + last mod: $Id: analysis.c,v 1.51 2002/03/29 07:10:38 xiphmont Exp $ ********************************************************************/ @@ -93,8 +93,11 @@ void _analysis_output_always(char *base,int i,float *v,int n,int bark,int dB,ogg if(bark) fprintf(of,"%g ",toBARK(22050.f*j/n)); else - fprintf(of,"%g ",(double)(j+off)/44100.); - + if(off!=0) + fprintf(of,"%g ",(double)(j+off)/44100.); + else + fprintf(of,"%g ",(double)j); + if(dB){ fprintf(of,"%g\n",todB(v+j)); }else{ diff --git a/lib/block.c b/lib/block.c index 5273cad..1e5054e 100644 --- a/lib/block.c +++ b/lib/block.c @@ -11,7 +11,7 @@ ******************************************************************** function: PCM data vector blocking, windowing and dis/reassembly - last mod: $Id: block.c,v 1.62 2002/03/24 21:04:00 xiphmont Exp $ + last mod: $Id: block.c,v 1.63 2002/03/29 07:10:38 xiphmont Exp $ Handle windowing, overlap-add, etc of the PCM vectors. This is made more amusing by Vorbis' current two allowed block sizes. @@ -509,19 +509,19 @@ int vorbis_analysis_blockout(vorbis_dsp_state *v,vorbis_block *vb){ if(v->W){ if(!v->lW || !v->nW){ vbi->blocktype=BLOCKTYPE_TRANSITION; - /*fprintf(stderr,"-");*/ + fprintf(stderr,"-"); }else{ vbi->blocktype=BLOCKTYPE_LONG; - /*fprintf(stderr,"_");*/ + fprintf(stderr,"_"); } }else{ if(_ve_envelope_mark(v)){ vbi->blocktype=BLOCKTYPE_IMPULSE; - /*fprintf(stderr,"|");*/ + fprintf(stderr,"|"); }else{ vbi->blocktype=BLOCKTYPE_PADDING; - /*fprintf(stderr,".");*/ + fprintf(stderr,"."); } } diff --git a/lib/envelope.c b/lib/envelope.c index 52931cb..160cccc 100644 --- a/lib/envelope.c +++ b/lib/envelope.c @@ -11,7 +11,7 @@ ******************************************************************** function: PCM data envelope analysis - last mod: $Id: envelope.c,v 1.44 2002/03/24 21:04:00 xiphmont Exp $ + last mod: $Id: envelope.c,v 1.45 2002/03/29 07:10:39 xiphmont Exp $ ********************************************************************/ @@ -33,9 +33,9 @@ void _ve_envelope_init(envelope_lookup *e,vorbis_info *vi){ codec_setup_info *ci=vi->codec_setup; vorbis_info_psy_global *gi=&ci->psy_g_param; int ch=vi->channels; - int i; - int n=e->winlength=ci->blocksizes[0]; - e->searchstep=ci->blocksizes[0]/VE_DIV; /* not random */ + int i,j; + int n=e->winlength=128; + e->searchstep=64; /* not random */ e->minenergy=gi->preecho_minenergy; e->ch=ch; @@ -45,54 +45,31 @@ void _ve_envelope_init(envelope_lookup *e,vorbis_info *vi){ mdct_init(&e->mdct,n); for(i=0;imdct_win[i]=sin((i+.5)/n*M_PI); + e->mdct_win[i]=sin(i/(n-1.)*M_PI); e->mdct_win[i]*=e->mdct_win[i]; } - /* overlapping bands, assuming 22050 (which is not always true, but - to Hell with that) */ - /* 2(1.3-3) 4(2.6-6) 8(5.3-12) 16(10.6-18) */ - - e->band[0].begin=rint(3000.f/22050.f*n/4.f)*2.f; - e->band[0].end=rint(6000.f/22050.f*n/4.f)*2.f-e->band[0].begin; - e->band[1].begin=rint(5000.f/22050.f*n/4.f)*2.f; - e->band[1].end=rint(10000.f/22050.f*n/4.f)*2.f-e->band[1].begin; - e->band[2].begin=rint(8000.f/22050.f*n/4.f)*2.f; - e->band[2].end=rint(16000.f/22050.f*n/4.f)*2.f-e->band[2].begin; - e->band[3].begin=rint(12000.f/22050.f*n/4.f)*2.f; - e->band[3].end=rint(20000.f/22050.f*n/4.f)*2.f-e->band[3].begin; - - e->band[0].window=_ogg_malloc((e->band[0].end)/2*sizeof(*e->band[0].window)); - e->band[1].window=_ogg_malloc((e->band[1].end)/2*sizeof(*e->band[1].window)); - e->band[2].window=_ogg_malloc((e->band[2].end)/2*sizeof(*e->band[2].window)); - e->band[3].window=_ogg_malloc((e->band[3].end)/2*sizeof(*e->band[3].window)); - - n=e->band[0].end/2; - for(i=0;iband[0].window[i]=sin((i+.5)/n*M_PI); - e->band[0].total+=e->band[0].window[i]; - } - n=e->band[1].end/2; - for(i=0;iband[1].window[i]=sin((i+.5)/n*M_PI); - e->band[1].total+=e->band[1].window[i]; - } - n=e->band[2].end/2; - for(i=0;iband[2].window[i]=sin((i+.5)/n*M_PI); - e->band[2].total+=e->band[2].window[i]; - } - n=e->band[3].end/2; - for(i=0;iband[3].window[i]=sin((i+.5)/n*M_PI); - e->band[3].total+=e->band[3].window[i]; - } + /* magic follows */ + e->band[0].begin=4; e->band[0].end=8; + e->band[1].begin=8; e->band[1].end=10; + e->band[2].begin=14; e->band[2].end=12; + e->band[3].begin=20; e->band[3].end=16; + e->band[4].begin=28; e->band[4].end=20; + e->band[5].begin=40; e->band[5].end=20; + for(j=0;jband[j].end; + e->band[j].window=_ogg_malloc(n*sizeof(*e->band[0].window)); + for(i=0;iband[j].window[i]=sin((i+.5)/n*M_PI); + e->band[j].total+=e->band[j].window[i]; + } + e->band[j].total=1./e->band[j].total; + } e->filter=_ogg_calloc(VE_BANDS*ch,sizeof(*e->filter)); e->mark=_ogg_calloc(e->storage,sizeof(*e->mark)); - } void _ve_envelope_clear(envelope_lookup *e){ @@ -106,8 +83,11 @@ void _ve_envelope_clear(envelope_lookup *e){ memset(e,0,sizeof(*e)); } +extern void _analysis_output_always(char *base,int i,float *v,int n,int bark,int dB,ogg_int64_t off); + /* fairly straight threshhold-by-band based until we find something that works better and isn't patented. */ + static int _ve_amp(envelope_lookup *ve, vorbis_info_psy_global *gi, float *data, @@ -117,57 +97,114 @@ static int _ve_amp(envelope_lookup *ve, long n=ve->winlength; int ret=0; long i,j; + float decay; /* we want to have a 'minimum bar' for energy, else we're just basing blocks on quantization noise that outweighs the signal itself (for low power signals) */ - float minV=ve->minenergy,acc[VE_BANDS]; + float minV=ve->minenergy; float *vec=alloca(n*sizeof(*vec)); - memset(acc,0,sizeof(acc)); - + + /* stretch is used to gradually lengthen the number of windows + considered prevoius-to-potential-trigger */ + int stretch=max(VE_MINSTRETCH,ve->stretch/2); + float penalty=gi->stretch_penalty-(ve->stretch/2-VE_MINSTRETCH); + if(penalty<0.f)penalty=0.f; + if(penalty>gi->stretch_penalty)penalty=gi->stretch_penalty; + + /*_analysis_output_always("lpcm",seq2,data,n,0,0, + totalshift+pos*ve->searchstep);*/ + /* window and transform */ for(i=0;imdct_win[i]; mdct_forward(&ve->mdct,vec,vec); + + /* _analysis_output_always("mdct",seq2,vec,n/2,0,1,0); */ - /* accumulate amplitude by band */ - for(j=0;j>1]; + /* near-DC spreading function; this has nothing to do with + psychoacoustics, just sidelobe leakage and window size */ + { + float temp=vec[0]*vec[0]+.7*vec[1]*vec[1]+.2*vec[2]*vec[2]; + int ptr=filters->nearptr; + + /* the accumulation is regularly refreshed from scratch to avoid + floating point creep */ + if(ptr==0){ + decay=filters->nearDC_acc=filters->nearDC_partialacc+temp; + filters->nearDC_partialacc=temp; + }else{ + decay=filters->nearDC_acc+=temp; + filters->nearDC_partialacc+=temp; } - acc[j]/=bands[j].total; - if(acc[j]nearDC_acc-=filters->nearDC[ptr]; + filters->nearDC[ptr]=temp; - /* convert amplitude to delta */ - for(j=0;j=VE_DIV)filters[j].ampptr=0; + decay*=(1./(VE_NEARDC+1)); + filters->nearptr++; + if(filters->nearptr>=VE_NEARDC)filters->nearptr=0; + decay=todB(&decay)*.5-15.f; } - - /* convolve deltas to threshhold values */ - for(j=0;j>1]=val; + decay-=8.; } - /* look at local min/max */ + /* _analysis_output_always("spread",seq2++,vec,n/4,0,0,0);*/ + + /* perform preecho/postecho triggering by band */ for(j=0;jgi->preecho_thresh[j] && buf[0]postecho_thresh[j] && buf[0]>buf[1] && acc[j]>buf[1])ret|=2; - buf[0]=buf[1];buf[1]=acc[j]; + float acc=0.; + float valmax,valmin; + + /* accumulate amplitude */ + for(i=0;i=VE_AMP)filters[j].ampptr=0; + } + + /* look at min/max, decide trigger */ + if(valmax>gi->preecho_thresh[j]+penalty)ret|=1; + if(valminpostecho_thresh[j]-penalty)ret|=2; } + + if(ret&1)ve->stretch=-1; + return(ret); } @@ -179,36 +216,37 @@ long _ve_envelope_search(vorbis_dsp_state *v){ long i,j; int first=ve->current/ve->searchstep; - int last=v->pcm_current/ve->searchstep-VE_DIV; + int last=v->pcm_current/ve->searchstep-VE_WIN; if(first<0)first=0; /* make sure we have enough storage to match the PCM */ if(last>ve->storage){ - ve->storage=last+VE_DIV; + ve->storage=last+VE_WIN; ve->mark=_ogg_realloc(ve->mark,ve->storage*sizeof(*ve->mark)); } for(j=first;jstretch++; + if(ve->stretch>VE_MAXSTRETCH*2) + ve->stretch=VE_MAXSTRETCH*2; + for(i=0;ich;i++){ - /* the mark delay is one searchstep because of min/max finder */ - float *pcm=v->pcm[i]+ve->searchstep*(j+1); + float *pcm=v->pcm[i]+ve->searchstep*(j); ret|=_ve_amp(ve,gi,pcm,ve->band,ve->filter+i*VE_BANDS,j); } - /* we assume a 'transient' occupies half a short block; this way, - it's contained in two short blocks, else the first block is - short and the second long, causing smearing. - - preecho triggers follow the impulse marker; postecho triger preceed it */ + ve->mark[j+VE_POST]=0; + if(ret&1){ + ve->mark[j]=1; + ve->mark[j+1]=1; + } - ve->mark[j+VE_DIV/2]=0; - if(ret&1) - for(i=0;i<=VE_DIV/2;i++) - ve->mark[j+i]=1; - if(ret&2) - for(i=-1;i>=-VE_DIV/2 && j+i>=0;i--) - ve->mark[j+i]=1; + if(ret&2){ + ve->mark[j]=1; + ve->mark[j-1]=1; + } } ve->current=last*ve->searchstep; @@ -223,20 +261,16 @@ long _ve_envelope_search(vorbis_dsp_state *v){ j=ve->cursor; - while(jcurrent-(VE_DIV/2*ve->searchstep)){ /* modified to - stay clear of - possibly - unfinished - postecho - detection */ + while(jcurrent-(ve->searchstep)){/* account for postecho + working back one window */ if(j>=testW)return(1); if(ve->mark[j/ve->searchstep]){ if(j>centerW){ -#if 0 + #if 0 if(j>ve->curmark){ float *marker=alloca(v->pcm_current*sizeof(*marker)); - int l; + int l,m; memset(marker,0,sizeof(*marker)*v->pcm_current); fprintf(stderr,"mark! seq=%d, cursor:%fs time:%fs\n", seq, @@ -248,27 +282,27 @@ long _ve_envelope_search(vorbis_dsp_state *v){ _analysis_output_always("markL",seq,v->pcm[0],j,0,0,totalshift); _analysis_output_always("markR",seq,v->pcm[1],j,0,0,totalshift); + for(m=0;msearchstep]=ve->filter[m].markers[l]*.1; + _analysis_output_always(buf,seq,marker,v->pcm_current,0,0,totalshift); + } + + for(m=0;msearchstep]=ve->filter[m+VE_BANDS].markers[l]*.1; + _analysis_output_always(buf,seq,marker,v->pcm_current,0,0,totalshift); + } + + for(l=0;lsearchstep]=ve->stretchm[l]*.1; + _analysis_output_always("stretch",seq,marker,v->pcm_current,0,0,totalshift); - for(l=0;lsearchstep]=ve->filter[0].markers[l]*.01; - _analysis_output_always("delL0",seq,marker,v->pcm_current,0,0,totalshift); - for(l=0;lsearchstep]=ve->filter[1].markers[l]*.01; - _analysis_output_always("delL1",seq,marker,v->pcm_current,0,0,totalshift); - for(l=0;lsearchstep]=ve->filter[2].markers[l]*.01; - _analysis_output_always("delL2",seq,marker,v->pcm_current,0,0,totalshift); - for(l=0;lsearchstep]=ve->filter[3].markers[l]*.01; - _analysis_output_always("delL3",seq,marker,v->pcm_current,0,0,totalshift); - for(l=0;lsearchstep]=ve->filter[4].markers[l]*.01; - _analysis_output_always("delR0",seq,marker,v->pcm_current,0,0,totalshift); - for(l=0;lsearchstep]=ve->filter[5].markers[l]*.01; - _analysis_output_always("delR1",seq,marker,v->pcm_current,0,0,totalshift); - for(l=0;lsearchstep]=ve->filter[6].markers[l]*.01; - _analysis_output_always("delR2",seq,marker,v->pcm_current,0,0,totalshift); - for(l=0;lsearchstep]=ve->filter[7].markers[l]*.01; - _analysis_output_always("delR3",seq,marker,v->pcm_current,0,0,totalshift); seq++; } -#endif + #endif ve->curmark=j; ve->cursor=j; @@ -311,23 +345,22 @@ int _ve_envelope_mark(vorbis_dsp_state *v){ } void _ve_envelope_shift(envelope_lookup *e,long shift){ - int smallsize=e->current/e->searchstep+VE_DIV/2; /* VE_DIV/2 is to - match setting a - mark on a region - in - envelope_search */ + int smallsize=e->current/e->searchstep; int smallshift=shift/e->searchstep; int i; memmove(e->mark,e->mark+smallshift,(smallsize-smallshift)*sizeof(*e->mark)); -#if 0 + #if 0 for(i=0;ich;i++) memmove(e->filter[i].markers, e->filter[i].markers+smallshift, (1024-smallshift)*sizeof(*(*e->filter).markers)); + memmove(e->stretchm, + e->stretchm+smallshift, + (1024-smallshift)*sizeof(*e->stretchm)); totalshift+=shift; -#endif +#endif e->current-=shift; if(e->curmark>=0) diff --git a/lib/envelope.h b/lib/envelope.h index 7087970..99d9d1b 100644 --- a/lib/envelope.h +++ b/lib/envelope.h @@ -11,7 +11,7 @@ ******************************************************************** function: PCM data envelope analysis and manipulation - last mod: $Id: envelope.h,v 1.21 2002/03/24 21:04:00 xiphmont Exp $ + last mod: $Id: envelope.h,v 1.22 2002/03/29 07:10:39 xiphmont Exp $ ********************************************************************/ @@ -20,16 +20,25 @@ #include "mdct.h" -#define VE_DIV 4 -#define VE_CONV 3 -#define VE_BANDS 4 +#define VE_PRE 16 +#define VE_WIN 4 +#define VE_POST 2 +#define VE_AMP (VE_PRE+VE_POST-1) + +#define VE_BANDS 6 +#define VE_NEARDC 15 + +#define VE_MINSTRETCH 2 /* a bit less than short block */ +#define VE_MAXSTRETCH 31 /* one full block */ typedef struct { - float ampbuf[VE_DIV]; + float ampbuf[VE_AMP]; int ampptr; - float delbuf[VE_CONV-1]; - float convbuf[2]; + float nearDC[VE_NEARDC]; + float nearDC_acc; + float nearDC_partialacc; + int nearptr; } envelope_filter_state; typedef struct { @@ -50,6 +59,7 @@ typedef struct { envelope_band band[VE_BANDS]; envelope_filter_state *filter; + int stretch; int *mark; diff --git a/lib/mapping0.c b/lib/mapping0.c index 37356db..b9e7f7e 100644 --- a/lib/mapping0.c +++ b/lib/mapping0.c @@ -11,7 +11,7 @@ ******************************************************************** function: channel mapping 0 implementation - last mod: $Id: mapping0.c,v 1.47 2002/03/24 21:04:00 xiphmont Exp $ + last mod: $Id: mapping0.c,v 1.48 2002/03/29 07:10:39 xiphmont Exp $ ********************************************************************/ @@ -284,6 +284,8 @@ static vorbis_info_mapping *mapping0_unpack(vorbis_info *vi,oggpack_buffer *opb) /* no time mapping implementation for now */ static long seq=0; +static ogg_int64_t total=0; +extern void _analysis_output_always(char *base,int i,float *v,int n,int bark,int dB,ogg_int64_t off); static int mapping0_forward(vorbis_block *vb,vorbis_look_mapping *l){ vorbis_dsp_state *vd=vb->vd; @@ -338,7 +340,7 @@ static int mapping0_forward(vorbis_block *vb,vorbis_look_mapping *l){ _vorbis_apply_window(pcm,b->window,ci->blocksizes,vb->lW,vb->W,vb->nW); memcpy(fft,pcm,sizeof(*fft)*n); - /*_analysis_output_always("windowed",seq+i,pcm,n,0,0,total-n/2);*/ + //_analysis_output_always("windowed",seq+i,pcm,n,0,0,total-n/2); /* transform the PCM data */ /* only MDCT right now.... */ @@ -384,7 +386,7 @@ static int mapping0_forward(vorbis_block *vb,vorbis_look_mapping *l){ for(j=0;jchannels; } - /*total+=ci->blocksizes[vb->W]/4+ci->blocksizes[vb->nW]/4;*/ + total+=ci->blocksizes[vb->W]/4+ci->blocksizes[vb->nW]/4; look->lastframe=vb->sequence; return(0); } diff --git a/lib/modes/psych_44.h b/lib/modes/psych_44.h index 06f5f9a..eb48417 100644 --- a/lib/modes/psych_44.h +++ b/lib/modes/psych_44.h @@ -11,7 +11,7 @@ ******************************************************************** function: key psychoacoustic settings for 44.1/48kHz - last mod: $Id: psych_44.h,v 1.11 2002/03/24 21:24:01 xiphmont Exp $ + last mod: $Id: psych_44.h,v 1.12 2002/03/29 07:10:40 xiphmont Exp $ ********************************************************************/ @@ -21,26 +21,28 @@ static vorbis_info_psy_global _psy_global_44[5]={ {8, /* lines per eighth octave */ - /*{990.f,990.f,990.f,990.f}, {-990.f,-990.f,-990.f,-990.f}, -90.f, - {0.f,0.f,0.f,0.f}, {-0.f,-0.f,-0.f,-0.f}, -90.f,*/ - {16.f,14.f,12.f,12.f}, {-990.f,-990.f,-990.f,-990.f}, -80.f, + {20.f,14.f,10.f,10.f,10.f,10.f}, + {-60.f,-30.f,-40.f,-40.f,-40.f,-40.f}, 4,-75.f, -6.f, 0, }, {8, /* lines per eighth octave */ - /*{990.f,990.f,990.f,990.f}, {-990.f,-990.f,-990.f,-990.f}, -90.f,*/ - {14.f,12.f,11.f,11.f}, {-990.f,-990.f,-990.f,-990.f}, -85.f, + {16.f,12.f,8.f,8.f,8.f,8.f}, + {-40.f,-30.f,-25.f,-25.f,-25.f,-25.f}, 4,-80.f, -6.f, 0, }, {8, /* lines per eighth octave */ - {14.f,12.f,10.f,10.f}, {-90.f,-90.f,-90.f,-90.f}, -85.f, + {14.f,10.f,6.f,6.f,6.f,6.f}, + {-20.f,-20.f,-15.f,-15.f,-15.f,-15.f}, 4,-80.f, -6.f, 0, }, {8, /* lines per eighth octave */ - {12.f,10.f,8.f,8.f}, {-40.f,-40.f,-40.f,-40.f}, -90.f, + {14.f,8.f,6.f,6.f,6.f,6.f}, + {-20.f,-15.f,-12.f,-12.f,-12.f,-12.f}, 2,-80.f, -6.f, 0, }, {8, /* lines per eighth octave */ - {12.f,10.f,8.f,8.f}, {-14.f,-14.f,-12.f,-12.f}, -90.f, + {14.f,10.f,6.f,6.f,6.f,6.f}, + {-15.f,-15.f,-12.f,-12.f,-12.f,-12.f}, 2,-85.f, -6.f, 0, }, }; diff --git a/lib/psy.h b/lib/psy.h index 542062a..0844cef 100644 --- a/lib/psy.h +++ b/lib/psy.h @@ -11,7 +11,7 @@ ******************************************************************** function: random psychoacoustics (not including preecho) - last mod: $Id: psy.h,v 1.27 2001/12/20 01:00:29 segher Exp $ + last mod: $Id: psy.h,v 1.28 2002/03/29 07:10:39 xiphmont Exp $ ********************************************************************/ @@ -20,6 +20,7 @@ #include "smallft.h" #include "backends.h" +#include "envelope.h" #ifndef EHMER_MAX #define EHMER_MAX 56 @@ -87,8 +88,9 @@ typedef struct{ int eighth_octave_lines; /* for block long/short tuning; encode only */ - float preecho_thresh[4]; - float postecho_thresh[4]; + float preecho_thresh[VE_BANDS]; + float postecho_thresh[VE_BANDS]; + float stretch_penalty; float preecho_minenergy; float ampmax_att_per_sec; diff --git a/lib/scales.h b/lib/scales.h index d8803e1..0817fc5 100644 --- a/lib/scales.h +++ b/lib/scales.h @@ -11,7 +11,7 @@ ******************************************************************** function: linear scale -> dB, Bark and Mel scales - last mod: $Id: scales.h,v 1.22 2002/03/21 04:04:26 xiphmont Exp $ + last mod: $Id: scales.h,v 1.23 2002/03/29 07:10:39 xiphmont Exp $ ********************************************************************/ @@ -30,10 +30,10 @@ static float unitnorm(float x){ return(x); } -static float FABS(float x){ +static float FABS(float *x){ ogg_uint32_t *ix=(ogg_uint32_t *)&x; *ix&=0x7fffffffUL; - return(x); + return(*x); } static float todB(const float *x){ -- 2.7.4