📄 mdf.c
字号:
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->wtmp);#ifdef FIXED_POINT speex_free(st->wtmp2);#endif 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 filter_dc_notch16(ref, st->notch_radius, st->d, st->frame_size, st->notch_mem); /* Copy input data to buffer */ for (i=0;i<st->frame_size;i++) { spx_word16_t tmp; st->x[i] = st->x[i+st->frame_size]; st->x[i+st->frame_size] = SUB16(echo[i], MULT16_16_P15(st->preemph, st->memX)); st->memX = echo[i]; tmp = st->d[i]; st->d[i] = st->d[i+st->frame_size]; st->d[i+st->frame_size] = SUB16(tmp, MULT16_16_P15(st->preemph, st->memD)); st->memD = tmp; } /* 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 /* 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 FIXED_POINT for (i=0;i<N;i++) st->wtmp2[i] = PSHR32(st->W[j*N+i],NORMALIZE_SCALEDOWN+16); spx_ifft(st->fft_table, st->wtmp2, st->wtmp); for (i=0;i<st->frame_size;i++) { st->wtmp[i]=0; } for (i=st->frame_size;i<N;i++) { st->wtmp[i]=SHL(st->wtmp[i],NORMALIZE_SCALEUP); } spx_fft(st->fft_table, st->wtmp, st->wtmp2); /* 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(st->wtmp2[i],16+NORMALIZE_SCALEDOWN-NORMALIZE_SCALEUP-1);#else spx_ifft(st->fft_table, &st->W[j*N], st->wtmp); for (i=st->frame_size;i<N;i++) { st->wtmp[i]=0; } spx_fft(st->fft_table, st->wtmp, &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]); }}int speex_echo_ctl(SpeexEchoState *st, int request, void *ptr){ switch(request) { case SPEEX_ECHO_GET_FRAME_SIZE: (*(int*)ptr) = st->frame_size; break; case SPEEX_ECHO_SET_SAMPLING_RATE: st->sampling_rate = (*(int*)ptr); st->spec_average = DIV32_16(SHL32(st->frame_size, 15), st->sampling_rate);#ifdef FIXED_POINT st->beta0 = DIV32_16(SHL32(st->frame_size, 16), st->sampling_rate); st->beta_max = DIV32_16(SHL32(st->frame_size, 14), st->sampling_rate);#else st->beta0 = (2.0f*st->frame_size)/st->sampling_rate; st->beta_max = (.5f*st->frame_size)/st->sampling_rate;#endif if (st->sampling_rate<12000) st->notch_radius = QCONST16(.9, 15); else if (st->sampling_rate<24000) st->notch_radius = QCONST16(.982, 15); else st->notch_radius = QCONST16(.992, 15); break; case SPEEX_ECHO_GET_SAMPLING_RATE: (*(int*)ptr) = st->sampling_rate; break; default: speex_warning_int("Unknown speex_echo_ctl request: ", request); return -1; } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -