diff --git a/drain/Algo.h b/drain/Algo.h index 91bf025..1afd28b 100644 --- a/drain/Algo.h +++ b/drain/Algo.h @@ -5,8 +5,8 @@ */ -#ifndef __AIRT_ALGO_CORE_ALGO_H__ -#define __AIRT_ALGO_CORE_ALGO_H__ +#ifndef __DRAIN_ALGO_CORE_ALGO_H__ +#define __DRAIN_ALGO_CORE_ALGO_H__ #include #include diff --git a/drain/AutoLogInOut.h b/drain/AutoLogInOut.h index a9d86e4..f9a38aa 100644 --- a/drain/AutoLogInOut.h +++ b/drain/AutoLogInOut.h @@ -5,8 +5,8 @@ */ -#ifndef __AIRT_ALGO_AUTO_LOG_IN_OUT_H__ -#define __AIRT_ALGO_AUTO_LOG_IN_OUT_H__ +#ifndef __DRAIN_ALGO_AUTO_LOG_IN_OUT_H__ +#define __DRAIN_ALGO_AUTO_LOG_IN_OUT_H__ #include #include "debug.h" diff --git a/drain/ChannelReorder.h b/drain/ChannelReorder.h index b69547d..c29139d 100644 --- a/drain/ChannelReorder.h +++ b/drain/ChannelReorder.h @@ -4,8 +4,8 @@ * @license APACHE v2.0 (see license file) */ -#ifndef __AIRT_ALGO_CHANNEL_REORDER_H__ -#define __AIRT_ALGO_CHANNEL_REORDER_H__ +#ifndef __DRAIN_ALGO_CHANNEL_REORDER_H__ +#define __DRAIN_ALGO_CHANNEL_REORDER_H__ #include diff --git a/drain/EndPoint.h b/drain/EndPoint.h index 67cea39..c95982a 100644 --- a/drain/EndPoint.h +++ b/drain/EndPoint.h @@ -4,8 +4,8 @@ * @license APACHE v2.0 (see license file) */ -#ifndef __AIRT_ALGO_END_POINT_H__ -#define __AIRT_ALGO_END_POINT_H__ +#ifndef __DRAIN_ALGO_END_POINT_H__ +#define __DRAIN_ALGO_END_POINT_H__ #include diff --git a/drain/EndPointCallback.h b/drain/EndPointCallback.h index ac13bea..ea8b9da 100644 --- a/drain/EndPointCallback.h +++ b/drain/EndPointCallback.h @@ -4,8 +4,8 @@ * @license APACHE v2.0 (see license file) */ -#ifndef __AIRT_ALGO_END_POINT_CALLBACK_H__ -#define __AIRT_ALGO_END_POINT_CALLBACK_H__ +#ifndef __DRAIN_ALGO_END_POINT_CALLBACK_H__ +#define __DRAIN_ALGO_END_POINT_CALLBACK_H__ #include #include diff --git a/drain/EndPointRead.h b/drain/EndPointRead.h index 37530fc..83e182f 100644 --- a/drain/EndPointRead.h +++ b/drain/EndPointRead.h @@ -4,8 +4,8 @@ * @license APACHE v2.0 (see license file) */ -#ifndef __AIRT_ALGO_END_POINT_READ_H__ -#define __AIRT_ALGO_END_POINT_READ_H__ +#ifndef __DRAIN_ALGO_END_POINT_READ_H__ +#define __DRAIN_ALGO_END_POINT_READ_H__ #include diff --git a/drain/EndPointWrite.h b/drain/EndPointWrite.h index e83c4b0..5725001 100644 --- a/drain/EndPointWrite.h +++ b/drain/EndPointWrite.h @@ -4,8 +4,8 @@ * @license APACHE v2.0 (see license file) */ -#ifndef __AIRT_ALGO_ALGO_END_POINT_WRITE_H__ -#define __AIRT_ALGO_ALGO_END_POINT_WRITE_H__ +#ifndef __DRAIN_ALGO_ALGO_END_POINT_WRITE_H__ +#define __DRAIN_ALGO_ALGO_END_POINT_WRITE_H__ #include #include diff --git a/drain/Equalizer.cpp b/drain/Equalizer.cpp new file mode 100644 index 0000000..f9c716c --- /dev/null +++ b/drain/Equalizer.cpp @@ -0,0 +1,246 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license APACHE v2.0 (see license file) + */ + +#include +#include +#include + +// see http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt + +drain::Equalizer::Equalizer() { + +} + +void drain::Equalizer::init() { + drain::Algo::init(); + drain::Algo::m_type = "Equalizer"; + m_supportedFormat.push_back(audio::format_int16); + m_type = drain::filterType_none; + m_gain = 0; + m_frequency = 1000; + m_bandWidth = 200; + configureBiQuad(); + // reset coefficients + m_b[0] = 1.0; + m_b[1] = 0.0; + m_b[2] = 0.0; + m_a[0] = 0.0; + m_a[1] = 0.0; +} + +std11::shared_ptr drain::Equalizer::create() { + std11::shared_ptr tmp(new drain::Equalizer()); + tmp->init(); + return tmp; +} + +drain::Equalizer::~Equalizer() { + +} + +void drain::Equalizer::configurationChange() { + drain::Algo::configurationChange(); + // Resize the configuration ouput of algirithm + m_history.clear(); + m_history.resize(getOutputFormat().getMap().size()); +} + +bool drain::Equalizer::process(std11::chrono::system_clock::time_point& _time, + void* _input, + size_t _inputNbChunk, + void*& _output, + size_t& _outputNbChunk) { + _outputNbChunk = _inputNbChunk; + _output = _input; + if (_input == nullptr) { + return false; + } + for (size_t jjj=0; jjj(_input); + // move to sample offset: + data += jjj; + for (size_t iii=0; iii<_inputNbChunk; ++iii) { + // process in float the biquad. + float out = processFloat(*data, m_history[jjj]); + // Limit output. + out = std::avg(-32768.0f, out, 32767.0f); + *data = static_cast(out); + // move to the sample on the same channel. + data += getOutputFormat().getMap().size(); + } + } + return true; +} + +bool drain::Equalizer::setParameter(const std::string& _parameter, const std::string& _value) { + if (_parameter == "type") { + if (_value == "none") { + m_type = drain::filterType_none; + } else if (_value == "LPF") { + m_type = drain::filterType_LPF; + } else if (_value == "HPF") { + m_type = drain::filterType_HPF; + } else if (_value == "BPF") { + m_type = drain::filterType_BPF; + } else if (_value == "NOTCH") { + m_type = drain::filterType_NOTCH; + } else if (_value == "APF") { + m_type = drain::filterType_APF; + } else if (_value == "PeakingEQ") { + m_type = drain::filterType_PeakingEQ; + } else if (_value == "LSH") { + m_type = drain::filterType_LSH; + } else if (_value == "HSH") { + m_type = drain::filterType_HSH; + } else if (_value == "EQU"){ + m_type = drain::filterType_EQU; + } else { + DRAIN_ERROR("Can not set equalizer type : " << _value); + return false; + } + configureBiQuad(); + return true; + } else if (_parameter == "gain") { + m_gain = etk::string_to_int32_t(_value); + configureBiQuad(); + return true; + } else if (_parameter == "frequency") { + m_frequency = etk::string_to_int32_t(_value); + configureBiQuad(); + return true; + } else if (_parameter == "band-width") { + m_bandWidth = etk::string_to_int32_t(_value); + configureBiQuad(); + return true; + } + return false; +} + +std::string drain::Equalizer::getParameter(const std::string& _parameter) const { + return "error"; +} + +std::string drain::Equalizer::getParameterProperty(const std::string& _parameter) const { + return "error"; +} + +float drain::Equalizer::processFloat(float _sample, drain::BGHistory& _history) { + float result; + // compute + result = m_b[0] * _sample + + m_b[1] * _history.m_x[0] + + m_b[2] * _history.m_x[1] + - m_a[0] * _history.m_y[0] + - m_a[1] * _history.m_y[1]; + //update history of X + _history.m_x[0] = _history.m_x[1]; + _history.m_x[1] = _sample; + //update history of Y + _history.m_y[0] = _history.m_y[1]; + _history.m_y[1] = result; + return result; +} + +bool drain::Equalizer::configureBiQuad() { + // reset biQuad. + m_b[0] = 1.0; + m_b[1] = 0.0; + m_b[2] = 0.0; + m_a[0] = 0.0; + m_a[1] = 0.0; + if (m_type == filterType_none) { + return true; + } + double a0, a1, a2, b0, b1, b2; + /* setup variables */ + double A = std::pow(10, m_gain /40); // used for peaking and shelving EQ filters only + double w0 = 2.0 * M_PI * double(m_frequency) / double(getOutputFormat().getFrequency()); + + // 2*sqrt(A)*alpha = sin(w0) * sqrt( (A^2 + 1)*(1/S - 1) + 2*A ) + // is a handy intermediate variable for shelving EQ filters. + double alpha = std::sin(w0) * std::sqrt((A*A+1.0)*(1.0/m_bandWidth - 1.0) + 2*A); + alpha /= 2.0*std::sqrt(A); + + + switch (m_type) { + case drain::filterType_LPF: + b0 = (1.0 - std::cos(w0)) * 0.5; + b1 = 1.0 - std::cos(w0); + b2 = (1.0 - std::cos(w0)) * 0.5; + a0 = 1.0 + alpha; + a1 = -2.0 * std::cos(w0); + a2 = 1.0 - alpha; + break; + case drain::filterType_HPF: + b0 = (1.0 + std::cos(w0)) * 0.5; + b1 = -(1.0 + std::cos(w0)); + b2 = (1.0 + std::cos(w0)) * 0.5; + a0 = 1.0 + alpha; + a1 = -2.0 * std::cos(w0); + a2 = 1.0 - alpha; + break; + case drain::filterType_BPF: // constant 0dB peak gain + b0 = alpha; + b1 = 0.0; + b2 = -alpha; + a0 = 1.0 + alpha; + a1 = -2.0 * std::cos(w0); + a2 = 1.0 - alpha; + break; + case drain::filterType_NOTCH: + b0 = 1.0; + b1 = -2.0 * std::cos(w0); + b2 = 1.0; + a0 = 1.0 + alpha; + a1 = -2.0 * std::cos(w0); + a2 = 1.0 - alpha; + break; + case drain::filterType_APF: + b0 = 1.0 - alpha; + b1 = -2.0 * std::cos(w0); + b2 = 1.0 + alpha; + a0 = 1.0 + alpha; + a1 = -2.0 * std::cos(w0); + a2 = 1.0 - alpha; + break; + case drain::filterType_PeakingEQ: + b0 = 1.0 + (alpha * A); + b1 = -2.0 * std::cos(w0); + b2 = 1.0 - (alpha * A); + a0 = 1.0 + (alpha /A); + a1 = -2.0 * std::cos(w0); + a2 = 1.0 - (alpha /A); + break; + case drain::filterType_LSH: + b0 = A*( (A+1.0) - (A-1.0)*std::cos(w0) + 2.0*std::sqrt(A)*alpha ); + b1 = 2.0*A*( (A-1.0) - (A+1.0)*std::cos(w0) ); + b2 = A*( (A+1.0) - (A-1.0)*std::cos(w0) - 2.0*std::sqrt(A)*alpha ); + a0 = (A+1.0) + (A-1.0)*std::cos(w0) + 2.0*std::sqrt(A)*alpha; + a1 = -2.0*( (A-1.0) + (A+1.0)*std::cos(w0) ); + a2 = (A+1.0) + (A-1.0)*std::cos(w0) - 2.0*std::sqrt(A)*alpha; + break; + case drain::filterType_HSH: + b0 = A*( (A+1.0) + (A-1.0) * std::cos(w0) + 2.0*std::sqrt(A)*alpha ); + b1 = -2.0*A*( (A-1.0) + (A+1.0) * std::cos(w0) ); + b2 = A*( (A+1.0) + (A-1.0) * std::cos(w0) - 2.0*std::sqrt(A)*alpha ); + a0 = (A+1.0) - (A-1.0) * std::cos(w0) + 2.0*std::sqrt(A)*alpha; + a1 = 2.0*( (A-1.0) - (A+1.0) * std::cos(w0) ); + a2 = (A+1.0) - (A-1.0) * std::cos(w0) - 2.0*std::sqrt(A)*alpha; + break; + default: + DRAIN_CRITICAL("Impossible case ..."); + return false; + } + // precalculate coefficients: + m_b[0] = b0 /a0; + m_b[1] = b1 /a0; + m_b[2] = b2 /a0; + m_a[0] = a1 /a0; + m_a[1] = a2 /a0; + return true; +} + diff --git a/drain/Equalizer.h b/drain/Equalizer.h new file mode 100644 index 0000000..78b9eef --- /dev/null +++ b/drain/Equalizer.h @@ -0,0 +1,82 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license APACHE v2.0 (see license file) + */ + +#ifndef __DRAIN_ALGO_EQUALIZER_H__ +#define __DRAIN_ALGO_EQUALIZER_H__ + +#include +#include + +namespace drain { + enum filterType { + filterType_none, //!< no filter + filterType_LPF, //!< low pass filter + filterType_HPF, //!< High pass filter + filterType_BPF, //!< band pass filter + filterType_NOTCH, //!< Notch Filter + filterType_APF, //!< All pass Filter + filterType_PeakingEQ, //!< Peaking band EQ filter + filterType_LSH, //!< Low shelf filter + filterType_HSH, //!< High shelf filter + filterType_EQU //!< Equalizer + }; + class BGHistory { + public: + BGHistory() { + m_x[0] = 0; + m_y[1] = 0; + m_x[0] = 0; + m_y[1] = 0; + } + float m_x[2]; //!< X history + float m_y[2]; //!< Y histiry + }; + class Equalizer : public Algo { + protected: + /** + * @brief Constructor + */ + Equalizer(); + void init(); + public: + static std11::shared_ptr create(); + /** + * @brief Destructor + */ + virtual ~Equalizer(); + protected: + virtual void configurationChange(); + public: + virtual bool process(std11::chrono::system_clock::time_point& _time, + void* _input, + size_t _inputNbChunk, + void*& _output, + size_t& _outputNbChunk); + virtual bool setParameter(const std::string& _parameter, const std::string& _value); + virtual std::string getParameter(const std::string& _parameter) const; + virtual std::string getParameterProperty(const std::string& _parameter) const; + + protected: + float processFloat(float _sample, drain::BGHistory& _history); + //----------------------------------------- + // START parameters: + enum filterType m_type; //!< current filter type. + float m_gain; //!< Gain to apply in dB + float m_frequency; //!< Frequency to apply filter + float m_bandWidth; //!< Band With to apply filter + // END parameters: + //----------------------------------------- + float m_a[2]; //!< A bi-Quad coef + float m_b[3]; //!< B bi-Quad coef + std::vector m_history; + /** + * @brief Configure the current biquad. + */ + bool configureBiQuad(); + }; +}; + +#endif diff --git a/drain/FormatUpdate.h b/drain/FormatUpdate.h index 2db2ed3..35c7a4b 100644 --- a/drain/FormatUpdate.h +++ b/drain/FormatUpdate.h @@ -3,8 +3,8 @@ * @copyright 2011, Edouard DUPIN, all right reserved * @license APACHE v2.0 (see license file) */ -#ifndef __AIRT_ALGO_FORMAT_UPDATE_H__ -#define __AIRT_ALGO_FORMAT_UPDATE_H__ +#ifndef __DRAIN_ALGO_FORMAT_UPDATE_H__ +#define __DRAIN_ALGO_FORMAT_UPDATE_H__ #include diff --git a/drain/IOFormatInterface.h b/drain/IOFormatInterface.h index d9d3171..8a78df1 100644 --- a/drain/IOFormatInterface.h +++ b/drain/IOFormatInterface.h @@ -5,8 +5,8 @@ */ -#ifndef __AIRT_ALGO_IO_FORMAT_INTERFACE_H__ -#define __AIRT_ALGO_IO_FORMAT_INTERFACE_H__ +#ifndef __DRAIN_ALGO_IO_FORMAT_INTERFACE_H__ +#define __DRAIN_ALGO_IO_FORMAT_INTERFACE_H__ #include #include diff --git a/drain/Process.h b/drain/Process.h index 717e706..beba85b 100644 --- a/drain/Process.h +++ b/drain/Process.h @@ -5,8 +5,8 @@ */ -#ifndef __AIRT_ALGO_PROCESS_H__ -#define __AIRT_ALGO_PROCESS_H__ +#ifndef __DRAIN_ALGO_PROCESS_H__ +#define __DRAIN_ALGO_PROCESS_H__ #include #include diff --git a/drain/Resampler.h b/drain/Resampler.h index bae501c..a67ff1a 100644 --- a/drain/Resampler.h +++ b/drain/Resampler.h @@ -4,8 +4,8 @@ * @license APACHE v2.0 (see license file) */ -#ifndef __AIRT_ALGO_RESAMPLER_H__ -#define __AIRT_ALGO_RESAMPLER_H__ +#ifndef __DRAIN_ALGO_RESAMPLER_H__ +#define __DRAIN_ALGO_RESAMPLER_H__ #include #ifdef HAVE_SPEEX_DSP_RESAMPLE diff --git a/drain/Volume.h b/drain/Volume.h index 48b3c24..5d04238 100644 --- a/drain/Volume.h +++ b/drain/Volume.h @@ -4,8 +4,8 @@ * @license APACHE v2.0 (see license file) */ -#ifndef __AIRT_ALGO_VOLUME_H__ -#define __AIRT_ALGO_VOLUME_H__ +#ifndef __DRAIN_ALGO_VOLUME_H__ +#define __DRAIN_ALGO_VOLUME_H__ #include #ifdef HAVE_SPEEX_DSP_RESAMPLE diff --git a/drain/airtalgo.h b/drain/airtalgo.h index 8541204..5407faf 100644 --- a/drain/airtalgo.h +++ b/drain/airtalgo.h @@ -4,8 +4,8 @@ * @license APACHE v2.0 (see license file) */ -#ifndef __AIRT_ALGO_CORE_H__ -#define __AIRT_ALGO_CORE_H__ +#ifndef __DRAIN_ALGO_CORE_H__ +#define __DRAIN_ALGO_CORE_H__ #include #include