// Copyright (C) 1999 Jean-Marc Valin
#include "BufferedNode.h"
#include "Buffer.h"
#include "Vector.h"
#include <math.h>
#include <speex/speex_echo.h>
#include <speex/speex_preprocess.h>
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<float>
* @input_description The input audio
*
* @input_name FAR_END
* @input_type Vector<float>
* @input_description The far end audio
*
* @output_name OUTPUT
* @output_type Vector<float>
* @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<int> (parameters.get("FRAME_SIZE"));
tail = dereference_cast<int> (parameters.get("TAIL_LENGTH"));
rate = dereference_cast<int> (parameters.get("SAMPLING_RATE"));
nlp = dereference_cast<bool> (parameters.get("NLP"));
state = speex_echo_state_init(frameSize, tail);
speex_echo_ctl(state, SPEEX_ECHO_SET_SAMPLING_RATE, &rate);
if (dereference_cast<bool> (parameters.get("NLP")))
{
pre = speex_preprocess_state_init(frameSize, rate);
speex_preprocess_ctl(pre, SPEEX_PREPROCESS_SET_ECHO_STATE, state);
int tmp = dereference_cast<int> (parameters.get("NOISE_SUPPRESS"));
speex_preprocess_ctl(pre, SPEEX_PREPROCESS_SET_NOISE_SUPPRESS, &tmp);
tmp = dereference_cast<int> (parameters.get("ECHO_SUPPRESS"));
speex_preprocess_ctl(pre, SPEEX_PREPROCESS_SET_ECHO_SUPPRESS, &tmp);
tmp = dereference_cast<int> (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<float> &in = object_cast<Vector<float> > (inputValue);
int inputLength = in.size();
const Vector<float> &far = object_cast<Vector<float> > (farEndValue);
Vector<float> &output = *Vector<float>::alloc(inputLength);
out[count] = &output;
vector<spx_int16_t> ins(inputLength), fars(inputLength), outs(inputLength);
for (int i=0;i<inputLength;i++)
ins[i] = in[i];
for (int i=0;i<inputLength;i++)
fars[i] = far[i];
//std:cerr << "cancel " << inputLength << std::endl;
speex_echo_cancellation(state, &ins[0], &fars[0], &outs[0]);
//speex_echo_capture(state, &ins[0], &outs[0], NULL);
//speex_echo_playback(state, &fars[0]);
speex_preprocess_run(pre, &outs[0]);
for (int i=0;i<inputLength;i++)
output[i] = outs[i];
}
IN_ORDER_NODE_SPEEDUP(AEC)
};
}//namespace FD
syntax highlighted by Code2HTML, v. 0.9.1