www.pudn.com > aec.rar > ec.cpp
// file: ec.cc // #include#include #include #include "ec.h" #include "cb.h" #include "ec_constants.h" //----------------------------------------------------------------------------- // // method: process_cc // description: processes one sample of data through the echo canceller // // arguments: // double ref: reference signal (outgoing speech) // double sig: incoming signal (signal plus echo) // // return: // a double value containing the echo canceller output // //----------------------------------------------------------------------------- double Echo_canceller::process_cc(double ref, double sig) { int k; double Py; double two_beta; // push the reference data onto the circular buffer y_d = ref; s_d = sig; // 1. FIR filtering // eq. (2): compute r double r = 0; for ( k = 0; k < N_d; k++ ) r += a_d[ k ] * (double)y_d( -k ); // eq. (3): compute the output value (see figure 3) and the error // note: the error is the same as the output signal when near-end // speech is not present double u_suppr = (double)s_d - r; // if the echo is being amplified then the echo canceller has gotten into // a bad state. This can often happen due to large impulsive noise // sources on the echo channel. The best thing to do here is to // ignore the echo canceller filter suggestion and just output the // input. if ( fabs( sig ) < fabs( u_suppr ) ) u_suppr = sig; e_d = u_d = u_suppr; // 2. power estimate of the return signal power & the reference // eq. (15): update power estimate of the return signal power // eq. (10): update power estimate of the reference Lu_d = ( 1.0 - sigma_Lu_d ) * Lu_d + sigma_Lu_d * fabs( (double)u_d ); Ly_d = ( 1.0 - sigma_Ly_d ) * Ly_d + sigma_Ly_d * fabs( (double)y_d ); if ( Ly_d < CUTOFF_d ) Ly_d = CUTOFF_d; // 3. near-end speech detector // eq. (12) and (13): update near-end speech detector s_tilde_d = ( 1.0 - alpha_st_d ) * s_tilde_d + alpha_st_d * fabs( (double)s_d ); y_tilde_d = ( 1.0 - alpha_yt_d ) * y_tilde_d + alpha_st_d * fabs( (double)y_d ); // eq. (14): is there near-end speech? double max_y_tilde = 0; for ( k = 0; k < N_d; k++ ) if ( max_y_tilde < y_tilde_d( -k ) ) max_y_tilde = y_tilde_d( -k ); if ( s_tilde_d >= ( 0.5 * max_y_tilde ) ) HCNTR_d = HANGT_d; else if ( HCNTR_d > (int)0 ) HCNTR_d--; // 4. update coefficients if no near-end speech #if 1 if ( ( HCNTR_d == 0 ) && ( i_d % M_d == (int)0 ) ) { Py = Ly_d * Ly_d; two_beta = beta1_d / Py; for ( k = 0; k < N_d; k++ ) { // eq. (7): // - compute an expectation over M_d samples // - update the coefficient double grad = 0.0; for ( int m = 0; m < M_d; m++ ) grad += (double)e_d( -m ) * (double)y_d( -m - k ); a_d[ k ] += two_beta * grad; } } #endif #if 0 if ( HCNTR_d == 0 ) { Py = Ly_d * Ly_d; two_beta = beta1_d / Py; // eq. (7): // - compute an expectation over M_d samples // - update the coefficient double grad = 0.0; for ( int m = 0; m < M_d; m++ ) grad += (double)e_d( -m ) * (double)y_d( -m - k_i ); a_d[ k_i ] += two_beta * grad; k_i = ( k_i + 1 ) % N_d; } #endif // 5. residual error suppression // paragraph below eq. (15): if no near-end speech, // check for residual error suppression // - "residual error suppression"是有必要的, 看看"下行数据为拨号音, // 上行数据只为回声"这种情况, 效果非常明显. // - "residual error suppression"中的"缓慢减少e(i)"很有必要, // 否则会产生"choppyness". 想想摩擦音. if ( ( HCNTR_d == 0 ) && ( Lu_d * DEFAULT_SUPPR < Ly_d ) ) u_suppr = 0; i_d++; return u_suppr; } //----------------------------------------------------------------------------- // method: constructor // description: creates an echo canceller object and initializes all buffers // //----------------------------------------------------------------------------- Echo_canceller::Echo_canceller() { a_d = (double*)NULL; } Echo_canceller::~Echo_canceller() { delete [] a_d; } void Echo_canceller::init_cc(double gamma, int N, int M, double beta1, double sigma_ly, double sigma_lu, double alpha_st, double alpha_yt, double cutoff, int hangt, double suppr, double tau) { gamma_d = gamma; N_d = N; M_d = M; beta1_d = beta1; beta2_d = beta1; tau_d = tau; start_speech_d = 0; flag_d = 1; sigma_Ly_d = sigma_ly; sigma_Lu_d = sigma_lu; alpha_st_d = alpha_st; alpha_yt_d = alpha_yt; CUTOFF_d = cutoff; HANGT_d = hangt; SUPPR_d = suppr; k_i = 0; // reset the high-pass filter // s_i_d = 0.0; sdc_d = 0.0; sdc_im1_d = 0.0; // reset the circular buffers // y_d.allocate_cc(N_d + M_d); s_d.allocate_cc(N_d + M_d); u_d.allocate_cc(M_d); e_d.allocate_cc(M_d); // allocate a buffer for the reference signal power computation // y_tilde_d.allocate_cc(N_d); // allocate coefficient memory // if (a_d != (double*)NULL) delete [] a_d; a_d = new double[N_d]; memset(a_d, (int)0, sizeof(double)*N_d); // reset absolute time // i_d = (int)0; // reset the power computations (for y and u) // Ly_d = CUTOFF_d; Lu_d = 0.0; // reset the near-end speech detector // s_tilde_d = 0.0; HCNTR_d = (int)0; } //----------------------------------------------------------------------------- // // method: max_cc // description: returns the maximum of two numbers (I hate macros!) // //----------------------------------------------------------------------------- int Echo_canceller::max_cc(int x, int y) { if (x > y) {return x;} else {return y;} } double Echo_canceller::max_cc(double x, double y) { if (x > y) {return x;} else {return y;} } //----------------------------------------------------------------------------- // // method: clip_cc // description: clips a sample value to +/-MAX_AMPL // //----------------------------------------------------------------------------- short int Echo_canceller::clip_cc(double value) { // restore the range of value // value *= AMPL_SCALE_2; // clip it to +/-AMPL_SCALE_2 // if (value > AMPL_SCALE_2) {return (short int)AMPL_SCALE_2;} else if (value < -AMPL_SCALE_2) {return (short int)-AMPL_SCALE_2;} else //{return (short int)rint(value);} {return (short int)floor(value);} }