Esempio n. 1
0
static void preprocess_analysis(SpeexPreprocessState *st, spx_int16_t *x)
{
   int i;
   int N = st->ps_size;
   int N3 = 2*N - st->frame_size;
   int N4 = st->frame_size - N3;
   float *ps=st->ps;

   /* 'Build' input frame */
   for (i=0;i<N3;i++)
      st->frame[i]=st->inbuf[i];
   for (i=0;i<st->frame_size;i++)
      st->frame[N3+i]=x[i];
   
   /* Update inbuf */
   for (i=0;i<N3;i++)
      st->inbuf[i]=x[N4+i];

   /* Windowing */
   for (i=0;i<2*N;i++)
      st->frame[i] *= st->window[i];

   /* Perform FFT */
   spx_drft_forward(st->fft_lookup, st->frame);

   /* Power spectrum */
   ps[0]=1;
   for (i=1;i<N;i++)
      ps[i]=1+st->frame[2*i-1]*st->frame[2*i-1] + st->frame[2*i]*st->frame[2*i];

}
Esempio n. 2
0
/* Transform a masking curve (power spectrum) into a pole-zero filter */
void curve_to_lpc(VorbisPsy *psy, float *curve, float *awk1, float *awk2, int ord)
{
   int i;
   float ac[psy->n];
   float tmp;
   int len = psy->n >> 1;
   for (i=0;i<2*len;i++)
      ac[i] = 0;
   for (i=1;i<len;i++)
      ac[2*i-1] = curve[i];
   ac[0] = curve[0];
   ac[2*len-1] = curve[len-1];
   
   spx_drft_backward(&psy->lookup, ac);
   _spx_lpc(awk1, ac, ord);
   tmp = 1.;
   for (i=0;i<ord;i++)
   {
      tmp *= .99;
      awk1[i] *= tmp;
   }
#if 0
   for (i=0;i<ord;i++)
      awk2[i] = 0;
#else
   /* Use the second (awk2) filter to correct the first one */
   for (i=0;i<2*len;i++)
      ac[i] = 0;   
   for (i=0;i<ord;i++)
      ac[i+1] = awk1[i];
   ac[0] = 1;
   spx_drft_forward(&psy->lookup, ac);
   /* Compute (power) response of awk1 (all zero) */
   ac[0] *= ac[0];
   for (i=1;i<len;i++)
      ac[i] = ac[2*i-1]*ac[2*i-1] + ac[2*i]*ac[2*i];
   ac[len] = ac[2*len-1]*ac[2*len-1];
   /* Compute correction required */
   for (i=0;i<len;i++)
      curve[i] = 1. / (1e-6f+curve[i]*ac[i]);

   for (i=0;i<2*len;i++)
      ac[i] = 0;
   for (i=1;i<len;i++)
      ac[2*i-1] = curve[i];
   ac[0] = curve[0];
   ac[2*len-1] = curve[len-1];
   
   spx_drft_backward(&psy->lookup, ac);
   _spx_lpc(awk2, ac, ord);
   tmp = 1;
   for (i=0;i<ord;i++)
   {
      tmp *= .99;
      awk2[i] *= tmp;
   }
#endif
}
Esempio n. 3
0
void compute_curve(VorbisPsy *psy, float *audio, float *curve)
{
   int i;
   float work[psy->n];

   float scale=4.f/psy->n;
   float scale_dB;

   scale_dB=todB(scale);
  
   /* window the PCM data; use a BH4 window, not vorbis */
   for(i=0;i<psy->n;i++)
     work[i]=audio[i] * psy->window[i];

   {
     static int seq=0;
     
     //_analysis_output("win",seq,work,psy->n,0,0);

     seq++;
   }

    /* FFT yields more accurate tonal estimation (not phase sensitive) */
    spx_drft_forward(&psy->lookup,work);

    /* magnitudes */
    work[0]=scale_dB+todB(work[0]);
    for(i=1;i<psy->n-1;i+=2){
      float temp = work[i]*work[i] + work[i+1]*work[i+1];
      work[(i+1)>>1] = scale_dB+.5f * todB(temp);
    }

    /* derive a noise curve */
    _vp_noisemask(psy,work,curve);
#define SIDEL 12
    for (i=0;i<SIDEL;i++)
    {
       curve[i]=curve[SIDEL];
    }
#define SIDEH 12
    for (i=0;i<SIDEH;i++)
    {
       curve[(psy->n>>1)-i-1]=curve[(psy->n>>1)-SIDEH];
    }
    for(i=0;i<((psy->n)>>1);i++)
       curve[i] = fromdB(1.2*curve[i]+.2*i);
       //curve[i] = fromdB(0.8*curve[i]+.35*i);
       //curve[i] = fromdB(0.9*curve[i])*pow(1.0*i+45,1.3);
}
Esempio n. 4
0
/** Performs echo cancellation on a frame */
void speex_echo_cancel(SpeexEchoState *st, short *ref, short *echo, short *out, float *Yout)
{
    int i,j,m;
    int N,M;
    float scale;
    float ESR;
    float SER;
    float Sry=0,Srr=0,Syy=0,Sey=0,See=0,Sxx=0;
    float leak_estimate;

    leak_estimate = .1+(.9/(1+2*st->sum_adapt));

    N = st->window_size;
    M = st->M;
    scale = 1.0f/N;
    st->cancel_count++;

    /* Copy input data to buffer */
    for (i=0; i<st->frame_size; i++)
    {
        st->x[i] = st->x[i+st->frame_size];
        st->x[i+st->frame_size] = echo[i];

        st->d[i] = st->d[i+st->frame_size];
        st->d[i+st->frame_size] = ref[i];
    }

    /* Shift memory: this could be optimized eventually*/
    for (i=0; i<N*(M-1); i++)
        st->X[i]=st->X[i+N];

    /* Copy new echo frame */
    for (i=0; i<N; i++)
        st->X[(M-1)*N+i]=st->x[i];

    /* Convert x (echo input) to frequency domain */
    spx_drft_forward(st->fft_lookup, &st->X[(M-1)*N]);

    /* Compute filter response Y */
    for (i=0; i<N; i++)
        st->Y[i] = 0;
    for (j=0; j<M; j++)
        spectral_mul_accum(&st->X[j*N], &st->W[j*N], st->Y, N);

    /* Convert Y (filter response) to time domain */
    for (i=0; i<N; i++)
        st->y[i] = st->Y[i];
    spx_drft_backward(st->fft_lookup, st->y);
    for (i=0; i<N; i++)
        st->y[i] *= scale;

    /* Transform d (reference signal) to frequency domain */
    for (i=0; i<N; i++)
        st->D[i]=st->d[i];
    spx_drft_forward(st->fft_lookup, st->D);

    /* Compute error signal (signal with echo removed) */
    for (i=0; i<st->frame_size; i++)
    {
        float tmp_out;
        tmp_out = (float)ref[i] - st->y[i+st->frame_size];

        st->E[i] = 0;
        st->E[i+st->frame_size] = tmp_out;

        /* Saturation */
        if (tmp_out>32767)
            tmp_out = 32767;
        else if (tmp_out<-32768)
            tmp_out = -32768;
        out[i] = tmp_out;
    }

    /* This bit of code provides faster adaptation by doing a projection of the previous gradient on the
       "MMSE surface" */
    if (1)
    {
        float Sge, Sgg, Syy;
        float gain;
        Syy = inner_prod(st->y+st->frame_size, st->y+st->frame_size, st->frame_size);
        for (i=0; i<N; i++)
            st->Y2[i] = 0;
        for (j=0; j<M; j++)
            spectral_mul_accum(&st->X[j*N], &st->PHI[j*N], st->Y2, N);
        for (i=0; i<N; i++)
            st->y2[i] = st->Y2[i];
        spx_drft_backward(st->fft_lookup, st->y2);
        for (i=0; i<N; i++)
            st->y2[i] *= scale;
        Sge = inner_prod(st->y2+st->frame_size, st->E+st->frame_size, st->frame_size);
        Sgg = inner_prod(st->y2+st->frame_size, st->y2+st->frame_size, st->frame_size);
        /* Compute projection gain */
        gain = Sge/(N+.03*Syy+Sgg);
        if (gain>2)
            gain = 2;
        if (gain < -2)
            gain = -2;

        /* Apply gain to weights, echo estimates, output */
        for (i=0; i<N; i++)
            st->Y[i] += gain*st->Y2[i];
        for (i=0; i<st->frame_size; i++)
        {
            st->y[i+st->frame_size] += gain*st->y2[i+st->frame_size];
            st->E[i+st->frame_size] -= gain*st->y2[i+st->frame_size];
        }
        for (i=0; i<M*N; i++)
            st->W[i] += gain*st->PHI[i];
    }

    /* Compute power spectrum of output (D-Y) and filter response (Y) */
    for (i=0; i<N; i++)
        st->D[i] -= st->Y[i];
    power_spectrum(st->D, st->Rf, N);
    power_spectrum(st->Y, st->Yf, N);

    /* Compute frequency-domain adaptation mask */
    for (j=0; j<=st->frame_size; j++)
    {
        float r;
        r = leak_estimate*st->Yf[j] / (1+st->Rf[j]);
        if (r>1)
            r = 1;
        st->fratio[j] = r;
    }

    /* Compute a bunch of correlations */
    Sry = inner_prod(st->y+st->frame_size, st->d+st->frame_size, st->frame_size);
    Sey = inner_prod(st->y+st->frame_size, st->E+st->frame_size, st->frame_size);
    See = inner_prod(st->E+st->frame_size, st->E+st->frame_size, st->frame_size);
    Syy = inner_prod(st->y+st->frame_size, st->y+st->frame_size, st->frame_size);
    Srr = inner_prod(st->d+st->frame_size, st->d+st->frame_size, st->frame_size);
    Sxx = inner_prod(st->x+st->frame_size, st->x+st->frame_size, st->frame_size);

    /* Compute smoothed cross-correlation and energy */
    st->Sey = .98*st->Sey + .02*Sey;
    st->Syy = .98*st->Syy + .02*Syy;
    st->See = .98*st->See + .02*See;

    /* Check if filter is completely mis-adapted (if so, reset filter) */
    if (st->Sey/(1+st->Syy + .01*st->See) < -1)
    {
        /*fprintf (stderr, "reset at %d\n", st->cancel_count);*/
        speex_echo_state_reset(st);
        return;
    }

    SER = Srr / (1+Sxx);
    ESR = leak_estimate*Syy / (1+See);
    if (ESR>1)
        ESR = 1;
#if 1
    /* If over-cancellation (creating echo with 180 phase) damp filter */
    if (st->Sey/(1+st->Syy) < -.1 && (ESR > .3))
    {
        for (i=0; i<M*N; i++)
            st->W[i] *= .95;
        st->Sey *= .5;
        /*fprintf (stderr, "corrected down\n");*/
    }
#endif
#if 1
    /* If under-cancellation (leaving echo with 0 phase) scale filter up */
    if (st->Sey/(1+st->Syy) > .1 && (ESR > .1 || SER < 10))
    {
        for (i=0; i<M*N; i++)
            st->W[i] *= 1.05;
        st->Sey *= .5;
        /*fprintf (stderr, "corrected up %d\n", st->cancel_count);*/
    }
#endif

    /* We consider that the filter is adapted if the following is true*/
    if (ESR>.6 && st->sum_adapt > 1)
    {
        /*if (!st->adapted)
           fprintf(stderr, "Adapted at %d %f\n", st->cancel_count, st->sum_adapt);*/
        st->adapted = 1;
    }

    /* Update frequency-dependent energy ratio with the total energy ratio */
    for (i=0; i<=st->frame_size; i++)
    {
        st->fratio[i]  = (.2*ESR+.8*min(.005+ESR,st->fratio[i]));
    }

    if (st->adapted)
    {
        st->adapt_rate = .95f/(2+M);
    } else {
        /* Temporary adaption rate if filter is not adapted correctly */
        if (SER<.1)
            st->adapt_rate =.8/(2+M);
        else if (SER<1)
            st->adapt_rate =.4/(2+M);
        else if (SER<10)
            st->adapt_rate =.2/(2+M);
        else if (SER<30)
            st->adapt_rate =.08/(2+M);
        else
            st->adapt_rate = 0;
    }

    /* How much have we adapted so far? */
    st->sum_adapt += st->adapt_rate;

    /* Compute echo power in each frequency bin */
    {
        float ss = 1.0f/st->cancel_count;
        if (ss < .3/M)
            ss=.3/M;
        power_spectrum(&st->X[(M-1)*N], st->Xf, N);
        /* Smooth echo energy estimate over time */
        for (j=0; j<=st->frame_size; j++)
            st->power[j] = (1-ss)*st->power[j] + ss*st->Xf[j];


        /* Combine adaptation rate to the the inverse energy estimate */
        if (st->adapted)
        {
            /* If filter is adapted, include the frequency-dependent ratio too */
            for (i=0; i<=st->frame_size; i++)
                st->power_1[i] = st->adapt_rate*st->fratio[i] /(1.f+st->power[i]);
        } else {
            for (i=0; i<=st->frame_size; i++)
                st->power_1[i] = st->adapt_rate/(1.f+st->power[i]);
        }
    }


    /* Convert error to frequency domain */
    spx_drft_forward(st->fft_lookup, st->E);

    /* Do some regularization (prevents problems when system is ill-conditoned) */
    for (m=0; m<M; m++)
        for (i=0; i<N; i++)
            st->W[m*N+i] *= 1-st->regul[i]*ESR;

    /* Compute weight gradient */
    for (j=0; j<M; j++)
    {
        weighted_spectral_mul_conj(st->power_1, &st->X[j*N], st->E, st->PHI+N*j, N);
    }

    /* Gradient descent */
    for (i=0; i<M*N; i++)
        st->W[i] += st->PHI[i];

    /* AUMDF weight constraint */
    for (j=0; j<M; j++)
    {
        /* Remove the "if" to make this an MDF filter */
        if (st->cancel_count%M == j)
        {
            spx_drft_backward(st->fft_lookup, &st->W[j*N]);
            for (i=0; i<N; i++)
                st->W[j*N+i]*=scale;
            for (i=st->frame_size; i<N; i++)
            {
                st->W[j*N+i]=0;
            }
            spx_drft_forward(st->fft_lookup, &st->W[j*N]);
        }
    }

    /* Compute spectrum of estimated echo for use in an echo post-filter (if necessary)*/
    if (Yout)
    {
        if (st->adapted)
        {
            /* If the filter is adapted, take the filtered echo */
            for (i=0; i<st->frame_size; i++)
                st->last_y[i] = st->last_y[st->frame_size+i];
            for (i=0; i<st->frame_size; i++)
                st->last_y[st->frame_size+i] = st->y[st->frame_size+i];
        } else {
            /* If filter isn't adapted yet, all we can do is take the echo signal directly */
            for (i=0; i<N; i++)
                st->last_y[i] = st->x[i];
        }

        /* Apply hanning window (should pre-compute it)*/
        for (i=0; i<N; i++)
            st->Yps[i] = (.5-.5*cos(2*M_PI*i/N))*st->last_y[i];

        /* Compute power spectrum of the echo */
        spx_drft_forward(st->fft_lookup, st->Yps);
        power_spectrum(st->Yps, st->Yps, N);

        /* Estimate residual echo */
        for (i=0; i<=st->frame_size; i++)
            Yout[i] = 2*leak_estimate*st->Yps[i];
    }

}