// Copyright (C) 1999 Jean-Marc Valin #include "BufferedNode.h" #include "Buffer.h" #include "Vector.h" #include #include #include using namespace std; namespace FD { class AEC; DECLARE_NODE(AEC); /*Node * * @name AEC * @category DSP:Filter * @description Acoustic echo canceller (AEC) with non-linear processing (NLP) * * @input_name INPUT * @input_type Vector * @input_description The input audio * * @input_name FAR_END * @input_type Vector * @input_description The far end audio * * @output_name OUTPUT * @output_type Vector * @output_description Result of echo cancellation * * @parameter_name FRAME_SIZE * @parameter_type int * @parameter_value 128 * @parameter_description Black size used * * @parameter_name TAIL_LENGTH * @parameter_type int * @parameter_value 1024 * @parameter_description Filter length (tail), how long the echo can be * * @parameter_name SAMPLING_RATE * @parameter_type int * @parameter_value 8000 * @parameter_description Sampling rate * * @parameter_name NLP * @parameter_type bool * @parameter_value true * @parameter_description Whether noise suppression (aka nonlinear processing) is used * * @parameter_name NOISE_SUPPRESS * @parameter_type int * @parameter_value 15 * @parameter_description Amount of noise to suppress (dB) * * @parameter_name ECHO_SUPPRESS * @parameter_type int * @parameter_value 45 * @parameter_description Amount of echo to suppress (dB) * * @parameter_name ECHO_SUPPRESS_ACTIVE * @parameter_type int * @parameter_value 10 * @parameter_description Amount of noise to suppress when there is active speech (dB) * END*/ class AEC : public BufferedNode { int inputID; int farEndID; int outputID; SpeexEchoState *state; SpeexPreprocessState *pre; int frameSize; spx_int32_t rate; int tail; bool nlp; public: AEC(string nodeName, ParameterSet params) : BufferedNode(nodeName, params) { inputID = addInput("INPUT"); farEndID = addInput("FAR_END"); outputID = addOutput("OUTPUT"); frameSize = dereference_cast (parameters.get("FRAME_SIZE")); tail = dereference_cast (parameters.get("TAIL_LENGTH")); rate = dereference_cast (parameters.get("SAMPLING_RATE")); nlp = dereference_cast (parameters.get("NLP")); state = speex_echo_state_init(frameSize, tail); speex_echo_ctl(state, SPEEX_ECHO_SET_SAMPLING_RATE, &rate); if (dereference_cast (parameters.get("NLP"))) { pre = speex_preprocess_state_init(frameSize, rate); speex_preprocess_ctl(pre, SPEEX_PREPROCESS_SET_ECHO_STATE, state); int tmp = dereference_cast (parameters.get("NOISE_SUPPRESS")); speex_preprocess_ctl(pre, SPEEX_PREPROCESS_SET_NOISE_SUPPRESS, &tmp); tmp = dereference_cast (parameters.get("ECHO_SUPPRESS")); speex_preprocess_ctl(pre, SPEEX_PREPROCESS_SET_ECHO_SUPPRESS, &tmp); tmp = dereference_cast (parameters.get("ECHO_SUPPRESS_ACTIVE")); speex_preprocess_ctl(pre, SPEEX_PREPROCESS_SET_ECHO_SUPPRESS_ACTIVE, &tmp); } else { pre = NULL; } inOrder = true; } void calculate(int output_id, int count, Buffer &out) { ObjectRef inputValue = getInput(inputID, count); ObjectRef farEndValue = getInput(farEndID, count); const Vector &in = object_cast > (inputValue); int inputLength = in.size(); const Vector &far = object_cast > (farEndValue); Vector &output = *Vector::alloc(inputLength); out[count] = &output; vector ins(inputLength), fars(inputLength), outs(inputLength); for (int i=0;i