[DEV] rename and rework lib to be compatible with other algo & rename river
This commit is contained in:
parent
cb12079db1
commit
f15b42e6e9
@ -1,93 +0,0 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @author Fatima MARFOUQ
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
*/
|
||||
|
||||
#include <audio/algo/aec/debug.h>
|
||||
#include <audio/algo/aec/Lms.h>
|
||||
#include <audio/algo/aec/updateFilter.h>
|
||||
#include <audio/algo/aec/convolution.h>
|
||||
|
||||
|
||||
|
||||
audio::algo::aec::Lms::Lms(void) :
|
||||
m_filter(),
|
||||
m_feedBack(),
|
||||
m_mu(0.03f) {
|
||||
setFilterSize(256);
|
||||
}
|
||||
|
||||
audio::algo::aec::Lms::~Lms(void) {
|
||||
|
||||
}
|
||||
|
||||
void audio::algo::aec::Lms::reset(void) {
|
||||
// simply reset filters.
|
||||
setFilterSize(m_filter.size());
|
||||
}
|
||||
|
||||
#define MAX_PROCESSING_BLOCK_SIZE (256)
|
||||
|
||||
bool audio::algo::aec::Lms::process(int16_t* _output, const int16_t* _feedback, const int16_t* _microphone, int32_t _nbSample) {
|
||||
bool ret = false;
|
||||
// due to the fact we allocate the data in the stack:
|
||||
int32_t nbCycle = _nbSample/MAX_PROCESSING_BLOCK_SIZE;
|
||||
if (_nbSample - int32_t(_nbSample/MAX_PROCESSING_BLOCK_SIZE)*MAX_PROCESSING_BLOCK_SIZE != 0 ) {
|
||||
nbCycle++;
|
||||
}
|
||||
for (int32_t bbb=0; bbb<nbCycle; ++bbb) {
|
||||
float output[MAX_PROCESSING_BLOCK_SIZE];
|
||||
float feedback[MAX_PROCESSING_BLOCK_SIZE];
|
||||
float microphone[MAX_PROCESSING_BLOCK_SIZE];
|
||||
int32_t offset = bbb*MAX_PROCESSING_BLOCK_SIZE;
|
||||
int32_t nbData = std::min(MAX_PROCESSING_BLOCK_SIZE,
|
||||
_nbSample - offset);
|
||||
for (size_t iii=0; iii<nbData; ++iii) {
|
||||
microphone[iii] = float(_microphone[offset+iii])/32767.0f;
|
||||
feedback[iii] = float(_feedback[offset+iii])/32767.0f;
|
||||
}
|
||||
ret = process(output, feedback, microphone, nbData);
|
||||
for (size_t iii=0; iii<nbData; ++iii) {
|
||||
_output[offset+iii] = int16_t(float(output[iii])*32767.0f);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool audio::algo::aec::Lms::process(float* _output, const float* _feedback, const float* _microphone, int32_t _nbSample) {
|
||||
// add sample in the feedback history:
|
||||
m_feedBack.resize(m_filter.size()+_nbSample, 0.0f);
|
||||
memcpy(&m_feedBack[m_filter.size()], _feedback, _nbSample*sizeof(float));
|
||||
for (int32_t iii=0; iii < _nbSample; iii++) {
|
||||
_output[iii] = processValue(&m_feedBack[m_filter.size()+iii], _microphone[iii]);
|
||||
}
|
||||
// remove old value:
|
||||
m_feedBack.erase(m_feedBack.begin(), m_feedBack.begin() + (m_feedBack.size()-m_filter.size()) );
|
||||
return true;
|
||||
}
|
||||
|
||||
float audio::algo::aec::Lms::processValue(float* _feedback, float _microphone) {
|
||||
// Error calculation.
|
||||
float convolutionValue = audio::algo::aec::convolution(_feedback, &m_filter[0], m_filter.size());
|
||||
float error = _microphone - convolutionValue;
|
||||
float out = std::avg(-1.0f, error, 1.0f);
|
||||
audio::algo::aec::updateFilter(&m_filter[0], _feedback, error*m_mu, m_filter.size());
|
||||
return out;
|
||||
}
|
||||
|
||||
void audio::algo::aec::Lms::setFilterSize(size_t _sampleRate, std11::chrono::microseconds _time) {
|
||||
setFilterSize((_sampleRate*_time.count())/1000000LL);
|
||||
}
|
||||
|
||||
void audio::algo::aec::Lms::setFilterSize(size_t _nbSample) {
|
||||
m_filter.clear();
|
||||
m_feedBack.clear();
|
||||
m_filter.resize(_nbSample, 0.0f);
|
||||
m_feedBack.resize(_nbSample, 0.0f);
|
||||
}
|
||||
|
||||
void audio::algo::aec::Lms::setMu(float _val) {
|
||||
m_mu = _val;
|
||||
}
|
@ -1,98 +0,0 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @author Fatima MARFOUQ
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
*/
|
||||
|
||||
#include <audio/algo/aec/debug.h>
|
||||
#include <audio/algo/aec/Nlms.h>
|
||||
#include <audio/algo/aec/updateFilter.h>
|
||||
#include <audio/algo/aec/convolution.h>
|
||||
#include <audio/algo/aec/power.h>
|
||||
|
||||
audio::algo::aec::Nlms::Nlms(void) :
|
||||
m_filter(),
|
||||
m_feedBack() {
|
||||
setFilterSize(256);
|
||||
}
|
||||
|
||||
audio::algo::aec::Nlms::~Nlms(void) {
|
||||
|
||||
}
|
||||
|
||||
void audio::algo::aec::Nlms::reset(void) {
|
||||
// simply reset filters.
|
||||
setFilterSize(m_filter.size());
|
||||
}
|
||||
|
||||
#define MAX_PROCESSING_BLOCK_SIZE (256)
|
||||
|
||||
bool audio::algo::aec::Nlms::process(int16_t* _output, const int16_t* _feedback, const int16_t* _microphone, int32_t _nbSample) {
|
||||
bool ret = false;
|
||||
// due to the fact we allocate the data in the stack:
|
||||
int32_t nbCycle = _nbSample/MAX_PROCESSING_BLOCK_SIZE;
|
||||
if (_nbSample - int32_t(_nbSample/MAX_PROCESSING_BLOCK_SIZE)*MAX_PROCESSING_BLOCK_SIZE != 0 ) {
|
||||
nbCycle++;
|
||||
}
|
||||
for (int32_t bbb=0; bbb<nbCycle; ++bbb) {
|
||||
float output[MAX_PROCESSING_BLOCK_SIZE];
|
||||
float feedback[MAX_PROCESSING_BLOCK_SIZE];
|
||||
float microphone[MAX_PROCESSING_BLOCK_SIZE];
|
||||
int32_t offset = bbb*MAX_PROCESSING_BLOCK_SIZE;
|
||||
int32_t nbData = std::min(MAX_PROCESSING_BLOCK_SIZE,
|
||||
_nbSample - offset);
|
||||
for (size_t iii=0; iii<nbData; ++iii) {
|
||||
microphone[iii] = float(_microphone[offset+iii])/32767.0f;
|
||||
feedback[iii] = float(_feedback[offset+iii])/32767.0f;
|
||||
}
|
||||
ret = process(output, feedback, microphone, nbData);
|
||||
for (size_t iii=0; iii<nbData; ++iii) {
|
||||
_output[offset+iii] = int16_t(float(output[iii])*32767.0f);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool audio::algo::aec::Nlms::process(float* _output, const float* _feedback, const float* _microphone, int32_t _nbSample) {
|
||||
// add sample in the feedback history:
|
||||
m_feedBack.resize(m_filter.size()+_nbSample, 0.0f);
|
||||
memcpy(&m_feedBack[m_filter.size()], _feedback, _nbSample*sizeof(float));
|
||||
for (int32_t iii=0; iii < _nbSample; iii++) {
|
||||
_output[iii] = processValue(&m_feedBack[m_filter.size()+iii], _microphone[iii]);
|
||||
}
|
||||
// remove old value:
|
||||
m_feedBack.erase(m_feedBack.begin(), m_feedBack.begin() + (m_feedBack.size()-m_filter.size()) );
|
||||
return true;
|
||||
}
|
||||
|
||||
float audio::algo::aec::Nlms::processValue(float* _feedback, float _microphone) {
|
||||
// Error calculation.
|
||||
float convolutionValue = audio::algo::aec::convolution(_feedback, &m_filter[0], m_filter.size());
|
||||
float error = _microphone - convolutionValue;
|
||||
float out = std::avg(-1.0f, error, 1.0f);
|
||||
// calculate mu:
|
||||
float mu = audio::algo::aec::power(_feedback, m_filter.size());
|
||||
//mu = *_feedback * *_feedback;
|
||||
//AA_AEC_WARNING("Mu =" << mu);
|
||||
if (mu <= 1.5f) {
|
||||
// Not enought power in output
|
||||
mu = 0.0001; // arbitrary
|
||||
} else {
|
||||
mu = 1.0f/mu;
|
||||
//AA_AEC_WARNING("Mu =" << mu);
|
||||
}
|
||||
audio::algo::aec::updateFilter(&m_filter[0], _feedback, error*mu, m_filter.size());
|
||||
return out;
|
||||
}
|
||||
|
||||
void audio::algo::aec::Nlms::setFilterSize(size_t _sampleRate, std11::chrono::microseconds _time) {
|
||||
setFilterSize((_sampleRate*_time.count())/1000000LL);
|
||||
}
|
||||
|
||||
void audio::algo::aec::Nlms::setFilterSize(size_t _nbSample) {
|
||||
m_filter.clear();
|
||||
m_feedBack.clear();
|
||||
m_filter.resize(_nbSample, 0.0f);
|
||||
m_feedBack.resize(_nbSample, 0.0f);
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
*/
|
||||
|
||||
#ifndef __APPL_DEBUG_H__
|
||||
#define __APPL_DEBUG_H__
|
||||
|
||||
#include <etk/log.h>
|
||||
|
||||
namespace audio {
|
||||
namespace algo {
|
||||
namespace aec {
|
||||
int32_t getLogId();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define AA_AEC_BASE(info,data) TK_LOG_BASE(audio::algo::aec::getLogId(),info,data)
|
||||
|
||||
#define AA_AEC_CRITICAL(data) AA_AEC_BASE(1, data)
|
||||
#define AA_AEC_ERROR(data) AA_AEC_BASE(2, data)
|
||||
#define AA_AEC_WARNING(data) AA_AEC_BASE(3, data)
|
||||
#ifdef DEBUG
|
||||
#define AA_AEC_INFO(data) AA_AEC_BASE(4, data)
|
||||
#define AA_AEC_DEBUG(data) AA_AEC_BASE(5, data)
|
||||
#define AA_AEC_VERBOSE(data) AA_AEC_BASE(6, data)
|
||||
#define AA_AEC_TODO(data) AA_AEC_BASE(4, "TODO : " << data)
|
||||
#else
|
||||
#define AA_AEC_INFO(data) do { } while(false)
|
||||
#define AA_AEC_DEBUG(data) do { } while(false)
|
||||
#define AA_AEC_VERBOSE(data) do { } while(false)
|
||||
#define AA_AEC_TODO(data) do { } while(false)
|
||||
#endif
|
||||
|
||||
#define AA_AEC_ASSERT(cond,data) \
|
||||
do { \
|
||||
if (!(cond)) { \
|
||||
APPL_CRITICAL(data); \
|
||||
assert(!#cond); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#endif
|
215
audio/algo/river/Lms.cpp
Normal file
215
audio/algo/river/Lms.cpp
Normal file
@ -0,0 +1,215 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @author Fatima MARFOUQ
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
*/
|
||||
|
||||
#include <audio/algo/river/debug.h>
|
||||
#include <audio/algo/river/Lms.h>
|
||||
#include <audio/algo/river/updateFilter.h>
|
||||
#include <audio/algo/river/convolution.h>
|
||||
|
||||
#define MAX_PROCESSING_BLOCK_SIZE (256)
|
||||
|
||||
namespace audio {
|
||||
namespace algo {
|
||||
namespace river {
|
||||
class LmsPrivate {
|
||||
private:
|
||||
int8_t m_nbChannel;
|
||||
float m_sampleRate;
|
||||
enum audio::format m_format;
|
||||
std::vector<std::vector<float> > m_filter; //!< Current filter
|
||||
std::vector<std::vector<float> > m_feedBack; //!< Feedback history
|
||||
float m_mu; //!< mu step size
|
||||
public:
|
||||
LmsPrivate() :
|
||||
m_nbChannel(1),
|
||||
m_sampleRate(48000),
|
||||
m_format(audio::format_float),
|
||||
m_filter(),
|
||||
m_feedBack(),
|
||||
m_mu(0.03f) {
|
||||
setFilterSize(256);
|
||||
}
|
||||
|
||||
~LmsPrivate(void) {
|
||||
|
||||
}
|
||||
|
||||
void reset(void) {
|
||||
// simply reset filters.
|
||||
setFilterSize(m_filter.size());
|
||||
}
|
||||
|
||||
void init(int8_t _nbChannel, float _sampleRate, enum audio::format _format) {
|
||||
m_nbChannel = _nbChannel;
|
||||
m_sampleRate = _sampleRate;
|
||||
m_format = _format;
|
||||
setFilterSize(m_filter.size());
|
||||
switch (m_format) {
|
||||
case audio::format_int16:
|
||||
case audio::format_float:
|
||||
break;
|
||||
default:
|
||||
AA_RIVER_ERROR("Can not INIT LMS with unsupported format : " << m_format);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void process(void* _output, const void* _input, const void* _inputFeedback, size_t _nbChunk) {
|
||||
switch (m_format) {
|
||||
case audio::format_int16:
|
||||
processI16(reinterpret_cast<int16_t*>(_output),
|
||||
reinterpret_cast<const int16_t*>(_inputFeedback),
|
||||
reinterpret_cast<const int16_t*>(_input),
|
||||
_nbChunk);
|
||||
break;
|
||||
case audio::format_float:
|
||||
processFloat(reinterpret_cast<float*>(_output),
|
||||
reinterpret_cast<const float*>(_inputFeedback),
|
||||
reinterpret_cast<const float*>(_input),
|
||||
_nbChunk);
|
||||
break;
|
||||
default:
|
||||
AA_RIVER_ERROR("Can not Echo remove with unsupported format : " << m_format);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool processI16(int16_t* _output, const int16_t* _microphone, const int16_t* _feedback, int32_t _nbSample) {
|
||||
bool ret = false;
|
||||
int32_t processingSize = MAX_PROCESSING_BLOCK_SIZE*m_nbChannel;
|
||||
// due to the fact we allocate the data in the stack:
|
||||
int32_t nbCycle = _nbSample/processingSize;
|
||||
if (_nbSample - int32_t(_nbSample/processingSize)*processingSize != 0 ) {
|
||||
nbCycle++;
|
||||
}
|
||||
for (int32_t bbb=0; bbb<nbCycle; ++bbb) {
|
||||
float output[processingSize];
|
||||
float feedback[processingSize];
|
||||
float microphone[processingSize];
|
||||
int32_t offset = bbb*processingSize;
|
||||
int32_t nbData = std::min(processingSize,
|
||||
_nbSample - offset);
|
||||
for (size_t iii=0; iii<nbData; ++iii) {
|
||||
microphone[iii] = float(_microphone[offset+iii])/32767.0f;
|
||||
feedback[iii] = float(_feedback[offset+iii])/32767.0f;
|
||||
}
|
||||
ret = processFloat(output, feedback, microphone, nbData);
|
||||
for (size_t iii=0; iii<nbData; ++iii) {
|
||||
_output[offset+iii] = int16_t(float(output[iii])*32767.0f);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool processFloat(float* _output, const float* _microphone, const float* _feedback, int32_t _nbSample) {
|
||||
for (int8_t kkk=0; kkk<m_nbChannel; ++kkk) {
|
||||
// add sample in the feedback history:
|
||||
m_feedBack[kkk].resize(m_filter[kkk].size()+_nbSample, 0.0f);
|
||||
memcpy(&m_feedBack[kkk][m_filter[kkk].size()], _feedback, _nbSample*sizeof(float));
|
||||
for (int32_t iii=0; iii < _nbSample; iii++) {
|
||||
_output[iii] = processValue(&m_feedBack[kkk][m_filter[kkk].size()+iii], _microphone[iii], m_filter[kkk]);
|
||||
}
|
||||
// remove old value:
|
||||
m_feedBack[kkk].erase(m_feedBack[kkk].begin(), m_feedBack[kkk].begin() + (m_feedBack[kkk].size()-m_filter[kkk].size()) );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
float processValue(float* _feedback, float _microphone, std::vector<float>& _filter) {
|
||||
// Error calculation.
|
||||
float convolutionValue = audio::algo::river::convolution(_feedback, &_filter[0], _filter.size());
|
||||
float error = _microphone - convolutionValue;
|
||||
float out = std::avg(-1.0f, error, 1.0f);
|
||||
audio::algo::river::updateFilter(&_filter[0], _feedback, error*m_mu, _filter.size());
|
||||
return out;
|
||||
}
|
||||
|
||||
void setFilterTime(std11::chrono::microseconds _time) {
|
||||
setFilterSize((m_sampleRate*_time.count())/1000000LL);
|
||||
}
|
||||
|
||||
void setFilterSize(size_t _nbSample) {
|
||||
m_filter.clear();
|
||||
m_feedBack.clear();
|
||||
m_filter.resize(m_nbChannel);
|
||||
m_feedBack.resize(m_nbChannel);
|
||||
for (int8_t kkk=0; kkk<m_nbChannel; ++kkk) {
|
||||
m_filter[kkk].resize(_nbSample, 0.0f);
|
||||
m_feedBack[kkk].resize(_nbSample, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void setMu(float _val) {
|
||||
m_mu = _val;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
audio::algo::river::Lms::Lms(void) {
|
||||
|
||||
}
|
||||
|
||||
audio::algo::river::Lms::~Lms(void) {
|
||||
|
||||
}
|
||||
|
||||
void audio::algo::river::Lms::reset(void) {
|
||||
if (m_private == nullptr) {
|
||||
AA_RIVER_ERROR("Algo is not initialized...");
|
||||
}
|
||||
m_private->reset();
|
||||
}
|
||||
|
||||
void audio::algo::river::Lms::init(int8_t _nbChannel, float _sampleRate, enum audio::format _format) {
|
||||
if (m_private == nullptr) {
|
||||
m_private = std::make_shared<audio::algo::river::LmsPrivate>();
|
||||
}
|
||||
m_private->init(_nbChannel, _sampleRate, _format);
|
||||
}
|
||||
|
||||
std::vector<enum audio::format> audio::algo::river::Lms::getSupportedFormat() {
|
||||
std::vector<enum audio::format> out = getNativeSupportedFormat();
|
||||
out.push_back(audio::format_int16);
|
||||
return out;
|
||||
}
|
||||
|
||||
std::vector<enum audio::format> audio::algo::river::Lms::getNativeSupportedFormat() {
|
||||
std::vector<enum audio::format> out;
|
||||
out.push_back(audio::format_float);
|
||||
return out;
|
||||
}
|
||||
|
||||
void audio::algo::river::Lms::process(void* _output, const void* _input, const void* _inputFeedback, size_t _nbChunk) {
|
||||
if (m_private == nullptr) {
|
||||
AA_RIVER_ERROR("Algo is not initialized...");
|
||||
}
|
||||
m_private->process(_output, _input, _inputFeedback, _nbChunk);
|
||||
}
|
||||
|
||||
|
||||
void audio::algo::river::Lms::setFilterTime(std11::chrono::microseconds _time) {
|
||||
if (m_private == nullptr) {
|
||||
AA_RIVER_ERROR("Algo is not initialized...");
|
||||
}
|
||||
m_private->setFilterTime(_time);
|
||||
}
|
||||
|
||||
void audio::algo::river::Lms::setFilterSize(size_t _nbSample) {
|
||||
if (m_private == nullptr) {
|
||||
AA_RIVER_ERROR("Algo is not initialized...");
|
||||
}
|
||||
m_private->setFilterSize(_nbSample);
|
||||
}
|
||||
|
||||
void audio::algo::river::Lms::setMu(double _val) {
|
||||
if (m_private == nullptr) {
|
||||
AA_RIVER_ERROR("Algo is not initialized...");
|
||||
}
|
||||
m_private->setMu(_val);
|
||||
}
|
@ -5,14 +5,18 @@
|
||||
* @license APACHE v2.0 (see license file)
|
||||
*/
|
||||
|
||||
#ifndef __AUDIO_ALGO_AEC_LMS_H__
|
||||
#define __AUDIO_ALGO_AEC_LMS_H__
|
||||
#ifndef __AUDIO_ALGO_RIVER_LMS_H__
|
||||
#define __AUDIO_ALGO_RIVER_LMS_H__
|
||||
|
||||
#include <etk/types.h>
|
||||
#include <etk/chrono.h>
|
||||
#include <audio/format.h>
|
||||
#include <etk/memory.h>
|
||||
|
||||
namespace audio {
|
||||
namespace algo {
|
||||
namespace aec {
|
||||
namespace river {
|
||||
class LmsPrivate;
|
||||
/**
|
||||
* @brief Least Mean Square (LMS) algorithm "echo canceller"
|
||||
* base on publication: http://www.arpapress.com/Volumes/Vol7Issue1/IJRRAS_7_1_05.pdf
|
||||
@ -70,64 +74,60 @@ namespace audio {
|
||||
/**
|
||||
* @brief Constructor
|
||||
*/
|
||||
Lms(void);
|
||||
Lms();
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
~Lms(void);
|
||||
virtual ~Lms();
|
||||
public:
|
||||
/**
|
||||
* @brief Reset filter history and filter
|
||||
* @brief Reset algorithm
|
||||
*/
|
||||
void reset(void);
|
||||
virtual void reset();
|
||||
/**
|
||||
* @brief Process 16 bit LMS (input 16 bits)
|
||||
* @param[in,out] _output output data of the LMS
|
||||
* @param[in] _feedback Input feedback of the signal: x(n)
|
||||
* @param[in] _microphone Input Microphone data: d(n)
|
||||
* @brief Initialize the Algorithm
|
||||
* @param[in] _nbChannel Number of channel in the stream.
|
||||
* @param[in] _sampleRate Sample rate.
|
||||
* @param[in] _format Input/output data format.
|
||||
*/
|
||||
bool process(int16_t* _output, const int16_t* _feedback, const int16_t* _microphone, int32_t _nbSample);
|
||||
virtual void init(int8_t _nbChannel, float _sampleRate, enum audio::format _format = audio::format_float);
|
||||
/**
|
||||
* @brief Process float LMS
|
||||
* @param[in,out] _output output data of the LMS
|
||||
* @param[in] _feedback Input feedback of the signal: x(n)
|
||||
* @param[in] _microphone Input Microphone data: d(n)
|
||||
* @brief Get list of format suported in input.
|
||||
* @return list of supported format
|
||||
*/
|
||||
bool process(float* _output, const float* _feedback, const float* _microphone, int32_t _nbSample);
|
||||
virtual std::vector<enum audio::format> getSupportedFormat();
|
||||
/**
|
||||
* @brief Get list of algorithm format suported. No format convertion.
|
||||
* @return list of supported format
|
||||
*/
|
||||
virtual std::vector<enum audio::format> getNativeSupportedFormat();
|
||||
/**
|
||||
* @brief Main input algo process.
|
||||
* @param[in,out] _output Output data.
|
||||
* @param[in] _input Input data.
|
||||
* @param[in] _inputFeedback Input feedback data (all time MONO).
|
||||
* @param[in] _nbChunk Number of chunk in the input buffer.
|
||||
* @param[in] _nbChannel Number of channel in the stream.
|
||||
*/
|
||||
virtual void process(void* _output, const void* _input, const void* _inputFeedback, size_t _nbChunk);
|
||||
protected:
|
||||
/**
|
||||
* @brief Process a single value of the LMS
|
||||
* @param[in] _feedback Pointer on the feedback data (with history and at the n(th) position
|
||||
* @param[in] _microphone Microphone single sample [-1..1]
|
||||
* @return New output value [-1..1]
|
||||
*/
|
||||
float processValue(float* _feedback, float _microphone);
|
||||
public:
|
||||
std11::shared_ptr<LmsPrivate> m_private; // private data.
|
||||
public: // parameter area:
|
||||
/**
|
||||
* @brief Set filter size with specifing the filter temporal size and his samplerate
|
||||
* @param[in] _sampleRate Current sample rate to apply filter
|
||||
* @param[in] _time Time of the filter size
|
||||
*/
|
||||
void setFilterSize(size_t _sampleRate, std11::chrono::microseconds _time);
|
||||
virtual void setFilterTime(std11::chrono::microseconds _time);
|
||||
/**
|
||||
* @brief Set filter size in number of sample
|
||||
* @param[in] _nbSample Sample size of the filter
|
||||
*/
|
||||
void setFilterSize(size_t _nbSample);
|
||||
virtual void setFilterSize(size_t _nbSample);
|
||||
/**
|
||||
* @brief Set Mu value for basic LMS value
|
||||
* @param[in] _val new mu value
|
||||
*/
|
||||
void setMu(float _val);
|
||||
private:
|
||||
std::vector<float> m_filter; //!< Current filter
|
||||
std::vector<float> m_feedBack; //!< Feedback history
|
||||
float m_mu; //!< mu step size
|
||||
public:
|
||||
// for debug only:
|
||||
std::vector<float> getFilter() {
|
||||
return m_filter;
|
||||
}
|
||||
virtual void setMu(double _val);
|
||||
};
|
||||
}
|
||||
}
|
241
audio/algo/river/Nlms.cpp
Normal file
241
audio/algo/river/Nlms.cpp
Normal file
@ -0,0 +1,241 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @author Fatima MARFOUQ
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
*/
|
||||
|
||||
#include <audio/algo/river/debug.h>
|
||||
#include <audio/algo/river/Nlms.h>
|
||||
#include <audio/algo/river/updateFilter.h>
|
||||
#include <audio/algo/river/convolution.h>
|
||||
#include <audio/algo/river/power.h>
|
||||
|
||||
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @author Fatima MARFOUQ
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
*/
|
||||
|
||||
#include <audio/algo/river/debug.h>
|
||||
#include <audio/algo/river/Nlms.h>
|
||||
#include <audio/algo/river/updateFilter.h>
|
||||
#include <audio/algo/river/convolution.h>
|
||||
|
||||
#define MAX_PROCESSING_BLOCK_SIZE (256)
|
||||
|
||||
namespace audio {
|
||||
namespace algo {
|
||||
namespace river {
|
||||
class NlmsPrivate {
|
||||
private:
|
||||
int8_t m_nbChannel;
|
||||
float m_sampleRate;
|
||||
enum audio::format m_format;
|
||||
std::vector<std::vector<float> > m_filter; //!< Current filter
|
||||
std::vector<std::vector<float> > m_feedBack; //!< Feedback history
|
||||
float m_mu; //!< mu step size
|
||||
public:
|
||||
NlmsPrivate() :
|
||||
m_nbChannel(1),
|
||||
m_sampleRate(48000),
|
||||
m_format(audio::format_float),
|
||||
m_filter(),
|
||||
m_feedBack(),
|
||||
m_mu(0.03f) {
|
||||
setFilterSize(256);
|
||||
}
|
||||
|
||||
~NlmsPrivate(void) {
|
||||
|
||||
}
|
||||
|
||||
void reset(void) {
|
||||
// simply reset filters.
|
||||
setFilterSize(m_filter.size());
|
||||
}
|
||||
|
||||
void init(int8_t _nbChannel, float _sampleRate, enum audio::format _format) {
|
||||
m_nbChannel = _nbChannel;
|
||||
m_sampleRate = _sampleRate;
|
||||
m_format = _format;
|
||||
setFilterSize(m_filter.size());
|
||||
switch (m_format) {
|
||||
case audio::format_int16:
|
||||
case audio::format_float:
|
||||
break;
|
||||
default:
|
||||
AA_RIVER_ERROR("Can not INIT LMS with unsupported format : " << m_format);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void process(void* _output, const void* _input, const void* _inputFeedback, size_t _nbChunk) {
|
||||
switch (m_format) {
|
||||
case audio::format_int16:
|
||||
processI16(reinterpret_cast<int16_t*>(_output),
|
||||
reinterpret_cast<const int16_t*>(_inputFeedback),
|
||||
reinterpret_cast<const int16_t*>(_input),
|
||||
_nbChunk);
|
||||
break;
|
||||
case audio::format_float:
|
||||
processFloat(reinterpret_cast<float*>(_output),
|
||||
reinterpret_cast<const float*>(_inputFeedback),
|
||||
reinterpret_cast<const float*>(_input),
|
||||
_nbChunk);
|
||||
break;
|
||||
default:
|
||||
AA_RIVER_ERROR("Can not Echo remove with unsupported format : " << m_format);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool processI16(int16_t* _output, const int16_t* _microphone, const int16_t* _feedback, int32_t _nbSample) {
|
||||
bool ret = false;
|
||||
int32_t processingSize = MAX_PROCESSING_BLOCK_SIZE*m_nbChannel;
|
||||
// due to the fact we allocate the data in the stack:
|
||||
int32_t nbCycle = _nbSample/processingSize;
|
||||
if (_nbSample - int32_t(_nbSample/processingSize)*processingSize != 0 ) {
|
||||
nbCycle++;
|
||||
}
|
||||
for (int32_t bbb=0; bbb<nbCycle; ++bbb) {
|
||||
float output[processingSize];
|
||||
float feedback[processingSize];
|
||||
float microphone[processingSize];
|
||||
int32_t offset = bbb*processingSize;
|
||||
int32_t nbData = std::min(processingSize,
|
||||
_nbSample - offset);
|
||||
for (size_t iii=0; iii<nbData; ++iii) {
|
||||
microphone[iii] = float(_microphone[offset+iii])/32767.0f;
|
||||
feedback[iii] = float(_feedback[offset+iii])/32767.0f;
|
||||
}
|
||||
ret = processFloat(output, feedback, microphone, nbData);
|
||||
for (size_t iii=0; iii<nbData; ++iii) {
|
||||
_output[offset+iii] = int16_t(float(output[iii])*32767.0f);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool processFloat(float* _output, const float* _microphone, const float* _feedback, int32_t _nbSample) {
|
||||
for (int8_t kkk=0; kkk<m_nbChannel; ++kkk) {
|
||||
// add sample in the feedback history:
|
||||
m_feedBack[kkk].resize(m_filter[kkk].size()+_nbSample, 0.0f);
|
||||
memcpy(&m_feedBack[kkk][m_filter[kkk].size()], _feedback, _nbSample*sizeof(float));
|
||||
for (int32_t iii=0; iii < _nbSample; iii++) {
|
||||
_output[iii] = processValue(&m_feedBack[kkk][m_filter[kkk].size()+iii], _microphone[iii], m_filter[kkk]);
|
||||
}
|
||||
// remove old value:
|
||||
m_feedBack[kkk].erase(m_feedBack[kkk].begin(), m_feedBack[kkk].begin() + (m_feedBack[kkk].size()-m_filter[kkk].size()) );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
float processValue(float* _feedback, float _microphone, std::vector<float>& _filter) {
|
||||
// Error calculation.
|
||||
float convolutionValue = audio::algo::river::convolution(_feedback, &_filter[0], _filter.size());
|
||||
float error = _microphone - convolutionValue;
|
||||
float out = std::avg(-1.0f, error, 1.0f);
|
||||
// calculate mu:
|
||||
float mu = audio::algo::river::power(_feedback, _filter.size());
|
||||
//mu = *_feedback * *_feedback;
|
||||
//AA_RIVER_WARNING("Mu =" << mu);
|
||||
if (mu <= 1.5f) {
|
||||
// Not enought power in output
|
||||
mu = 0.0001; // arbitrary
|
||||
} else {
|
||||
mu = 1.0f/mu;
|
||||
//AA_RIVER_WARNING("Mu =" << mu);
|
||||
}
|
||||
audio::algo::river::updateFilter(&_filter[0], _feedback, error*m_mu, _filter.size());
|
||||
return out;
|
||||
}
|
||||
|
||||
void setFilterTime(std11::chrono::microseconds _time) {
|
||||
setFilterSize((m_sampleRate*_time.count())/1000000LL);
|
||||
}
|
||||
|
||||
void setFilterSize(size_t _nbSample) {
|
||||
m_filter.clear();
|
||||
m_feedBack.clear();
|
||||
m_filter.resize(m_nbChannel);
|
||||
m_feedBack.resize(m_nbChannel);
|
||||
for (int8_t kkk=0; kkk<m_nbChannel; ++kkk) {
|
||||
m_filter[kkk].resize(_nbSample, 0.0f);
|
||||
m_feedBack[kkk].resize(_nbSample, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void setMu(float _val) {
|
||||
m_mu = _val;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
audio::algo::river::Nlms::Nlms(void) {
|
||||
|
||||
}
|
||||
|
||||
audio::algo::river::Nlms::~Nlms(void) {
|
||||
|
||||
}
|
||||
|
||||
void audio::algo::river::Nlms::reset(void) {
|
||||
if (m_private == nullptr) {
|
||||
AA_RIVER_ERROR("Algo is not initialized...");
|
||||
}
|
||||
m_private->reset();
|
||||
}
|
||||
|
||||
void audio::algo::river::Nlms::init(int8_t _nbChannel, float _sampleRate, enum audio::format _format) {
|
||||
if (m_private == nullptr) {
|
||||
m_private = std::make_shared<audio::algo::river::NlmsPrivate>();
|
||||
}
|
||||
m_private->init(_nbChannel, _sampleRate, _format);
|
||||
}
|
||||
|
||||
std::vector<enum audio::format> audio::algo::river::Nlms::getSupportedFormat() {
|
||||
std::vector<enum audio::format> out = getNativeSupportedFormat();
|
||||
out.push_back(audio::format_int16);
|
||||
return out;
|
||||
}
|
||||
|
||||
std::vector<enum audio::format> audio::algo::river::Nlms::getNativeSupportedFormat() {
|
||||
std::vector<enum audio::format> out;
|
||||
out.push_back(audio::format_float);
|
||||
return out;
|
||||
}
|
||||
|
||||
void audio::algo::river::Nlms::process(void* _output, const void* _input, const void* _inputFeedback, size_t _nbChunk) {
|
||||
if (m_private == nullptr) {
|
||||
AA_RIVER_ERROR("Algo is not initialized...");
|
||||
}
|
||||
m_private->process(_output, _input, _inputFeedback, _nbChunk);
|
||||
}
|
||||
|
||||
|
||||
void audio::algo::river::Nlms::setFilterTime(std11::chrono::microseconds _time) {
|
||||
if (m_private == nullptr) {
|
||||
AA_RIVER_ERROR("Algo is not initialized...");
|
||||
}
|
||||
m_private->setFilterTime(_time);
|
||||
}
|
||||
|
||||
void audio::algo::river::Nlms::setFilterSize(size_t _nbSample) {
|
||||
if (m_private == nullptr) {
|
||||
AA_RIVER_ERROR("Algo is not initialized...");
|
||||
}
|
||||
m_private->setFilterSize(_nbSample);
|
||||
}
|
||||
|
||||
void audio::algo::river::Nlms::setMu(double _val) {
|
||||
if (m_private == nullptr) {
|
||||
AA_RIVER_ERROR("Algo is not initialized...");
|
||||
}
|
||||
m_private->setMu(_val);
|
||||
}
|
||||
|
@ -5,14 +5,18 @@
|
||||
* @license APACHE v2.0 (see license file)
|
||||
*/
|
||||
|
||||
#ifndef __AUDIO_ALGO_AEC_NLMS_H__
|
||||
#define __AUDIO_ALGO_AEC_NLMS_H__
|
||||
#ifndef __AUDIO_ALGO_RIVER_NLMS_H__
|
||||
#define __AUDIO_ALGO_RIVER_NLMS_H__
|
||||
|
||||
#include <etk/types.h>
|
||||
#include <etk/chrono.h>
|
||||
#include <audio/format.h>
|
||||
#include <etk/memory.h>
|
||||
|
||||
namespace audio {
|
||||
namespace algo {
|
||||
namespace aec {
|
||||
namespace river {
|
||||
class NlmsPrivate;
|
||||
/**
|
||||
* @brief Least Mean Square (LMS) algorithm "echo canceller"
|
||||
* base on publication: http://www.arpapress.com/Volumes/Vol7Issue1/IJRRAS_7_1_05.pdf
|
||||
@ -70,58 +74,60 @@ namespace audio {
|
||||
/**
|
||||
* @brief Constructor
|
||||
*/
|
||||
Nlms(void);
|
||||
Nlms();
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
~Nlms(void);
|
||||
virtual ~Nlms();
|
||||
public:
|
||||
/**
|
||||
* @brief Reset filter history and filter
|
||||
* @brief Reset algorithm
|
||||
*/
|
||||
void reset(void);
|
||||
virtual void reset();
|
||||
/**
|
||||
* @brief Process 16 bit LMS (input 16 bits)
|
||||
* @param[in,out] _output output data of the LMS
|
||||
* @param[in] _feedback Input feedback of the signal: x(n)
|
||||
* @param[in] _microphone Input Microphone data: d(n)
|
||||
* @brief Initialize the Algorithm
|
||||
* @param[in] _nbChannel Number of channel in the stream.
|
||||
* @param[in] _sampleRate Sample rate.
|
||||
* @param[in] _format Input/output data format.
|
||||
*/
|
||||
bool process(int16_t* _output, const int16_t* _feedback, const int16_t* _microphone, int32_t _nbSample);
|
||||
virtual void init(int8_t _nbChannel, float _sampleRate, enum audio::format _format = audio::format_float);
|
||||
/**
|
||||
* @brief Process float LMS
|
||||
* @param[in,out] _output output data of the LMS
|
||||
* @param[in] _feedback Input feedback of the signal: x(n)
|
||||
* @param[in] _microphone Input Microphone data: d(n)
|
||||
* @brief Get list of format suported in input.
|
||||
* @return list of supported format
|
||||
*/
|
||||
bool process(float* _output, const float* _feedback, const float* _microphone, int32_t _nbSample);
|
||||
virtual std::vector<enum audio::format> getSupportedFormat();
|
||||
/**
|
||||
* @brief Get list of algorithm format suported. No format convertion.
|
||||
* @return list of supported format
|
||||
*/
|
||||
virtual std::vector<enum audio::format> getNativeSupportedFormat();
|
||||
/**
|
||||
* @brief Main input algo process.
|
||||
* @param[in,out] _output Output data.
|
||||
* @param[in] _input Input data.
|
||||
* @param[in] _inputFeedback Input feedback data (all time MONO).
|
||||
* @param[in] _nbChunk Number of chunk in the input buffer.
|
||||
* @param[in] _nbChannel Number of channel in the stream.
|
||||
*/
|
||||
virtual void process(void* _output, const void* _input, const void* _inputFeedback, size_t _nbChunk);
|
||||
protected:
|
||||
/**
|
||||
* @brief Process a single value of the LMS
|
||||
* @param[in] _feedback Pointer on the feedback data (with history and at the n(th) position
|
||||
* @param[in] _microphone Microphone single sample [-1..1]
|
||||
* @return New output value [-1..1]
|
||||
*/
|
||||
float processValue(float* _feedback, float _microphone);
|
||||
public:
|
||||
std11::shared_ptr<NlmsPrivate> m_private; // private data.
|
||||
public: // parameter area:
|
||||
/**
|
||||
* @brief Set filter size with specifing the filter temporal size and his samplerate
|
||||
* @param[in] _sampleRate Current sample rate to apply filter
|
||||
* @param[in] _time Time of the filter size
|
||||
*/
|
||||
void setFilterSize(size_t _sampleRate, std11::chrono::microseconds _time);
|
||||
virtual void setFilterTime(std11::chrono::microseconds _time);
|
||||
/**
|
||||
* @brief Set filter size in number of sample
|
||||
* @param[in] _nbSample Sample size of the filter
|
||||
*/
|
||||
void setFilterSize(size_t _nbSample);
|
||||
private:
|
||||
std::vector<float> m_filter; //!< Current filter
|
||||
std::vector<float> m_feedBack; //!< Feedback history
|
||||
public:
|
||||
// for debug only:
|
||||
std::vector<float> getFilter() {
|
||||
return m_filter;
|
||||
}
|
||||
virtual void setFilterSize(size_t _nbSample);
|
||||
/**
|
||||
* @brief Set Mu value for basic LMS value
|
||||
* @param[in] _val new mu value
|
||||
*/
|
||||
virtual void setMu(double _val);
|
||||
};
|
||||
}
|
||||
}
|
@ -5,9 +5,9 @@
|
||||
* @license APACHE v2.0 (see license file)
|
||||
*/
|
||||
|
||||
#include <audio/algo/aec/convolution.h>
|
||||
#include <audio/algo/river/convolution.h>
|
||||
|
||||
float audio::algo::aec::convolution(float* _dataMinus, float* _dataPlus, size_t _count) {
|
||||
float audio::algo::river::convolution(float* _dataMinus, float* _dataPlus, size_t _count) {
|
||||
float out = 0.0f;
|
||||
for (size_t iii = 0; iii < _count; ++iii) {
|
||||
out += *_dataMinus-- * *_dataPlus++;
|
@ -5,14 +5,14 @@
|
||||
* @license APACHE v2.0 (see license file)
|
||||
*/
|
||||
|
||||
#ifndef __AUDIO_ALGO_AEC_CONVOLUTION_H__
|
||||
#define __AUDIO_ALGO_AEC_CONVOLUTION_H__
|
||||
#ifndef __AUDIO_ALGO_RIVER_CONVOLUTION_H__
|
||||
#define __AUDIO_ALGO_RIVER_CONVOLUTION_H__
|
||||
|
||||
#include <etk/types.h>
|
||||
|
||||
namespace audio {
|
||||
namespace algo {
|
||||
namespace aec {
|
||||
namespace river {
|
||||
float convolution(float* _dataMinus, float* _dataPlus, size_t _count);
|
||||
}
|
||||
}
|
@ -7,8 +7,8 @@
|
||||
#include "debug.h"
|
||||
|
||||
|
||||
int32_t audio::algo::aec::getLogId() {
|
||||
static int32_t g_val = etk::log::registerInstance("audio-algo-aec");
|
||||
int32_t audio::algo::river::getLogId() {
|
||||
static int32_t g_val = etk::log::registerInstance("audio-algo-river");
|
||||
return g_val;
|
||||
}
|
||||
|
45
audio/algo/river/debug.h
Normal file
45
audio/algo/river/debug.h
Normal file
@ -0,0 +1,45 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
*/
|
||||
|
||||
#ifndef __APPL_DEBUG_H__
|
||||
#define __APPL_DEBUG_H__
|
||||
|
||||
#include <etk/log.h>
|
||||
|
||||
namespace audio {
|
||||
namespace algo {
|
||||
namespace river {
|
||||
int32_t getLogId();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define AA_RIVER_BASE(info,data) TK_LOG_BASE(audio::algo::river::getLogId(),info,data)
|
||||
|
||||
#define AA_RIVER_CRITICAL(data) AA_RIVER_BASE(1, data)
|
||||
#define AA_RIVER_ERROR(data) AA_RIVER_BASE(2, data)
|
||||
#define AA_RIVER_WARNING(data) AA_RIVER_BASE(3, data)
|
||||
#ifdef DEBUG
|
||||
#define AA_RIVER_INFO(data) AA_RIVER_BASE(4, data)
|
||||
#define AA_RIVER_DEBUG(data) AA_RIVER_BASE(5, data)
|
||||
#define AA_RIVER_VERBOSE(data) AA_RIVER_BASE(6, data)
|
||||
#define AA_RIVER_TODO(data) AA_RIVER_BASE(4, "TODO : " << data)
|
||||
#else
|
||||
#define AA_RIVER_INFO(data) do { } while(false)
|
||||
#define AA_RIVER_DEBUG(data) do { } while(false)
|
||||
#define AA_RIVER_VERBOSE(data) do { } while(false)
|
||||
#define AA_RIVER_TODO(data) do { } while(false)
|
||||
#endif
|
||||
|
||||
#define AA_RIVER_ASSERT(cond,data) \
|
||||
do { \
|
||||
if (!(cond)) { \
|
||||
APPL_CRITICAL(data); \
|
||||
assert(!#cond); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#endif
|
@ -5,10 +5,10 @@
|
||||
* @license APACHE v2.0 (see license file)
|
||||
*/
|
||||
|
||||
#include <audio/algo/aec/power.h>
|
||||
#include <audio/algo/river/power.h>
|
||||
|
||||
|
||||
float audio::algo::aec::power(float* _data, int32_t _count) {
|
||||
float audio::algo::river::power(float* _data, int32_t _count) {
|
||||
float out = 0;
|
||||
for (size_t iii = 0; iii < _count; ++iii) {
|
||||
out += *_data * *_data;
|
@ -5,14 +5,14 @@
|
||||
* @license APACHE v2.0 (see license file)
|
||||
*/
|
||||
|
||||
#ifndef __AUDIO_ALGO_AEC_POWER_H__
|
||||
#define __AUDIO_ALGO_AEC_POWER_H__
|
||||
#ifndef __AUDIO_ALGO_RIVER_POWER_H__
|
||||
#define __AUDIO_ALGO_RIVER_POWER_H__
|
||||
|
||||
#include <etk/types.h>
|
||||
|
||||
namespace audio {
|
||||
namespace algo {
|
||||
namespace aec {
|
||||
namespace river {
|
||||
float power(float* _data, int32_t _count);
|
||||
}
|
||||
}
|
@ -5,10 +5,10 @@
|
||||
* @license APACHE v2.0 (see license file)
|
||||
*/
|
||||
|
||||
#include <audio/algo/aec/updateFilter.h>
|
||||
#include <audio/algo/river/updateFilter.h>
|
||||
|
||||
|
||||
void audio::algo::aec::updateFilter(float* _filter, float* _data, float _value, int32_t _count) {
|
||||
void audio::algo::river::updateFilter(float* _filter, float* _data, float _value, int32_t _count) {
|
||||
for (size_t iii = 0; iii < _count; ++iii) {
|
||||
*(_filter++) += *_data-- * _value;
|
||||
}
|
@ -5,14 +5,14 @@
|
||||
* @license APACHE v2.0 (see license file)
|
||||
*/
|
||||
|
||||
#ifndef __AUDIO_ALGO_AEC_UPDATE_FILTER_H__
|
||||
#define __AUDIO_ALGO_AEC_UPDATE_FILTER_H__
|
||||
#ifndef __AUDIO_ALGO_RIVER_UPDATE_FILTER_H__
|
||||
#define __AUDIO_ALGO_RIVER_UPDATE_FILTER_H__
|
||||
|
||||
#include <etk/types.h>
|
||||
|
||||
namespace audio {
|
||||
namespace algo {
|
||||
namespace aec {
|
||||
namespace river {
|
||||
void updateFilter(float* _filter, float* _data, float _value, int32_t _count);
|
||||
}
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
import lutinModule as module
|
||||
import lutinTools as tools
|
||||
import lutinDebug as debug
|
||||
|
||||
def get_desc():
|
||||
return "audio_algo_aec : AEC basic algo"
|
||||
|
||||
|
||||
def create(target):
|
||||
myModule = module.Module(__file__, 'audio_algo_aec', 'LIBRARY')
|
||||
myModule.add_src_file([
|
||||
'audio/algo/aec/debug.cpp',
|
||||
'audio/algo/aec/convolution.cpp',
|
||||
'audio/algo/aec/power.cpp',
|
||||
'audio/algo/aec/updateFilter.cpp',
|
||||
'audio/algo/aec/Lms.cpp',
|
||||
'audio/algo/aec/Nlms.cpp'
|
||||
])
|
||||
myModule.add_module_depend(['etk'])
|
||||
myModule.add_export_path(tools.get_current_path(__file__))
|
||||
# return module
|
||||
return myModule
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
32
lutin_audio_algo_river.py
Normal file
32
lutin_audio_algo_river.py
Normal file
@ -0,0 +1,32 @@
|
||||
#!/usr/bin/python
|
||||
import lutinModule as module
|
||||
import lutinTools as tools
|
||||
import lutinDebug as debug
|
||||
|
||||
def get_desc():
|
||||
return "audio_algo_river : AEC basic algo"
|
||||
|
||||
|
||||
def create(target):
|
||||
myModule = module.Module(__file__, 'audio_algo_river', 'LIBRARY')
|
||||
myModule.add_src_file([
|
||||
'audio/algo/river/debug.cpp',
|
||||
'audio/algo/river/convolution.cpp',
|
||||
'audio/algo/river/power.cpp',
|
||||
'audio/algo/river/updateFilter.cpp',
|
||||
'audio/algo/river/Lms.cpp',
|
||||
'audio/algo/river/Nlms.cpp'
|
||||
])
|
||||
myModule.add_module_depend(['etk', 'audio'])
|
||||
myModule.add_export_path(tools.get_current_path(__file__))
|
||||
# return module
|
||||
return myModule
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -8,12 +8,12 @@ def get_desc():
|
||||
|
||||
|
||||
def create(target):
|
||||
myModule = module.Module(__file__, 'audio_algo_aec_test', 'BINARY')
|
||||
myModule = module.Module(__file__, 'audio_algo_river_test', 'BINARY')
|
||||
myModule.add_src_file([
|
||||
'test/main.cpp',
|
||||
'test/debug.cpp'
|
||||
])
|
||||
myModule.add_module_depend(['audio_algo_aec'])
|
||||
myModule.add_module_depend(['audio_algo_river'])
|
||||
return myModule
|
||||
|
||||
|
115
test/main.cpp
115
test/main.cpp
@ -6,8 +6,8 @@
|
||||
|
||||
#include <test/debug.h>
|
||||
#include <etk/etk.h>
|
||||
#include <audio/algo/aec/Lms.h>
|
||||
#include <audio/algo/aec/Nlms.h>
|
||||
#include <audio/algo/river/Lms.h>
|
||||
#include <audio/algo/river/Nlms.h>
|
||||
#include <etk/os/FSNode.h>
|
||||
#include <etk/chrono.h>
|
||||
#include <etk/thread/tools.h>
|
||||
@ -17,6 +17,51 @@
|
||||
#define __class__ "test"
|
||||
|
||||
|
||||
class Performance {
|
||||
private:
|
||||
std11::chrono::steady_clock::time_point m_timeStart;
|
||||
std11::chrono::steady_clock::time_point m_timeStop;
|
||||
std11::chrono::nanoseconds m_totalTimeProcessing;
|
||||
std11::chrono::nanoseconds m_minProcessing;
|
||||
std11::chrono::nanoseconds m_maxProcessing;
|
||||
int32_t m_totalIteration;
|
||||
public:
|
||||
Performance() :
|
||||
m_totalTimeProcessing(0),
|
||||
m_minProcessing(99999999999999LL),
|
||||
m_maxProcessing(0),
|
||||
m_totalIteration(0) {
|
||||
|
||||
}
|
||||
void tic() {
|
||||
m_timeStart = std11::chrono::steady_clock::now();
|
||||
}
|
||||
void toc() {
|
||||
m_timeStop = std11::chrono::steady_clock::now();
|
||||
std11::chrono::nanoseconds time = m_timeStop - m_timeStart;
|
||||
m_minProcessing = std::min(m_minProcessing, time);
|
||||
m_maxProcessing = std::max(m_maxProcessing, time);
|
||||
m_totalTimeProcessing += time;
|
||||
m_totalIteration++;
|
||||
|
||||
}
|
||||
|
||||
std11::chrono::nanoseconds getTotalTimeProcessing() {
|
||||
return m_totalTimeProcessing;
|
||||
}
|
||||
std11::chrono::nanoseconds getMinProcessing() {
|
||||
return m_minProcessing;
|
||||
}
|
||||
std11::chrono::nanoseconds getMaxProcessing() {
|
||||
return m_maxProcessing;
|
||||
}
|
||||
int32_t getTotalIteration() {
|
||||
return m_totalIteration;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
int main(int _argc, const char** _argv) {
|
||||
// the only one init for etk:
|
||||
etk::init(_argc, _argv);
|
||||
@ -67,6 +112,9 @@ int main(int _argc, const char** _argv) {
|
||||
APPL_ERROR("Can not Process missing parameters...");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
Performance perfo;
|
||||
|
||||
APPL_INFO("Read FeedBack:");
|
||||
std::vector<int16_t> fbData = etk::FSNodeReadAllDataType<int16_t>(fbName);
|
||||
APPL_INFO(" " << fbData.size() << " samples");
|
||||
@ -78,17 +126,12 @@ int main(int _argc, const char** _argv) {
|
||||
output.resize(std::min(fbData.size(), micData.size()), 0);
|
||||
// process in chunk of 256 samples
|
||||
int32_t blockSize = 256;
|
||||
// end filter :
|
||||
std::vector<float> filter;
|
||||
std11::chrono::nanoseconds totalTimeProcessing(0);
|
||||
std11::chrono::nanoseconds minProcessing(99999999999999LL);
|
||||
std11::chrono::nanoseconds maxProcessing(0);
|
||||
int32_t totalIteration = 0;
|
||||
if (nlms == false) {
|
||||
APPL_PRINT("***********************");
|
||||
APPL_PRINT("** LMS **");
|
||||
APPL_PRINT("***********************");
|
||||
audio::algo::aec::Lms algo;
|
||||
audio::algo::river::Lms algo;
|
||||
algo.init(1, sampleRate, audio::format_float);
|
||||
if (filterSize != 0) {
|
||||
algo.setFilterSize(filterSize);
|
||||
}
|
||||
@ -103,24 +146,19 @@ int main(int _argc, const char** _argv) {
|
||||
} else {
|
||||
APPL_VERBOSE("Process : " << iii*blockSize << "/" << int32_t(output.size()/blockSize)*blockSize);
|
||||
}
|
||||
std11::chrono::steady_clock::time_point timeStart = std11::chrono::steady_clock::now();
|
||||
perfo.tic();
|
||||
algo.process(&output[iii*blockSize], &fbData[iii*blockSize], &micData[iii*blockSize], blockSize);
|
||||
if (perf == true) {
|
||||
std11::chrono::steady_clock::time_point timeEnd = std11::chrono::steady_clock::now();
|
||||
std11::chrono::nanoseconds time = timeEnd - timeStart;
|
||||
minProcessing = std::min(minProcessing, time);
|
||||
maxProcessing = std::max(maxProcessing, time);
|
||||
totalTimeProcessing += time;
|
||||
totalIteration++;
|
||||
usleep(10000);
|
||||
perfo.toc();
|
||||
usleep(1000);
|
||||
}
|
||||
}
|
||||
filter = algo.getFilter();
|
||||
} else {
|
||||
APPL_PRINT("***********************");
|
||||
APPL_PRINT("** NLMS (power) **");
|
||||
APPL_PRINT("***********************");
|
||||
audio::algo::aec::Nlms algo;
|
||||
audio::algo::river::Nlms algo;
|
||||
algo.init(1, sampleRate, audio::format_float);
|
||||
if (filterSize != 0) {
|
||||
algo.setFilterSize(filterSize);
|
||||
}
|
||||
@ -132,38 +170,27 @@ int main(int _argc, const char** _argv) {
|
||||
} else {
|
||||
APPL_VERBOSE("Process : " << iii*blockSize << "/" << int32_t(output.size()/blockSize)*blockSize);
|
||||
}
|
||||
perfo.tic();
|
||||
algo.process(&output[iii*blockSize], &fbData[iii*blockSize], &micData[iii*blockSize], blockSize);
|
||||
if (perf == true) {
|
||||
perfo.toc();
|
||||
usleep(1000);
|
||||
}
|
||||
}
|
||||
filter = algo.getFilter();
|
||||
}
|
||||
APPL_PRINT("Process done");
|
||||
if (perf == true) {
|
||||
APPL_PRINT("Performance Result: ");
|
||||
APPL_PRINT(" blockSize=" << blockSize << " sample");
|
||||
APPL_PRINT(" total data time=" << int64_t(totalIteration)*int64_t(blockSize)*1000000000LL/int64_t(sampleRate) << " ns");
|
||||
APPL_PRINT(" min=" << minProcessing.count() << " ns");
|
||||
APPL_PRINT(" max=" << maxProcessing.count() << " ns");
|
||||
APPL_PRINT(" avg=" << totalTimeProcessing.count()/totalIteration << " ns");
|
||||
|
||||
APPL_PRINT(" " << sampleRate << " Hz");
|
||||
APPL_PRINT(" min=" << (float((minProcessing.count()*sampleRate)/blockSize)/1000000000.0)*100.0 << " %");
|
||||
APPL_PRINT(" max=" << (float((maxProcessing.count()*sampleRate)/blockSize)/1000000000.0)*100.0 << " %");
|
||||
APPL_PRINT(" avg=" << (float(((totalTimeProcessing.count()/totalIteration)*sampleRate)/blockSize)/1000000000.0)*100.0 << " %");
|
||||
APPL_PRINT(" 48000 Hz");
|
||||
sampleRate = 48000;
|
||||
APPL_PRINT(" avg=" << (float(((totalTimeProcessing.count()/totalIteration)*sampleRate)/blockSize)/1000000000.0)*100.0 << " %");
|
||||
APPL_PRINT(" 32000 Hz");
|
||||
sampleRate = 32000;
|
||||
APPL_PRINT(" avg=" << (float(((totalTimeProcessing.count()/totalIteration)*sampleRate)/blockSize)/1000000000.0)*100.0 << " %");
|
||||
APPL_PRINT(" 16000 Hz");
|
||||
sampleRate = 16000;
|
||||
APPL_PRINT(" avg=" << (float(((totalTimeProcessing.count()/totalIteration)*sampleRate)/blockSize)/1000000000.0)*100.0 << " %");
|
||||
APPL_PRINT(" 8000 Hz");
|
||||
sampleRate = 8000;
|
||||
APPL_PRINT(" avg=" << (float(((totalTimeProcessing.count()/totalIteration)*sampleRate)/blockSize)/1000000000.0)*100.0 << " %");
|
||||
APPL_INFO(" blockSize=" << blockSize << " sample");
|
||||
APPL_INFO(" min < avg < max =" << perfo.getMinProcessing().count() << "ns < "
|
||||
<< perfo.getTotalTimeProcessing().count()/perfo.getTotalIteration() << "ns < "
|
||||
<< perfo.getMaxProcessing().count() << "ns ");
|
||||
float avg = (float(((perfo.getTotalTimeProcessing().count()/perfo.getTotalIteration())*sampleRate)/double(blockSize))/1000000000.0)*100.0;
|
||||
APPL_INFO(" min < avg < max= " << (float((perfo.getMinProcessing().count()*sampleRate)/double(blockSize))/1000000000.0)*100.0 << "% < "
|
||||
<< avg << "% < "
|
||||
<< (float((perfo.getMaxProcessing().count()*sampleRate)/double(blockSize))/1000000000.0)*100.0 << "%");
|
||||
APPL_PRINT("float : " << sampleRate << " : " << avg << "%");
|
||||
}
|
||||
etk::FSNodeWriteAllDataType<int16_t>("output.raw", output);
|
||||
etk::FSNodeWriteAllDataType<float>("filter.raw", filter);
|
||||
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user