********************************************************************
function: PCM data envelope analysis and manipulation
- last mod: $Id: envelope.c,v 1.31 2001/02/02 03:51:56 xiphmont Exp $
+ last mod: $Id: envelope.c,v 1.32 2001/02/15 19:05:45 xiphmont Exp $
Preecho calculation.
#include "envelope.h"
#include "misc.h"
-/* Digital filter designed by mkfilter/mkshape/gencode A.J. Fisher
- Command line: /www/usr/fisher/helpers/mkfilter -Ch \
- -6.0000000000e+00 -Bp -o 5 -a 1.3605442177e-01 3.1746031746e-01 -l */
-
-#if 0
-static int cheb_bandpass_stages=10;
-static float cheb_bandpass_gain=5.589612458e+01f;
-static float cheb_bandpass_B[]={-1.f,0.f,5.f,0.f,-10.f,0.f,
- 10.f,0.f,-5.f,0.f,1f};
-static float cheb_bandpass_A[]={
- -0.1917409386f,
- 0.0078657069f,
- -0.7126903444f,
- 0.0266343467f,
- -1.4047174730f,
- 0.0466964232f,
- -1.9032773429f,
- 0.0451493360f,
- -1.4471447397f,
- 0.0303413711f};
-#endif
-
-/* 4kHz Chebyshev highpass */
-static int cheb_highpass_stages=10;
-static float cheb_highpass_gain= 1.314337427e+01f;
-/* z^-stage, z^-stage+1... */
-static float cheb_highpass_B[]={1.f,-10.f,45.f,-120.f,210.f,
- -252.f,210.f,-120.f,45.f,-10.f,1.f};
-static float cheb_highpass_A[]={
- -0.1013448254f,
- 0.4524819695f,
- -1.3268091670f,
- 3.2875726855f,
- -7.2782468961f,
- 13.0298867474f,
- -17.6698599469f,
- 17.2757670409f,
- -11.6207967046f,
- 4.8672119675f};
-
-#if 0
-/* 6kHz Chebyshev highpass */
-static int cheb_highpass_stages=10;
-static float cheb_highpass_gain= 5.291963434e+01f;
-/* z^-stage, z^-stage+1... */
-static float cheb_highpass_B[]={1.f,-10.f,45.f,-120.f,210.f,
- -252.f,210.f,-120.f,45.f,-10.f,1.f};
-static float cheb_highpass_A[]={
- -0.1247628029f,
- 0.1334086523f,
- -0.3997715614f,
- 0.3213011089f,
- -1.1131924119f,
- 1.7692446626f,
- -3.6241199038f,
- 4.1950871291f,
- -4.2771757867f,
- 2.3920318913f};
-#endif
+/* Digital filter designed by mkfilter/mkshape/gencode A.J. Fisher */
+
+
+
+static int cheb_highpass_stages=6;
+static float cheb_highpass_B[]={1.f,-6.f,15.f,-20.f,15.f,-6.f,1.f};
+
+static int cheb_bandpass_stages=6;
+static float cheb_bandpass_B[]={-1.f,0.f,3.f,0.f,-3.f,0.f,1.f};
+
+
+/* 10kHz Chebyshev highpass */
+static float cheb_highpass10k_gain= 54.34519586f;
+static float cheb_highpass10k_A[]={
+ -0.2064797169f,
+ -0.5609713214f,
+ -1.1352465327f,
+ -1.4495555418f,
+ -1.7938140760f,
+ -0.9473564683f};
+
+/* 6kHz-10kHz Chebyshev bandpass */
+static float cheb_bandpass6k_gain=113.4643935f;
+static float cheb_bandpass6k_A[]={
+ -0.5712621337f,
+ 1.5626130710f,
+ -3.3348854983f,
+ 4.0471340821f,
+ -4.0051680331f,
+ 2.2786325610f};
+
+/* 3kHz-6kHz Chebyshev bandpass */
+static float cheb_bandpass3k_gain= 248.8359377f;
+static float cheb_bandpass3k_A[]={
+ -0.6564230022f,
+ 3.3747911257f,
+ -8.0098635981f,
+ 11.0040876874f,
+ -9.2250963484f,
+ 4.4760355389f};
+
+/* 1.5kHz-3kHz Chebyshev bandpass */
+static float cheb_bandpass1k_gain= 1798.537183f;
+static float cheb_bandpass1k_A[]={
+ -0.8097527363f,
+ 4.7725742682f,
+ -11.9800219408f,
+ 16.3770336223f,
+ -12.8553129536f,
+ 5.4948074309f};
+
void _ve_envelope_init(envelope_lookup *e,vorbis_info *vi){
codec_setup_info *ci=vi->codec_setup;
int i;
e->winlength=window;
e->minenergy=fromdB(ci->preecho_minenergy);
- e->iir=_ogg_calloc(ch,sizeof(IIR_state));
- e->filtered=_ogg_calloc(ch,sizeof(float *));
+ e->iir=_ogg_calloc(ch*4,sizeof(IIR_state));
+ e->filtered=_ogg_calloc(ch*4,sizeof(float *));
e->ch=ch;
e->storage=128;
- for(i=0;i<ch;i++){
- IIR_init(e->iir+i,cheb_highpass_stages,cheb_highpass_gain,
- cheb_highpass_A,cheb_highpass_B);
+ for(i=0;i<ch*4;i+=4){
+
+ IIR_init(e->iir+i,cheb_highpass_stages,cheb_highpass10k_gain,
+ cheb_highpass10k_A,cheb_highpass_B);
+ IIR_init(e->iir+i+1,cheb_bandpass_stages,cheb_bandpass6k_gain,
+ cheb_bandpass6k_A,cheb_bandpass_B);
+ IIR_init(e->iir+i+2,cheb_bandpass_stages,cheb_bandpass3k_gain,
+ cheb_bandpass3k_A,cheb_bandpass_B);
+ IIR_init(e->iir+i+3,cheb_bandpass_stages,cheb_bandpass1k_gain,
+ cheb_bandpass1k_A,cheb_bandpass_B);
+
e->filtered[i]=_ogg_calloc(e->storage,sizeof(float));
+ e->filtered[i+1]=_ogg_calloc(e->storage,sizeof(float));
+ e->filtered[i+2]=_ogg_calloc(e->storage,sizeof(float));
+ e->filtered[i+3]=_ogg_calloc(e->storage,sizeof(float));
}
- drft_init(&e->drft,window);
- e->window=_ogg_malloc(e->winlength*sizeof(float));
- /* We just use a straight sin(x) window for this */
- for(i=0;i<e->winlength;i++)
- e->window[i]=sin((i+.5)/e->winlength*M_PI);
}
void _ve_envelope_clear(envelope_lookup *e){
int i;
- for(i=0;i<e->ch;i++){
+ for(i=0;i<e->ch*4;i++){
IIR_clear((e->iir+i));
_ogg_free(e->filtered[i]);
}
- drft_clear(&e->drft);
- _ogg_free(e->window);
_ogg_free(e->filtered);
_ogg_free(e->iir);
memset(e,0,sizeof(envelope_lookup));
return(B-A);
}
-static float _ve_ampi(envelope_lookup *ve,float *pre){
- long n=ve->winlength;
-
- long i;
-
- /* 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 min=ve->minenergy;
- float A=min*min*n;
-
- for(i=0;i<n;i++){
- A+=pre[i]*pre[i];
- }
-
- A=todB(A);
- return(A);
-}
-
long _ve_envelope_search(vorbis_dsp_state *v,long searchpoint){
vorbis_info *vi=v->vi;
codec_setup_info *ci=vi->codec_setup;
envelope_lookup *ve=((backend_lookup_state *)(v->backend_state))->ve;
- long i,j,k;
+ long i,j,k,l;
float *work=alloca(sizeof(float)*ve->winlength*2);
+ static int seq=0;
/* make sure we have enough storage to match the PCM */
if(v->pcm_storage>ve->storage){
ve->storage=v->pcm_storage;
- for(i=0;i<ve->ch;i++)
+ for(i=0;i<ve->ch*4;i++)
ve->filtered[i]=_ogg_realloc(ve->filtered[i],ve->storage*sizeof(float));
}
/* catch up the highpass to match the pcm */
for(i=0;i<ve->ch;i++){
- float *filtered=ve->filtered[i];
float *pcm=v->pcm[i];
- IIR_state *iir=ve->iir+i;
+ float *filtered0=ve->filtered[i*4];
+ float *filtered1=ve->filtered[i*4+1];
+ float *filtered2=ve->filtered[i*4+2];
+ float *filtered3=ve->filtered[i*4+3];
+ IIR_state *iir0=ve->iir+i*4;
+ IIR_state *iir1=ve->iir+i*4+1;
+ IIR_state *iir2=ve->iir+i*4+2;
+ IIR_state *iir3=ve->iir+i*4+3;
int flag=1;
for(j=ve->current;j<v->pcm_current;j++){
- filtered[j]=IIR_filter(iir,pcm[j]);
+ filtered0[j]=IIR_filter(iir0,pcm[j]);
+ filtered1[j]=IIR_filter(iir1,pcm[j]);
+ filtered2[j]=IIR_filter(iir2,pcm[j]);
+ filtered3[j]=IIR_filter(iir3,pcm[j]);
if(pcm[j])flag=0;
}
- if(flag && ve->current+64<v->pcm_current)IIR_reset(iir);
+ if(flag && ve->current+64<v->pcm_current){
+ IIR_reset(iir0);
+ IIR_reset(iir1);
+ IIR_reset(iir2);
+ IIR_reset(iir3);
+ }
+
+ _analysis_output("pcm",seq,pcm+v->centerW,v->pcm_current-v->centerW,0,0);
+ _analysis_output("f0",seq,filtered0+v->centerW,v->pcm_current-v->centerW,
+ 0,0);
+ _analysis_output("f1",seq,filtered1+v->centerW,v->pcm_current-v->centerW,
+ 0,0);
+ _analysis_output("f2",seq,filtered2+v->centerW,v->pcm_current-v->centerW,
+ 0,0);
+ _analysis_output("f3",seq++,filtered3+v->centerW,v->pcm_current-v->centerW,
+ 0,0);
+
}
ve->current=v->pcm_current;
while(j+ve->winlength<=v->pcm_current){
for(i=0;i<ve->ch;i++){
- float *filtered=ve->filtered[i]+j;
- float m=_ve_deltai(ve,filtered-ve->winlength,filtered);
-
- if(m>ci->preecho_thresh){
- /*granulepos++;*/
- return(0);
- }
- if(m<ci->postecho_thresh){
- /*granulepos++;*/
- return(0);
- }
- /*granulepos++;*/
- }
-
- /* look also for preecho in coupled channel pairs with the center
- subtracted out (A-B) */
- for(i=1;i<ve->ch;i+=2){
- float *filteredA=ve->filtered[i-1]+j-ve->winlength;
- float *filteredB=ve->filtered[i]+j-ve->winlength;
- float m;
-
- for(k=0;k<ve->winlength*2;k++)
- work[k]=filteredA[k]-filteredB[k];
-
- m=_ve_deltai(ve,work,work+ve->winlength);
+ for(k=0;k<4;k++){
+ float *filtered=ve->filtered[i*4+k]+j;
+ float m=_ve_deltai(ve,filtered-ve->winlength,filtered);
- if(m>ci->preecho_thresh){
- /*granulepos++;*/
- return(0);
- }
- if(m<ci->postecho_thresh){
+ if(m>ci->preecho_thresh[k]){
+ /*granulepos++;*/
+ return(0);
+ }
+ if(m<ci->postecho_thresh[k]){
+ /*granulepos++;*/
+ return(0);
+ }
/*granulepos++;*/
- return(0);
}
- /*granulepos++;*/
}
-
j+=min(ci->blocksizes[0],ve->winlength)/2;
if(j>=searchpoint){
void _ve_envelope_shift(envelope_lookup *e,long shift){
int i;
- for(i=0;i<e->ch;i++)
+ for(i=0;i<e->ch*4;i++)
memmove(e->filtered[i],e->filtered[i]+shift,(e->current-shift)*
sizeof(float));
e->current-=shift;