📄 mdf.c
字号:
speex_free(st->Rf);
speex_free(st->Xf);
speex_free(st->Yh);
speex_free(st->Eh);
speex_free(st->X);
speex_free(st->Y);
speex_free(st->E);
speex_free(st->W);
speex_free(st->PHI);
speex_free(st->power);
speex_free(st->power_1);
speex_free(st->window);
speex_free(st);
}
extern int fixed_point;
/** Performs echo cancellation on a frame */
void speex_echo_cancel(SpeexEchoState *st, short *ref, short *echo, short *out, spx_int32_t *Yout)
{
int i,j;
int N,M;
spx_word32_t Syy,See;
spx_word16_t leak_estimate;
spx_word16_t ss, ss_1;
spx_float_t Pey = FLOAT_ONE, Pyy=FLOAT_ONE;
spx_float_t alpha, alpha_1;
spx_word16_t RER;
spx_word32_t tmp32;
spx_word16_t M_1;
N = st->window_size;
M = st->M;
st->cancel_count++;
#ifdef FIXED_POINT
ss=DIV32_16(11469,M);
ss_1 = SUB16(32767,ss);
M_1 = DIV32_16(32767,M);
#else
ss=.35/M;
ss_1 = 1-ss;
M_1 = 1.f/M;
#endif
/* 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] = SHL16(SUB16(echo[i], MULT16_16_P15(st->preemph, st->memX)),1);
st->memX = echo[i];
st->d[i] = st->d[i+st->frame_size];
st->d[i+st->frame_size] = SHL16(SUB16(ref[i], MULT16_16_P15(st->preemph, st->memD)),1);
st->memD = ref[i];
}
/* Shift memory: this could be optimized eventually*/
for (i=0;i<N*(M-1);i++)
st->X[i]=st->X[i+N];
/* Convert x (echo input) to frequency domain */
spx_fft(st->fft_table, st->x, &st->X[(M-1)*N]);
/* Compute filter response Y */
spectral_mul_accum(st->X, st->W, st->Y, N, M);
spx_ifft(st->fft_table, st->Y, st->y);
#if 1
spectral_mul_accum(st->X, st->PHI, st->Y, N, M);
spx_ifft(st->fft_table, st->Y, st->e);
#endif
/* Compute error signal (for the output with de-emphasis) */
for (i=0;i<st->frame_size;i++)
{
spx_word32_t tmp_out;
#if 1
spx_word16_t y = MULT16_16_Q15(st->window[i+st->frame_size],st->e[i+st->frame_size]) + MULT16_16_Q15(st->window[i],st->y[i+st->frame_size]);
tmp_out = SUB32(EXTEND32(st->d[i+st->frame_size]), EXTEND32(y));
#else
tmp_out = SUB32(EXTEND32(st->d[i+st->frame_size]), EXTEND32(st->y[i+st->frame_size]));
#endif
tmp_out = PSHR32(tmp_out,1);
/* Saturation */
if (tmp_out>32767)
tmp_out = 32767;
else if (tmp_out<-32768)
tmp_out = -32768;
tmp_out = ADD32(tmp_out, EXTEND32(MULT16_16_P15(st->preemph, st->memE)));
out[i] = tmp_out;
st->memE = tmp_out;
}
/* Compute error signal (filter update version) */
for (i=0;i<st->frame_size;i++)
{
st->e[i] = 0;
st->e[i+st->frame_size] = st->d[i+st->frame_size] - st->y[i+st->frame_size];
}
/* Compute a bunch of correlations */
See = inner_prod(st->e+st->frame_size, st->e+st->frame_size, st->frame_size);
See = ADD32(See, SHR32(10000,6));
Syy = inner_prod(st->y+st->frame_size, st->y+st->frame_size, st->frame_size);
/* Convert error to frequency domain */
spx_fft(st->fft_table, st->e, st->E);
for (i=0;i<st->frame_size;i++)
st->y[i] = 0;
spx_fft(st->fft_table, st->y, st->Y);
/* Compute power spectrum of echo (X), error (E) and filter response (Y) */
power_spectrum(st->E, st->Rf, N);
power_spectrum(st->Y, st->Yf, N);
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] = MULT16_32_Q15(ss_1,st->power[j]) + 1 + MULT16_32_Q15(ss,st->Xf[j]);
/* Enable this to compute the power based only on the tail (would need to compute more
efficiently to make this really useful */
if (0)
{
float scale2 = .5f/M;
for (j=0;j<=st->frame_size;j++)
st->power[j] = 0;
for (i=0;i<M;i++)
{
power_spectrum(&st->X[i*N], st->Xf, N);
for (j=0;j<=st->frame_size;j++)
st->power[j] += scale2*st->Xf[j];
}
}
/* Compute filtered spectra and (cross-)correlations */
for (j=st->frame_size;j>=0;j--)
{
spx_float_t Eh, Yh;
Eh = PSEUDOFLOAT(st->Rf[j] - st->Eh[j]);
Yh = PSEUDOFLOAT(st->Yf[j] - st->Yh[j]);
Pey = FLOAT_ADD(Pey,FLOAT_MULT(Eh,Yh));
Pyy = FLOAT_ADD(Pyy,FLOAT_MULT(Yh,Yh));
#ifdef FIXED_POINT
st->Eh[j] = MAC16_32_Q15(MULT16_32_Q15(SUB16(32767,st->spec_average),st->Eh[j]), st->spec_average, st->Rf[j]);
st->Yh[j] = MAC16_32_Q15(MULT16_32_Q15(SUB16(32767,st->spec_average),st->Yh[j]), st->spec_average, st->Yf[j]);
#else
st->Eh[j] = (1-st->spec_average)*st->Eh[j] + st->spec_average*st->Rf[j];
st->Yh[j] = (1-st->spec_average)*st->Yh[j] + st->spec_average*st->Yf[j];
#endif
}
/* Compute correlation updatete rate */
tmp32 = MULT16_32_Q15(st->beta0,Syy);
if (tmp32 > MULT16_32_Q15(st->beta_max,See))
tmp32 = MULT16_32_Q15(st->beta_max,See);
alpha = FLOAT_DIV32(tmp32, See);
alpha_1 = FLOAT_SUB(FLOAT_ONE, alpha);
/* Update correlations (recursive average) */
st->Pey = FLOAT_ADD(FLOAT_MULT(alpha_1,st->Pey) , FLOAT_MULT(alpha,Pey));
st->Pyy = FLOAT_ADD(FLOAT_MULT(alpha_1,st->Pyy) , FLOAT_MULT(alpha,Pyy));
if (FLOAT_LT(st->Pyy, FLOAT_ONE))
st->Pyy = FLOAT_ONE;
/* We don't really hope to get better than 33 dB (MIN_LEAK-3dB) attenuation anyway */
if (FLOAT_LT(st->Pey, FLOAT_MULT(MIN_LEAK,st->Pyy)))
st->Pey = FLOAT_MULT(MIN_LEAK,st->Pyy);
if (FLOAT_GT(st->Pey, st->Pyy))
st->Pey = st->Pyy;
/* leak_estimate is the limear regression result */
leak_estimate = FLOAT_EXTRACT16(FLOAT_SHL(FLOAT_DIVU(st->Pey, st->Pyy),14));
if (leak_estimate > 16383)
leak_estimate = 32767;
else
leak_estimate = SHL16(leak_estimate,1);
/*printf ("%f\n", leak_estimate);*/
/* Compute Residual to Error Ratio */
#ifdef FIXED_POINT
tmp32 = MULT16_32_Q15(leak_estimate,Syy);
tmp32 = ADD32(tmp32, SHL32(tmp32,1));
if (tmp32 > SHR32(See,1))
tmp32 = SHR32(See,1);
RER = FLOAT_EXTRACT16(FLOAT_SHL(FLOAT_DIV32(tmp32,See),15));
#else
RER = 3.*MULT16_32_Q15(leak_estimate,Syy) / See;
if (RER > .5)
RER = .5;
#endif
/* We consider that the filter has had minimal adaptation if the following is true*/
if (!st->adapted && st->sum_adapt > QCONST32(1,15))
{
st->adapted = 1;
}
if (st->adapted)
{
for (i=0;i<=st->frame_size;i++)
{
spx_word32_t r, e;
/* Compute frequency-domain adaptation mask */
r = MULT16_32_Q15(leak_estimate,SHL32(st->Yf[i],3));
e = SHL32(st->Rf[i],3)+1;
#ifdef FIXED_POINT
if (r>SHR32(e,1))
r = SHR32(e,1);
#else
if (r>.5*e)
r = .5*e;
#endif
r = MULT16_32_Q15(QCONST16(.8,15),r) + MULT16_32_Q15(QCONST16(.2,15),(spx_word32_t)(MULT16_32_Q15(RER,e)));
/*st->power_1[i] = adapt_rate*r/(e*(1+st->power[i]));*/
st->power_1[i] = FLOAT_SHL(FLOAT_DIV32_FLOAT(MULT16_32_Q15(M_1,r),FLOAT_MUL32U(e,st->power[i]+10)),WEIGHT_SHIFT+16);
}
} else {
spx_word32_t Sxx;
spx_word16_t adapt_rate=0;
Sxx = inner_prod(st->x+st->frame_size, st->x+st->frame_size, st->frame_size);
/* Temporary adaption rate if filter is not adapted correctly */
tmp32 = MULT16_32_Q15(QCONST16(.15f, 15), Sxx);
#ifdef FIXED_POINT
if (Sxx > SHR32(See,2))
Sxx = SHR32(See,2);
#else
if (Sxx > .25*See)
Sxx = .25*See;
#endif
adapt_rate = FLOAT_EXTRACT16(FLOAT_SHL(FLOAT_DIV32(MULT16_32_Q15(M_1,Sxx), See),15));
for (i=0;i<=st->frame_size;i++)
st->power_1[i] = FLOAT_SHL(FLOAT_DIV32(EXTEND32(adapt_rate),ADD32(st->power[i],10)),WEIGHT_SHIFT+1);
/* How much have we adapted so far? */
st->sum_adapt = ADD32(st->sum_adapt,adapt_rate);
}
/* 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];
/* Old value of W in PHI */
st->PHI[i] = st->W[i] - st->PHI[i];
}
/* Update weight to prevent circular convolution (MDF / AUMDF) */
for (j=0;j<M;j++)
{
/* This is a variant of the Alternatively Updated MDF (AUMDF) */
/* Remove the "if" to make this an MDF filter */
if (j==M-1 || st->cancel_count%(M-1) == j)
{
#ifdef _WIN32
spx_word16_t * w = (spx_word16_t *)_alloca(N * sizeof(spx_word16_t));
#else
spx_word16_t w[N];
#endif
#ifdef FIXED_POINT
spx_word16_t w2[N];
for (i=0;i<N;i++)
w2[i] = PSHR32(st->W[j*N+i],NORMALIZE_SCALEDOWN+16);
spx_ifft(st->fft_table, w2, w);
for (i=0;i<st->frame_size;i++)
{
w[i]=0;
}
for (i=st->frame_size;i<N;i++)
{
w[i]=SHL(w[i],NORMALIZE_SCALEUP);
}
spx_fft(st->fft_table, w, w2);
/* The "-1" in the shift is a sort of kludge that trades less efficient update speed for decrease noise */
for (i=0;i<N;i++)
st->W[j*N+i] -= SHL32(w2[i],16+NORMALIZE_SCALEDOWN-NORMALIZE_SCALEUP-1);
#else
spx_ifft(st->fft_table, &st->W[j*N], w);
for (i=st->frame_size;i<N;i++)
{
w[i]=0;
}
spx_fft(st->fft_table, w, &st->W[j*N]);
#endif
}
}
/* Compute spectrum of estimated echo for use in an echo post-filter (if necessary)*/
if (Yout)
{
spx_word16_t leak2;
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] = ref[i]-out[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->y[i] = MULT16_16_Q15(st->window[i],st->last_y[i]);
/* Compute power spectrum of the echo */
spx_fft(st->fft_table, st->y, st->Y);
power_spectrum(st->Y, st->Yps, N);
#ifdef FIXED_POINT
if (leak_estimate > 16383)
leak2 = 32767;
else
leak2 = SHL16(leak_estimate, 1);
#else
if (leak_estimate>.5)
leak2 = 1;
else
leak2 = 2*leak_estimate;
#endif
/* Estimate residual echo */
for (i=0;i<=st->frame_size;i++)
Yout[i] = MULT16_32_Q15(leak2,st->Yps[i]);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -