From 20275009b30c44307fab325ca1cf96856dad23f8 Mon Sep 17 00:00:00 2001 From: Edouard DUPIN Date: Mon, 30 Mar 2015 21:00:12 +0200 Subject: [PATCH] [DEV] create single handle of bequad --- drain/BiQuadFloat.cpp | 284 +++++++++++++++ drain/BiQuadFloat.h | 95 ++++++ drain/Equalizer.cpp | 322 +++++------------- drain/Equalizer.h | 59 +--- lutin_drain.py | 3 +- tools/drainBiQuadProfiling/appl/Windows.cpp | 305 +++++++++++++++++ tools/drainBiQuadProfiling/appl/Windows.h | 53 +++ tools/drainBiQuadProfiling/appl/debug.cpp | 15 + tools/drainBiQuadProfiling/appl/debug.h | 43 +++ tools/drainBiQuadProfiling/appl/main.cpp | 60 ++++ tools/drainBiQuadProfiling/appl/main.h | 14 + .../appl/widget/DisplayFrequency.cpp | 176 ++++++++++ .../appl/widget/DisplayFrequency.h | 58 ++++ tools/drainBiQuadProfiling/data/gui.xml | 76 +++++ .../lutin_drain_biquad_profiling.py | 34 ++ .../drainEqualizerProfiling/appl/Windows.cpp | 173 ++++------ tools/drainEqualizerProfiling/appl/Windows.h | 3 +- .../appl/widget/DisplayFrequency.cpp | 52 ++- tools/drainEqualizerProfiling/data/gui.xml | 7 +- 19 files changed, 1417 insertions(+), 415 deletions(-) create mode 100644 drain/BiQuadFloat.cpp create mode 100644 drain/BiQuadFloat.h create mode 100644 tools/drainBiQuadProfiling/appl/Windows.cpp create mode 100644 tools/drainBiQuadProfiling/appl/Windows.h create mode 100644 tools/drainBiQuadProfiling/appl/debug.cpp create mode 100644 tools/drainBiQuadProfiling/appl/debug.h create mode 100644 tools/drainBiQuadProfiling/appl/main.cpp create mode 100644 tools/drainBiQuadProfiling/appl/main.h create mode 100644 tools/drainBiQuadProfiling/appl/widget/DisplayFrequency.cpp create mode 100644 tools/drainBiQuadProfiling/appl/widget/DisplayFrequency.h create mode 100644 tools/drainBiQuadProfiling/data/gui.xml create mode 100644 tools/drainBiQuadProfiling/lutin_drain_biquad_profiling.py diff --git a/drain/BiQuadFloat.cpp b/drain/BiQuadFloat.cpp new file mode 100644 index 0000000..e26851e --- /dev/null +++ b/drain/BiQuadFloat.cpp @@ -0,0 +1,284 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license APACHE v2.0 (see license file) + */ + +#include +#include + +static const char* listValues[] = { + "none", + "low-pass", + "high-pass", + "band-pass", + "notch", + "peak", + "low-shelf", + "high-shelf" +}; +static int32_t listValuesSize = sizeof(listValues)/sizeof(char*); + + +namespace etk { + template<> std::string to_string(const enum drain::filterType& _variable) { + return listValues[_variable]; + } + template <> bool from_string(enum drain::filterType& _variableRet, const std::string& _value) { + for (int32_t iii=0; iii(iii); + return true; + } + } + _variableRet = drain::filterType_none; + return false; + } +} + + + +drain::BiQuadFloat::BiQuadFloat() { + reset(); + // reset coefficients + m_a[0] = 1.0; + m_a[1] = 0.0; + m_a[2] = 0.0; + m_b[0] = 0.0; + m_b[1] = 0.0; +} + + +float drain::BiQuadFloat::processFloat(float _sample) { + float result; + // compute + result = m_a[0] * _sample + + m_a[1] * m_x[0] + + m_a[2] * m_x[1] + - m_b[0] * m_y[0] + - m_b[1] * m_y[1]; + //update history of X + m_x[1] = m_x[0]; + m_x[0] = _sample; + //update history of Y + m_y[1] = m_y[0]; + m_y[0] = result; + return result; +} + +void drain::BiQuadFloat::processFloat(float* _input, + float* _output, + size_t _nbChunk, + int32_t _inputOffset, + int32_t _outputOffset) { + for (size_t iii=0; iii<_nbChunk; ++iii) { + // process in float the biquad. + *_output = processFloat(*_input); + // move to the sample on the same channel. + _input += _inputOffset; + _output += _outputOffset; + } +} + +void drain::BiQuadFloat::processInt16(int16_t* _input, + int16_t* _output, + size_t _nbChunk, + int32_t _inputOffset, + int32_t _outputOffset) { + for (size_t iii=0; iii<_nbChunk; ++iii) { + // process in float the biquad. + float out = processFloat(*_input); + // Limit output. + out = std::avg(-32768.0f, out, 32767.0f); + *_output = static_cast(out); + // move to the sample on the same channel. + _input += _inputOffset; + _output += _outputOffset; + } +} + + +void drain::BiQuadFloat::setBiquad(enum drain::filterType _type, double _frequencyCut, double _qualityFactor, double _gain, float _sampleRate) { + reset(); + if (_sampleRate < 1) { + m_a[0] = 1.0; + m_a[1] = 0.0; + m_a[2] = 0.0; + m_b[0] = 0.0; + m_b[1] = 0.0; + return; + } + if (_frequencyCut > _sampleRate/2) { + _frequencyCut = _sampleRate/2; + } else if (_frequencyCut < 0) { + _frequencyCut = 0; + } + if (_qualityFactor < 0.01) { + _qualityFactor = 0.01; + } + double norm; + double V = std::pow(10.0, std::abs(_gain) / 20.0); + double K = std::tan(M_PI * _frequencyCut / _sampleRate); + switch (_type) { + case filterType_none: + m_a[0] = 1.0; + m_a[1] = 0.0; + m_a[2] = 0.0; + m_b[0] = 0.0; + m_b[1] = 0.0; + break; + case filterType_lowPass: + norm = 1 / (1 + K / _qualityFactor + K * K); + m_a[0] = K * K * norm; + m_a[1] = 2 * m_a[0]; + m_a[2] = m_a[0]; + m_b[0] = 2 * (K * K - 1) * norm; + m_b[1] = (1 - K / _qualityFactor + K * K) * norm; + break; + case filterType_highPass: + norm = 1 / (1 + K / _qualityFactor + K * K); + m_a[0] = 1 * norm; + m_a[1] = -2 * m_a[0]; + m_a[2] = m_a[0]; + m_b[0] = 2 * (K * K - 1) * norm; + m_b[1] = (1 - K / _qualityFactor + K * K) * norm; + break; + case filterType_bandPass: + norm = 1 / (1 + K / _qualityFactor + K * K); + m_a[0] = K / _qualityFactor * norm; + m_a[1] = 0; + m_a[2] = -m_a[0]; + m_b[0] = 2 * (K * K - 1) * norm; + m_b[1] = (1 - K / _qualityFactor + K * K) * norm; + break; + case filterType_notch: + norm = 1 / (1 + K / _qualityFactor + K * K); + m_a[0] = (1 + K * K) * norm; + m_a[1] = 2 * (K * K - 1) * norm; + m_a[2] = m_a[0]; + m_b[0] = m_a[1]; + m_b[1] = (1 - K / _qualityFactor + K * K) * norm; + break; + case filterType_peak: + if (_gain >= 0) { + norm = 1 / (1 + 1/_qualityFactor * K + K * K); + m_a[0] = (1 + V/_qualityFactor * K + K * K) * norm; + m_a[1] = 2 * (K * K - 1) * norm; + m_a[2] = (1 - V/_qualityFactor * K + K * K) * norm; + m_b[0] = m_a[1]; + m_b[1] = (1 - 1/_qualityFactor * K + K * K) * norm; + } else { + norm = 1 / (1 + V/_qualityFactor * K + K * K); + m_a[0] = (1 + 1/_qualityFactor * K + K * K) * norm; + m_a[1] = 2 * (K * K - 1) * norm; + m_a[2] = (1 - 1/_qualityFactor * K + K * K) * norm; + m_b[0] = m_a[1]; + m_b[1] = (1 - V/_qualityFactor * K + K * K) * norm; + } + break; + case filterType_lowShelf: + if (_gain >= 0) { + norm = 1 / (1 + M_SQRT2 * K + K * K); + m_a[0] = (1 + std::sqrt(2*V) * K + V * K * K) * norm; + m_a[1] = 2 * (V * K * K - 1) * norm; + m_a[2] = (1 - std::sqrt(2*V) * K + V * K * K) * norm; + m_b[0] = 2 * (K * K - 1) * norm; + m_b[1] = (1 - M_SQRT2 * K + K * K) * norm; + } else { + norm = 1 / (1 + std::sqrt(2*V) * K + V * K * K); + m_a[0] = (1 + M_SQRT2 * K + K * K) * norm; + m_a[1] = 2 * (K * K - 1) * norm; + m_a[2] = (1 - M_SQRT2 * K + K * K) * norm; + m_b[0] = 2 * (V * K * K - 1) * norm; + m_b[1] = (1 - std::sqrt(2*V) * K + V * K * K) * norm; + } + break; + case filterType_highShelf: + if (_gain >= 0) { + norm = 1 / (1 + M_SQRT2 * K + K * K); + m_a[0] = (V + std::sqrt(2*V) * K + K * K) * norm; + m_a[1] = 2 * (K * K - V) * norm; + m_a[2] = (V - std::sqrt(2*V) * K + K * K) * norm; + m_b[0] = 2 * (K * K - 1) * norm; + m_b[1] = (1 - M_SQRT2 * K + K * K) * norm; + } else { + norm = 1 / (V + std::sqrt(2*V) * K + K * K); + m_a[0] = (1 + M_SQRT2 * K + K * K) * norm; + m_a[1] = 2 * (K * K - 1) * norm; + m_a[2] = (1 - M_SQRT2 * K + K * K) * norm; + m_b[0] = 2 * (K * K - V) * norm; + m_b[1] = (V - std::sqrt(2*V) * K + K * K) * norm; + } + break; + } +} + +void drain::BiQuadFloat::reset() { + m_x[0] = 0; + m_y[1] = 0; + m_x[0] = 0; + m_y[1] = 0; +} + +void drain::BiQuadFloat::setBiquadCoef(float _a0, float _a1, float _a2, float _b0, float _b1) { + m_a[0] = _a0; + m_a[1] = _a1; + m_a[2] = _a2; + m_b[0] = _b0; + m_b[1] = _b1; + reset(); +} +void drain::BiQuadFloat::getBiquadCoef(float& _a0, float& _a1, float& _a2, float& _b0, float& _b1) { + _a0 = m_a[0]; + _a1 = m_a[1]; + _a2 = m_a[2]; + _b0 = m_b[0]; + _b1 = m_b[1]; +} + +std::vector drain::BiQuadFloat::getCoef() { + std::vector out; + out.push_back(m_a[0]); + out.push_back(m_a[1]); + out.push_back(m_a[2]); + out.push_back(m_b[0]); + out.push_back(m_b[1]); + return out; +} + + +std::vector > drain::BiQuadFloat::calculateTheory(double _sampleRate) { + std::vector > out; + double norm; + + bool buildLinear = true; + + size_t len = 512; + for (size_t iii=0; iii < len; iii++) { + double w; + if (buildLinear == true) { + // 0 to pi, linear scale + w = iii / (len - 1.0) * M_PI; + } else { + // 0.001 to 1, times pi, log scale + w = std::exp(std::log(1.0 / 0.001) * iii / (len - 1.0)) * 0.001 * M_PI; + } + double freq = iii / (len - 1.0) * _sampleRate / 2.0; + double phi = std::pow(std::sin(w/2.0), 2.0); + double y = std::log( std::pow(m_a[0]+m_a[1]+m_a[2], 2.0) + - 4.0*(m_a[0]*m_a[1] + 4.0*m_a[0]*m_a[2] + m_a[1]*m_a[2])*phi + + 16.0*m_a[0]*m_a[2]*phi*phi) + - std::log( std::pow(1.0+m_b[0]+m_b[1], 2.0) + - 4.0*(m_b[0] + 4.0*m_b[1] + m_b[0]*m_b[1])*phi + + 16.0*m_b[1]*phi*phi); + y = y * 10.0 / M_LN10; + + if (y <= -200) { + y = -200.0; + } + + //APPL_DEBUG("theory = " << freq << " power=" << y); + out.push_back(std::make_pair(freq, y)); + } + return out; +} diff --git a/drain/BiQuadFloat.h b/drain/BiQuadFloat.h new file mode 100644 index 0000000..5ad127c --- /dev/null +++ b/drain/BiQuadFloat.h @@ -0,0 +1,95 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license APACHE v2.0 (see license file) + */ + +#ifndef __DRAIN_ALGO_BIQUAD_FLOAT_H__ +#define __DRAIN_ALGO_BIQUAD_FLOAT_H__ + +#include +#include + +namespace drain { + enum filterType { + filterType_none, //!< no filter (pass threw...) + filterType_lowPass, //!< low pass filter + filterType_highPass, //!< High pass filter + filterType_bandPass, //!< band pass filter + filterType_notch, //!< Notch Filter + filterType_peak, //!< Peaking band EQ filter + filterType_lowShelf, //!< Low shelf filter + filterType_highShelf, //!< High shelf filter + }; + class BiQuadFloat { + public: + BiQuadFloat(); + protected: + float m_x[2]; //!< X history + float m_y[2]; //!< Y histiry + float m_a[3]; //!< A bi-Quad coef + float m_b[2]; //!< B bi-Quad coef + public: + /** + * @brief Set the bi-quad value and type + * @param[in] _type Type of biquad. + * @param[in] _frequencyCut Cut Frequency. [0..sampleRate/2] + * @param[in] _qualityFactor Q factor of quality (good value of 0.707 ==> permit to not ower gain) limit [0.01 .. 10] + * @param[in] _gain Gain to apply (for notch, peak, lowShelf and highShelf) limit : -30, +30 + * @param[in] _sampleRate Sample rate of the signal + */ + void setBiquad(enum drain::filterType _type, double _frequencyCut, double _qualityFactor, double _gain, float _sampleRate); + /** + * @brief Set direct Coefficients + */ + void setBiquadCoef(float _a0, float _a1, float _a2, float _b0, float _b1); + /** + * @brief Get direct Coefficients + */ + void getBiquadCoef(float& _a0, float& _a1, float& _a2, float& _b0, float& _b1); + /** + * @brief Get direct Coefficients + */ + std::vector getCoef(); + /** + * @brief Reset bequad filter (only history not value). + */ + void reset(); + protected: + /** + * @brief process single sample in float. + * @param[in] _sample Sample to process + * @return updataed value + */ + float processFloat(float _sample); + public: + /** + * @brief Porcess function. + * param[in] _input Pointer on the input data. + * param[in,out] _output Poirter on the output data (can be the same as input (inplace availlable). + * param[in] _nbChunk Number of qample to process. + * param[in] _inputOffset Offset to add when read input data. + * param[in] _outputOffset Offset to add when write output data. + */ + void processFloat(float* _input, + float* _output, + size_t _nbChunk, + int32_t _inputOffset, + int32_t _outputOffset); + //! @previous + void processInt16(int16_t* _input, + int16_t* _output, + size_t _nbChunk, + int32_t _inputOffset, + int32_t _outputOffset); + /** + * @brief calculate respond of the filter: + * @param[in] _sampleRate input qample rate + * @retrun list of frequency/power in dB + */ + std::vector > calculateTheory(double _sampleRate); + }; +} + +#endif + diff --git a/drain/Equalizer.cpp b/drain/Equalizer.cpp index 1e327be..6208877 100644 --- a/drain/Equalizer.cpp +++ b/drain/Equalizer.cpp @@ -19,18 +19,7 @@ void drain::Equalizer::init() { drain::Algo::init(); drain::Algo::m_type = "Equalizer"; m_supportedFormat.push_back(audio::format_int16); - m_supportedFormat.push_back(audio::format_float); - m_type = drain::filterType_none; - m_gain = 6; - m_frequencyCut = 1000; - m_qualityFactor = 0.707; configureBiQuad(); - // reset coefficients - m_a[0] = 1.0; - m_a[1] = 0.0; - m_a[2] = 0.0; - m_b[0] = 0.0; - m_b[1] = 0.0; } std11::shared_ptr drain::Equalizer::create() { @@ -45,9 +34,9 @@ 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()); + if (m_biquads.size() != getOutputFormat().getMap().size()) { + configureBiQuad(); + } } bool drain::Equalizer::process(std11::chrono::system_clock::time_point& _time, @@ -66,11 +55,8 @@ bool drain::Equalizer::process(std11::chrono::system_clock::time_point& _time, float* data = static_cast(_input); // move to sample offset: data += jjj; - for (size_t iii=0; iii<_inputNbChunk; ++iii) { - // process in float the biquad. - *data = processFloat(*data, m_history[jjj]); - // move to the sample on the same channel. - data += getOutputFormat().getMap().size(); + for (size_t iii=0; iii(_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(); + for (size_t iii=0; iii& _object, float _frequency) { + drain::BiQuadFloat out; + // get type: + std::string typeString = _object->getStringValue("type", "none"); + if (typeString == "direct-value") { + double a0 = _object->getNumberValue("a0", 0.0); + double a1 = _object->getNumberValue("a1", 0.0); + double a2 = _object->getNumberValue("a2", 0.0); + double b0 = _object->getNumberValue("b0", 0.0); + double b1 = _object->getNumberValue("b1", 0.0); + out.setBiquadCoef(a0, a1, a2, b0, b1); + } else { + enum drain::filterType type; + if (etk::from_string(type, typeString) == false) { + DRAIN_ERROR("Can not parse equalizer type:'" << typeString << "'"); + } + double gain = _object->getNumberValue("gain", 0.0); + double frequency = _object->getNumberValue("cut-frequency", 0.0); + double quality = _object->getNumberValue("quality", 0.0); + out.setBiquad(type, frequency, quality, gain, _frequency); + } + return out; } -bool drain::Equalizer::configureBiQuad() { - calcBiquad(m_type, m_frequencyCut, m_qualityFactor, m_gain); - return true; -} - -void drain::Equalizer::calcBiquad(enum drain::filterType _type, double _frequencyCut, double _qualityFactor, double _gain) { - m_type = _type; - m_frequencyCut = _frequencyCut; - m_qualityFactor = _qualityFactor; - m_gain = _gain; - - if (getOutputFormat().getFrequency() < 1) { - m_a[0] = 1.0; - m_a[1] = 0.0; - m_a[2] = 0.0; - m_b[0] = 0.0; - m_b[1] = 0.0; +void drain::Equalizer::configureBiQuad() { + m_biquads.clear(); + m_biquads.resize(getOutputFormat().getMap().size()); + if (m_config == nullptr) { return; } - if (m_frequencyCut > getOutputFormat().getFrequency()/2) { - m_frequencyCut = getOutputFormat().getFrequency()/2; - } else if (m_frequencyCut < 0) { - m_frequencyCut = 0; - } - if (m_qualityFactor < 0.01) { - m_qualityFactor = 0.01; - } - switch (m_type) { - case filterType_lowPass: - case filterType_highPass: - case filterType_bandPass: - case filterType_notch: - // Quality : USE IT - // Gain : Not USE IT - break; - case filterType_peak: - // Quality : USE IT - // Gain : USE IT - break; - case filterType_lowShelf: - case filterType_highShelf: - // Quality : NOT USE IT - // Gain : USE IT - break; - default: - // Quality : USE IT - // Gain : USE IT - break; - } - double norm; - double V = std::pow(10.0, std::abs(m_gain) / 20.0); - double K = std::tan(M_PI * m_frequencyCut / getOutputFormat().getFrequency()); - switch (m_type) { - case filterType_none: - m_a[0] = 1.0; - m_a[1] = 0.0; - m_a[2] = 0.0; - m_b[0] = 0.0; - m_b[1] = 0.0; - break; - case filterType_lowPass: - norm = 1 / (1 + K / m_qualityFactor + K * K); - m_a[0] = K * K * norm; - m_a[1] = 2 * m_a[0]; - m_a[2] = m_a[0]; - m_b[0] = 2 * (K * K - 1) * norm; - m_b[1] = (1 - K / m_qualityFactor + K * K) * norm; - break; - case filterType_highPass: - norm = 1 / (1 + K / m_qualityFactor + K * K); - m_a[0] = 1 * norm; - m_a[1] = -2 * m_a[0]; - m_a[2] = m_a[0]; - m_b[0] = 2 * (K * K - 1) * norm; - m_b[1] = (1 - K / m_qualityFactor + K * K) * norm; - break; - case filterType_bandPass: - norm = 1 / (1 + K / m_qualityFactor + K * K); - m_a[0] = K / m_qualityFactor * norm; - m_a[1] = 0; - m_a[2] = -m_a[0]; - m_b[0] = 2 * (K * K - 1) * norm; - m_b[1] = (1 - K / m_qualityFactor + K * K) * norm; - break; - case filterType_notch: - norm = 1 / (1 + K / m_qualityFactor + K * K); - m_a[0] = (1 + K * K) * norm; - m_a[1] = 2 * (K * K - 1) * norm; - m_a[2] = m_a[0]; - m_b[0] = m_a[1]; - m_b[1] = (1 - K / m_qualityFactor + K * K) * norm; - break; - case filterType_peak: - if (m_gain >= 0) { - norm = 1 / (1 + 1/m_qualityFactor * K + K * K); - m_a[0] = (1 + V/m_qualityFactor * K + K * K) * norm; - m_a[1] = 2 * (K * K - 1) * norm; - m_a[2] = (1 - V/m_qualityFactor * K + K * K) * norm; - m_b[0] = m_a[1]; - m_b[1] = (1 - 1/m_qualityFactor * K + K * K) * norm; - } else { - norm = 1 / (1 + V/m_qualityFactor * K + K * K); - m_a[0] = (1 + 1/m_qualityFactor * K + K * K) * norm; - m_a[1] = 2 * (K * K - 1) * norm; - m_a[2] = (1 - 1/m_qualityFactor * K + K * K) * norm; - m_b[0] = m_a[1]; - m_b[1] = (1 - V/m_qualityFactor * K + K * K) * norm; + // check for a global config: + const std11::shared_ptr global = m_config->getArray("global"); + if (global != nullptr) { + // only global configuration get all elements: + for (size_t kkk=0; kkksize(); ++kkk) { + const std11::shared_ptr tmpObject = global->getObject(kkk); + if (tmpObject == nullptr) { + DRAIN_ERROR("Parse the configuration error : not a correct parameter:" << kkk); + continue; } - break; - case filterType_lowShelf: - if (m_gain >= 0) { - norm = 1 / (1 + M_SQRT2 * K + K * K); - m_a[0] = (1 + std::sqrt(2*V) * K + V * K * K) * norm; - m_a[1] = 2 * (V * K * K - 1) * norm; - m_a[2] = (1 - std::sqrt(2*V) * K + V * K * K) * norm; - m_b[0] = 2 * (K * K - 1) * norm; - m_b[1] = (1 - M_SQRT2 * K + K * K) * norm; - } else { - norm = 1 / (1 + std::sqrt(2*V) * K + V * K * K); - m_a[0] = (1 + M_SQRT2 * K + K * K) * norm; - m_a[1] = 2 * (K * K - 1) * norm; - m_a[2] = (1 - M_SQRT2 * K + K * K) * norm; - m_b[0] = 2 * (V * K * K - 1) * norm; - m_b[1] = (1 - std::sqrt(2*V) * K + V * K * K) * norm; - } - break; - case filterType_highShelf: - if (m_gain >= 0) { - norm = 1 / (1 + M_SQRT2 * K + K * K); - m_a[0] = (V + std::sqrt(2*V) * K + K * K) * norm; - m_a[1] = 2 * (K * K - V) * norm; - m_a[2] = (V - std::sqrt(2*V) * K + K * K) * norm; - m_b[0] = 2 * (K * K - 1) * norm; - m_b[1] = (1 - M_SQRT2 * K + K * K) * norm; - } else { - norm = 1 / (V + std::sqrt(2*V) * K + K * K); - m_a[0] = (1 + M_SQRT2 * K + K * K) * norm; - m_a[1] = 2 * (K * K - 1) * norm; - m_a[2] = (1 - M_SQRT2 * K + K * K) * norm; - m_b[0] = 2 * (K * K - V) * norm; - m_b[1] = (V - std::sqrt(2*V) * K + K * K) * norm; - } - break; - } -} - -static const char* listValues[] = { - "none", - "low-pass", - "high-pass", - "band-pass", - "notch", - "peak", - "low-shelf", - "high-shelf" -}; -static int32_t listValuesSize = sizeof(listValues)/sizeof(char*); - - -namespace etk { - template<> std::string to_string(const enum drain::filterType& _variable) { - return listValues[_variable]; - } - template <> bool from_string(enum drain::filterType& _variableRet, const std::string& _value) { - for (int32_t iii=0; iii(iii); - return true; + // declare biquad: + drain::BiQuadFloat biquad = getBiquad(tmpObject, getOutputFormat().getFrequency()); + // add this bequad for every Channel: + for (size_t iii=0; iii channelConfig = m_config->getArray(channelName); + + if (channelConfig == nullptr) { + // no config ... not a problem ... + continue; + } + // only global configuration get all elements: + for (size_t kkk=0; kkksize(); ++kkk) { + const std11::shared_ptr tmpObject = channelConfig->getObject(kkk); + if (tmpObject == nullptr) { + DRAIN_ERROR("Parse the configuration error : not a correct parameter:" << kkk); + continue; + } + // declare biquad: + drain::BiQuadFloat biquad = getBiquad(tmpObject, getOutputFormat().getFrequency()); + // add this bequad for specific channel: + m_biquads[iii].push_back(biquad); + } + } + return; } diff --git a/drain/Equalizer.h b/drain/Equalizer.h index e3b33db..576202a 100644 --- a/drain/Equalizer.h +++ b/drain/Equalizer.h @@ -9,29 +9,10 @@ #include #include +#include +#include namespace drain { - enum filterType { - filterType_none, //!< no filter (pass threw...) - filterType_lowPass, //!< low pass filter - filterType_highPass, //!< High pass filter - filterType_bandPass, //!< band pass filter - filterType_notch, //!< Notch Filter - filterType_peak, //!< Peaking band EQ filter - filterType_lowShelf, //!< Low shelf filter - filterType_highShelf, //!< High shelf filter - }; - 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: /** @@ -53,42 +34,24 @@ namespace drain { size_t _inputNbChunk, void*& _output, size_t& _outputNbChunk); + protected: + std11::shared_ptr m_config; // configuration of the equalizer. + public: 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 ??? limit : -30, +30 - float m_frequencyCut; //!< Frequency to apply filter ???? LIMIT : [0..sampleRate/2] - // good value of 0.707 ==> permit to not ower gain - float m_qualityFactor; //!< Quality factor ??? limit [0.01 .. 10] - // END parameters: - //----------------------------------------- - float m_a[3]; //!< A bi-Quad coef - float m_b[2]; //!< B bi-Quad coef - std::vector m_history; /** - * @brief Configure the current biquad. + * @brief repesent all the biquad to process: + * The first vector represent the number of channel to process + * The second vector represent the number of biquad to process */ - bool configureBiQuad(); - public: + std::vector > m_biquads; /** - * @brief Configure the current biquad. + * @brief Configure biquad with the user spec. */ - void calcBiquad(enum drain::filterType _type, double _frequencyCut, double _qualityFactor, double _gain); - std::vector getCoef() { - std::vector out; - out.push_back(m_a[0]); - out.push_back(m_a[1]); - out.push_back(m_a[2]); - out.push_back(m_b[0]); - out.push_back(m_b[1]); - return out; - } + void configureBiQuad(); }; }; diff --git a/lutin_drain.py b/lutin_drain.py index b50452d..8c273da 100644 --- a/lutin_drain.py +++ b/lutin_drain.py @@ -14,6 +14,7 @@ def create(target): 'drain/debug.cpp', 'drain/airtalgo.cpp', 'drain/Algo.cpp', + 'drain/BiQuadFloat.cpp', 'drain/ChannelReorder.cpp', 'drain/CircularBuffer.cpp', 'drain/EndPointCallback.cpp', @@ -32,7 +33,7 @@ def create(target): # TODO: myModule.add_optional_module_depend('speexdsp', "HAVE_SPEEX_DSP_RESAMPLE") myModule.compile_flags_CC("-DHAVE_SPEEX_DSP_RESAMPLE") - myModule.add_module_depend(['etk', 'audio', 'speexdsp']) + myModule.add_module_depend(['etk', 'audio', 'ejson', 'speexdsp']) myModule.add_export_path(tools.get_current_path(__file__)) # add the currrent module at the diff --git a/tools/drainBiQuadProfiling/appl/Windows.cpp b/tools/drainBiQuadProfiling/appl/Windows.cpp new file mode 100644 index 0000000..2ce8b91 --- /dev/null +++ b/tools/drainBiQuadProfiling/appl/Windows.cpp @@ -0,0 +1,305 @@ +/** + * @author Edouard DUPIN + * + * @copyright 2010, Edouard DUPIN, all right reserved + * + * @license APACHE-2 (see license file) + */ + +#include +#include +#include +#include +#include +#include +#include + +#undef __class__ +#define __class__ "Windows" + +appl::Windows::Windows() : + m_sampleRate(48000), + m_type(drain::filterType::filterType_lowPass), + m_cutFrequency(8000.0), + m_gain(0.0), + m_quality(0.707) { + addObjectType("appl::Windows"); + m_listSampleRate.push_back(192000); + m_listSampleRate.push_back(176400); + m_listSampleRate.push_back(96000); + m_listSampleRate.push_back(88200); + m_listSampleRate.push_back(48000); + m_listSampleRate.push_back(44100); + m_listSampleRate.push_back(32000); + m_listSampleRate.push_back(22050); + m_listSampleRate.push_back(16000); + m_listSampleRate.push_back(11025); + m_listSampleRate.push_back(8000); + m_listSampleRate.push_back(4000); + m_listType.push_back(drain::filterType_none); + m_listType.push_back(drain::filterType_lowPass); + m_listType.push_back(drain::filterType_highPass); + m_listType.push_back(drain::filterType_bandPass); + m_listType.push_back(drain::filterType_notch); + m_listType.push_back(drain::filterType_peak); + m_listType.push_back(drain::filterType_lowShelf); + m_listType.push_back(drain::filterType_highShelf); +} + +void appl::Windows::init() { + ewol::widget::Windows::init(); + setTitle("Drain Equalizer Profiler"); + + m_gui = ewol::widget::Composer::create(ewol::widget::Composer::file, "DATA:gui.xml"); + if (m_gui != nullptr) { + setSubWidget(m_gui); + } + subBind(ewol::widget::Button, "sample-rate-low", signalPressed, shared_from_this(), &appl::Windows::onCallbackSampleRateLow); + subBind(ewol::widget::Button, "sample-rate-up", signalPressed, shared_from_this(), &appl::Windows::onCallbackSampleRateUp); + subBind(ewol::widget::Button, "type-low", signalPressed, shared_from_this(), &appl::Windows::onCallbackTypeLow); + subBind(ewol::widget::Button, "type-up", signalPressed, shared_from_this(), &appl::Windows::onCallbackTypeUp); + + subBind(ewol::widget::Entry, "gain", signalModify, shared_from_this(), &appl::Windows::onCallbackGain); + subBind(ewol::widget::Slider, "gain-slider", signalChange, shared_from_this(), &appl::Windows::onCallbackGainSlider); + + subBind(ewol::widget::Entry, "frequency", signalModify, shared_from_this(), &appl::Windows::onCallbackFrequency); + subBind(ewol::widget::Slider, "frequency-slider", signalChange, shared_from_this(), &appl::Windows::onCallbackFrequencySlider); + + subBind(ewol::widget::Entry, "quality", signalModify, shared_from_this(), &appl::Windows::onCallbackQuality); + subBind(ewol::widget::Slider, "quality-slider", signalChange, shared_from_this(), &appl::Windows::onCallbackQualitySlider); + + subBind(ewol::widget::Button, "display16", signalPressed, shared_from_this(), &appl::Windows::onCallbackStart16); + subBind(ewol::widget::Button, "displayFloat", signalPressed, shared_from_this(), &appl::Windows::onCallbackStartFloat); + m_displayer = std11::dynamic_pointer_cast(getSubObjectNamed("displayer")); + onCallbackStart(); +} + + +void appl::Windows::onCallbackSampleRateUp() { + for (int32_t iii=0; iii=0) { + m_sampleRate = m_listSampleRate[iii]; + } else { + m_sampleRate = m_listSampleRate[m_listSampleRate.size()-1]; + } + ewol::parameterSetOnObjectNamed("sample-rate", "value", etk::to_string(m_sampleRate)); + ewol::parameterSetOnObjectNamed("frequency-slider", "max", etk::to_string(m_sampleRate/2)); + onCallbackStart(); + return; + } + } + m_sampleRate = m_listSampleRate[0]; + ewol::parameterSetOnObjectNamed("sample-rate", "value", etk::to_string(m_sampleRate)); + ewol::parameterSetOnObjectNamed("frequency-slider", "max", etk::to_string(m_sampleRate/2)); + onCallbackStart(); +} + +void appl::Windows::onCallbackTypeUp() { + for (int32_t iii=0; iii=0) { + m_type = m_listType[iii]; + } else { + m_type = m_listType[m_listType.size()-1]; + } + ewol::parameterSetOnObjectNamed("type", "value", etk::to_string(m_type)); + onCallbackStart(); + return; + } + } + m_type = m_listType[0]; + ewol::parameterSetOnObjectNamed("type", "value", etk::to_string(m_type)); + onCallbackStart(); +} + + +void appl::Windows::onCallbackGain(const std::string& _value) { + m_gain = etk::string_to_float(_value); + ewol::parameterSetOnObjectNamed("gain-slider", "value", etk::to_string(_value)); + APPL_INFO("Gain " << m_gain); + onCallbackStart(); +} + +void appl::Windows::onCallbackGainSlider(const float& _value) { + m_gain = _value; + ewol::parameterSetOnObjectNamed("gain", "value", etk::to_string(_value)); + APPL_INFO("Gain " << m_gain); + onCallbackStart(); +} + + + +void appl::Windows::onCallbackQuality(const std::string& _value) { + m_quality = etk::string_to_float(_value); + ewol::parameterSetOnObjectNamed("quality-slider", "value", etk::to_string(_value)); + APPL_INFO("quality " << m_quality); + onCallbackStart(); +} + +void appl::Windows::onCallbackQualitySlider(const float& _value) { + m_quality = _value; + ewol::parameterSetOnObjectNamed("quality", "value", etk::to_string(_value)); + APPL_INFO("quality " << m_quality); + onCallbackStart(); +} + + +void appl::Windows::onCallbackFrequency(const std::string& _value) { + m_cutFrequency = etk::string_to_float(_value); + ewol::parameterSetOnObjectNamed("frequency-slider", "value", etk::to_string(_value)); + APPL_INFO("cut frequency " << m_cutFrequency); + onCallbackStart(); +} + +void appl::Windows::onCallbackFrequencySlider(const float& _value) { + m_cutFrequency = _value; + ewol::parameterSetOnObjectNamed("frequency", "value", etk::to_string(_value)); + APPL_INFO("cut frequency " << m_cutFrequency); + onCallbackStart(); +} + +#include + +void appl::Windows::onCallbackStart() { + APPL_INFO("start "); + int32_t iii = 10; + std::vector map; + map.push_back(audio::channel_frontCenter); + //drain::IOFormatInterface format(map, audio::format_int16, m_sampleRate); + drain::IOFormatInterface format(map, audio::format_float, m_sampleRate); + // create biquad + drain::BiQuadFloat bq; + // configure parameter + bq.setBiquad(m_type, m_cutFrequency, m_quality, m_gain, m_sampleRate); + std::vector > theory = bq.calculateTheory(m_sampleRate); + m_displayer->clear(); + m_displayer->setValue(theory); +} + + +void appl::Windows::onCallbackStart16() { + APPL_INFO("start "); + // create biquad + drain::BiQuadFloat bq; + // configure parameter + bq.setBiquad(m_type, m_cutFrequency, m_quality, m_gain, m_sampleRate); + std::vector > pratic; + size_t len = 512; + for (size_t iii=0; iii < len; iii++) { + float freq = iii / (len - 1.0) * m_sampleRate / 2.0; + // To reset filter + bq.reset(); + double m_phase = 0; + double baseCycle = 2.0*M_PI/double(m_sampleRate) * double(freq); + float gain = 0; + std::vector data; + // create sinus + data.resize(16000, 0); + for (int32_t iii=0; iii= 2*M_PI) { + m_phase -= 2*M_PI; + } + } + // process + int16_t* output = nullptr; + void* outputVoid = nullptr; + size_t outputNbChunk = 0; + std11::chrono::system_clock::time_point time; + //RIVER_SAVE_FILE_MACRO(int16_t,"aaa_test_INPUT_16.raw",&data[0],data.size()); + bq.processInt16(&data[0], &data[0], data.size(), 1, 1); + //RIVER_SAVE_FILE_MACRO(int16_t,"aaa_test_OUTPUT_16.raw",&data[0],data.size()); + int16_t value = 0; + for (size_t iii=200; iii(float(freq),float(gain))); + } + m_displayer->setValue(pratic); +} + +void appl::Windows::onCallbackStartFloat() { + APPL_INFO("start "); + // create biquad + drain::BiQuadFloat bq; + // configure parameter + bq.setBiquad(m_type, m_cutFrequency, m_quality, m_gain, m_sampleRate); + std::vector > pratic; + size_t len = 512; + for (size_t iii=0; iii < len; iii++) { + float freq = iii / (len - 1.0) * m_sampleRate / 2.0; + // To reset filter + bq.reset(); + double m_phase = 0; + double baseCycle = 2.0*M_PI/double(m_sampleRate) * double(freq); + float gain = 0; + std::vector data; + // create sinus + data.resize(16000, 0); + for (int32_t iii=0; iii= 2*M_PI) { + m_phase -= 2*M_PI; + } + } + //RIVER_SAVE_FILE_MACRO(float,"aaa_test_INPUT_F.raw",&data[0],data.size()); + bq.processFloat(&data[0], &data[0], data.size(), 1, 1); + //RIVER_SAVE_FILE_MACRO(float,"aaa_test_OUTPUT_F.raw",&data[0],data.size()); + float value = 0; + for (size_t iii=200; iii(float(freq),float(gain))); + } + m_displayer->setValue(pratic); +} + diff --git a/tools/drainBiQuadProfiling/appl/Windows.h b/tools/drainBiQuadProfiling/appl/Windows.h new file mode 100644 index 0000000..ca3f173 --- /dev/null +++ b/tools/drainBiQuadProfiling/appl/Windows.h @@ -0,0 +1,53 @@ +/** + * @author Edouard DUPIN + * + * @copyright 2010, Edouard DUPIN, all right reserved + * + * @license APACHE-2 (see license file) + */ + +#ifndef __APPL_WINDOWS_H__ +#define __APPL_WINDOWS_H__ + +#include +#include +#include +#include +#include + +namespace appl { + class Windows : public ewol::widget::Windows { + protected: + Windows(); + void init(); + public: + DECLARE_FACTORY(Windows); + protected: + std::shared_ptr m_gui; + std::shared_ptr m_displayer; + void onCallbackSampleRateLow(); + void onCallbackSampleRateUp(); + void onCallbackTypeUp(); + void onCallbackTypeLow(); + void onCallbackGain(const std::string& _value); + void onCallbackGainSlider(const float& _value); + void onCallbackFrequency(const std::string& _value); + void onCallbackFrequencySlider(const float& _value); + void onCallbackQuality(const std::string& _value); + void onCallbackQualitySlider(const float& _value); + void onCallbackStart(); + void onCallbackStart16(); + void onCallbackStartFloat(); + protected: + int32_t m_sampleRate; + std::vector m_listSampleRate; + enum drain::filterType m_type; + std::vector m_listType; + float m_cutFrequency; + float m_gain; + float m_quality; + }; +}; + + +#endif \ No newline at end of file diff --git a/tools/drainBiQuadProfiling/appl/debug.cpp b/tools/drainBiQuadProfiling/appl/debug.cpp new file mode 100644 index 0000000..4eeb27c --- /dev/null +++ b/tools/drainBiQuadProfiling/appl/debug.cpp @@ -0,0 +1,15 @@ +/** + * @author Edouard DUPIN + * + * @copyright 2010, Edouard DUPIN, all right reserved + * + * @license APACHE-2 (see license file) + */ + + +#include + +int32_t appl::getLogId() { + static int32_t g_val = etk::log::registerInstance("drain-equalizer"); + return g_val; +} diff --git a/tools/drainBiQuadProfiling/appl/debug.h b/tools/drainBiQuadProfiling/appl/debug.h new file mode 100644 index 0000000..1670c4c --- /dev/null +++ b/tools/drainBiQuadProfiling/appl/debug.h @@ -0,0 +1,43 @@ +/** + * @author Edouard DUPIN + * + * @copyright 2010, Edouard DUPIN, all right reserved + * + * @license APACHE-2 (see license file) + */ + + +#ifndef __APPL_DEBUG_H__ +#define __APPL_DEBUG_H__ + +#include + +namespace appl { + int32_t getLogId(); +}; +#define APPL_BASE(info,data) TK_LOG_BASE(appl::getLogId(),info,data) + +#define APPL_CRITICAL(data) APPL_BASE(1, data) +#define APPL_ERROR(data) APPL_BASE(2, data) +#define APPL_WARNING(data) APPL_BASE(3, data) +#ifdef DEBUG + #define APPL_INFO(data) APPL_BASE(4, data) + #define APPL_DEBUG(data) APPL_BASE(5, data) + #define APPL_VERBOSE(data) APPL_BASE(6, data) + #define APPL_TODO(data) APPL_BASE(4, "TODO : " << data) +#else + #define APPL_INFO(data) do { } while(false) + #define APPL_DEBUG(data) do { } while(false) + #define APPL_VERBOSE(data) do { } while(false) + #define APPL_TODO(data) do { } while(false) +#endif + +#define APPL_ASSERT(cond,data) \ + do { \ + if (!(cond)) { \ + APPL_CRITICAL(data); \ + assert(!#cond); \ + } \ + } while (0) + +#endif diff --git a/tools/drainBiQuadProfiling/appl/main.cpp b/tools/drainBiQuadProfiling/appl/main.cpp new file mode 100644 index 0000000..08f0a89 --- /dev/null +++ b/tools/drainBiQuadProfiling/appl/main.cpp @@ -0,0 +1,60 @@ +/** + * @author Edouard DUPIN + * + * @copyright 2010, Edouard DUPIN, all right reserved + * + * @license GPL v3 (see license file) + */ + + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +class MainApplication : public ewol::context::Application { + public: + bool init(ewol::Context& _context, size_t _initId) { + APPL_INFO("==> Init APPL (START) [" << ewol::getBoardType() << "] (" << ewol::getCompilationMode() << ")"); + + // TODO : Remove this : Move if in the windows properties + _context.setSize(vec2(800, 600)); + + // select internal data for font ... + _context.getFontDefault().setUseExternal(true); + _context.getFontDefault().set("FreeSerif;DejaVuSansMono", 19); + + // add local widget list: + appl::widget::DisplayFrequency::createManagerWidget(_context.getWidgetManager()); + + std::shared_ptr basicWindows = appl::Windows::create(); + // create the specific windows + _context.setWindows(basicWindows); + APPL_INFO("==> Init APPL (END)"); + return true; + } + + void unInit(ewol::Context& _context) { + APPL_INFO("==> Un-Init APPL (START)"); + // nothing to do ... + APPL_INFO("==> Un-Init APPL (END)"); + } +}; + +/** + * @brief Main of the program (This can be set in every case, but it is not used in Andoid...). + * @param std IO + * @return std IO + */ +int main(int _argc, const char *_argv[]) { + return ewol::run(new MainApplication(), _argc, _argv); +} + + diff --git a/tools/drainBiQuadProfiling/appl/main.h b/tools/drainBiQuadProfiling/appl/main.h new file mode 100644 index 0000000..caa7110 --- /dev/null +++ b/tools/drainBiQuadProfiling/appl/main.h @@ -0,0 +1,14 @@ +/** + * @author Edouard DUPIN + * + * @copyright 2010, Edouard DUPIN, all right reserved + * + * @license APACHE-2 (see license file) + */ + +#ifndef __APPL_MAIN_H__ +#define __APPL_MAIN_H__ + + +#endif + diff --git a/tools/drainBiQuadProfiling/appl/widget/DisplayFrequency.cpp b/tools/drainBiQuadProfiling/appl/widget/DisplayFrequency.cpp new file mode 100644 index 0000000..84c971e --- /dev/null +++ b/tools/drainBiQuadProfiling/appl/widget/DisplayFrequency.cpp @@ -0,0 +1,176 @@ +/** + * @author Edouard DUPIN + * + * @copyright 2010, Edouard DUPIN, all right reserved + * + * @license APACHE-2 (see license file) + */ + +#include +#include +#include + +#undef __class__ +#define __class__ "DisplayFrequency" + + +appl::widget::DisplayFrequency::DisplayFrequency() : + m_gainMin(0.0f), + m_gainMax(1.0f), + m_frequencyMin(0.0f), + m_frequencyMax(24000.0f) { + addObjectType("appl::widget::DisplayFrequency"); + m_text.setFontSize(13); +} + +void appl::widget::DisplayFrequency::init() { + ewol::Widget::init(); + markToRedraw(); +} + + +appl::widget::DisplayFrequency::~DisplayFrequency() { + +} + + +void appl::widget::DisplayFrequency::setValue(const std::vector >& _data) { + m_data.push_back(_data); + markToRedraw(); +} + +void appl::widget::DisplayFrequency::setGainRange(float _min, float _max) { + m_gainMin = _min; + m_gainMax = _max; + markToRedraw(); +} + +void appl::widget::DisplayFrequency::setFrequencyRange(float _min, float _max) { + m_frequencyMin = _min; + m_frequencyMax = _max; + markToRedraw(); +} + +void appl::widget::DisplayFrequency::onDraw() { + m_draw.draw(); + m_text.draw(); +} + + +void appl::widget::DisplayFrequency::onRegenerateDisplay() { + //!< Check if we really need to redraw the display, if not needed, we redraw the previous data ... + if (needRedraw() == false) { + return; + } + // remove previous data + m_draw.clear(); + m_text.clear(); + m_borderSize = m_size * 0.05; + // set background + m_draw.setColor(etk::color::black); + m_draw.setPos(vec2(0,0)); + m_draw.rectangleWidth(m_size); + m_draw.setColor(etk::color::gray); + m_draw.setPos(m_borderSize); + m_draw.setThickness(1); + vec2 plop = m_size-m_borderSize; + m_draw.lineTo(vec2(m_borderSize.x(), plop.y())); + m_draw.lineTo(m_size-m_borderSize); + m_draw.lineTo(vec2(plop.x(), m_borderSize.y())); + m_draw.lineTo(m_borderSize); + if (m_data.size() == 0) { + return; + } + // calculate min and Max : + m_gainMax = -999999999.9; + m_gainMin = 9999999999.9; + m_frequencyMin = 99999999.0; + m_frequencyMax = -99999999.0; + bool displayLog = true; + for (size_t kkk=0; kkk::infinity()) { + m_gainMax = std::max(m_gainMax, m_data[kkk][iii].second); + m_gainMin = std::min(m_gainMin, m_data[kkk][iii].second); + } + if (displayLog == false) { + if (std::abs(m_data[kkk][iii].first) != std::numeric_limits::infinity()) { + m_frequencyMax = std::max(m_frequencyMax, m_data[kkk][iii].first); + m_frequencyMin = std::min(m_frequencyMin, m_data[kkk][iii].first); + } + } else { + if (std::abs(m_data[kkk][iii].first) != std::numeric_limits::infinity()) { + if (m_data[kkk][iii].first == 0) { + continue; + } + m_frequencyMax = std::max(m_frequencyMax, std::log(m_data[kkk][iii].first)); + m_frequencyMin = std::min(m_frequencyMin, std::log(m_data[kkk][iii].first)); + APPL_INFO("plop " << m_data[kkk][iii].first << " " << std::log(m_data[kkk][iii].first)); + } + } + } + } + // TODO : limit unit at a unit value. + /* + for (size_t iii=0; iii +#include +#include +#include + +namespace appl { + namespace widget { + class DisplayFrequency : public ewol::Widget { + private: + ewol::compositing::Drawing m_draw; //!< drawing instance + ewol::compositing::Text m_text; //!< drawing instance + protected: + //! @brief constructor + DisplayFrequency(); + void init(); + public: + DECLARE_WIDGET_FACTORY(DisplayFrequency, "DisplayFrequency"); + //! @brief destructor + virtual ~DisplayFrequency(); + private: + std::vector > > m_data; //!< data that might be displayed + public: + void clear() { + m_data.clear(); + } + void setValue(const std::vector >& _data); + private: + float m_gainMin; //!< display minimum gain value + float m_gainMax; //!< display maximum gain value + public: + void setGainRange(float _min, float _max); + private: + float m_frequencyMin; //!< display minimum gain value + float m_frequencyMax; //!< display maximum gain value + public: + void setFrequencyRange(float _min, float _max); + public: // herited function + virtual void onDraw(); + virtual void onRegenerateDisplay(); + private: + vec2 m_borderSize; + }; + } +} + +#endif diff --git a/tools/drainBiQuadProfiling/data/gui.xml b/tools/drainBiQuadProfiling/data/gui.xml new file mode 100644 index 0000000..bb77e6d --- /dev/null +++ b/tools/drainBiQuadProfiling/data/gui.xml @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tools/drainBiQuadProfiling/lutin_drain_biquad_profiling.py b/tools/drainBiQuadProfiling/lutin_drain_biquad_profiling.py new file mode 100644 index 0000000..03d6566 --- /dev/null +++ b/tools/drainBiQuadProfiling/lutin_drain_biquad_profiling.py @@ -0,0 +1,34 @@ +#!/usr/bin/python +import lutinModule as module +import lutinTools as tools + + +# optionnal : Describe in the "lutin.py --help" +def get_desc(): + return "drain_biquad_profiling : basic test and profiling of equalizer work or not" + +def create(target): + myModule = module.Module(__file__, 'drain_biquad_profiling', 'BINARY') + # add the file to compile: + myModule.add_src_file([ + 'appl/main.cpp', + 'appl/debug.cpp', + 'appl/Windows.cpp', + 'appl/widget/DisplayFrequency.cpp', + ]) + # add Library dependency name + myModule.add_module_depend(['ewol', 'drain', 'river']) + # add application C flags + myModule.compile_flags_CC([ + "-DPROJECT_NAME=\"\\\""+myModule.name+"\\\"\""]) + # Add current include Path + myModule.add_path(tools.get_current_path(__file__)) + # copy internal datas + myModule.copy_folder("data/*") + + # return the created module + return myModule + + + + diff --git a/tools/drainEqualizerProfiling/appl/Windows.cpp b/tools/drainEqualizerProfiling/appl/Windows.cpp index 928ed6f..2ce8b91 100644 --- a/tools/drainEqualizerProfiling/appl/Windows.cpp +++ b/tools/drainEqualizerProfiling/appl/Windows.cpp @@ -68,7 +68,8 @@ void appl::Windows::init() { subBind(ewol::widget::Entry, "quality", signalModify, shared_from_this(), &appl::Windows::onCallbackQuality); subBind(ewol::widget::Slider, "quality-slider", signalChange, shared_from_this(), &appl::Windows::onCallbackQualitySlider); - subBind(ewol::widget::Button, "display", signalPressed, shared_from_this(), &appl::Windows::onCallbackStart); + subBind(ewol::widget::Button, "display16", signalPressed, shared_from_this(), &appl::Windows::onCallbackStart16); + subBind(ewol::widget::Button, "displayFloat", signalPressed, shared_from_this(), &appl::Windows::onCallbackStartFloat); m_displayer = std11::dynamic_pointer_cast(getSubObjectNamed("displayer")); onCallbackStart(); } @@ -179,7 +180,7 @@ void appl::Windows::onCallbackQuality(const std::string& _value) { } void appl::Windows::onCallbackQualitySlider(const float& _value) { - m_gain = _value; + m_quality = _value; ewol::parameterSetOnObjectNamed("quality", "value", etk::to_string(_value)); APPL_INFO("quality " << m_quality); onCallbackStart(); @@ -209,126 +210,96 @@ void appl::Windows::onCallbackStart() { map.push_back(audio::channel_frontCenter); //drain::IOFormatInterface format(map, audio::format_int16, m_sampleRate); drain::IOFormatInterface format(map, audio::format_float, m_sampleRate); - // create equalizer - std11::shared_ptr eq = drain::Equalizer::create(); - // configure input - eq->setInputFormat(format); - // configure output - eq->setOutputFormat(format); + // create biquad + drain::BiQuadFloat bq; // configure parameter - eq->calcBiquad(m_type, m_cutFrequency, m_quality, m_gain); - std::vector > theory = calculateTheory(m_sampleRate, eq->getCoef()); + bq.setBiquad(m_type, m_cutFrequency, m_quality, m_gain, m_sampleRate); + std::vector > theory = bq.calculateTheory(m_sampleRate); m_displayer->clear(); m_displayer->setValue(theory); +} + + +void appl::Windows::onCallbackStart16() { + APPL_INFO("start "); + // create biquad + drain::BiQuadFloat bq; + // configure parameter + bq.setBiquad(m_type, m_cutFrequency, m_quality, m_gain, m_sampleRate); std::vector > pratic; size_t len = 512; for (size_t iii=0; iii < len; iii++) { float freq = iii / (len - 1.0) * m_sampleRate / 2.0; // To reset filter - eq->setParameter("reset", ""); + bq.reset(); double m_phase = 0; double baseCycle = 2.0*M_PI/double(m_sampleRate) * double(freq); float gain = 0; - if (format.getFormat() == audio::format_int16) { - std::vector data; - // create sinus - data.resize(16000, 0); - for (int32_t iii=0; iii= 2*M_PI) { - m_phase -= 2*M_PI; - } + std::vector data; + // create sinus + data.resize(16000, 0); + for (int32_t iii=0; iii= 2*M_PI) { + m_phase -= 2*M_PI; } - // process - int16_t* output = nullptr; - void* outputVoid = nullptr; - size_t outputNbChunk = 0; - std11::chrono::system_clock::time_point time; - //RIVER_SAVE_FILE_MACRO(int16_t,"aaa_test_INPUT.raw",&data[0],data.size()); - eq->process(time, &data[0], data.size(), outputVoid, outputNbChunk); - output = static_cast(outputVoid); - //RIVER_SAVE_FILE_MACRO(int16_t,"aaa_test_OUTPUT.raw",output,outputNbChunk); - int16_t value = 0; - for (size_t iii=200; iii data; - // create sinus - data.resize(16000, 0); - for (int32_t iii=0; iii= 2*M_PI) { - m_phase -= 2*M_PI; - } - } - // process - float* output = nullptr; - void* outputVoid = nullptr; - size_t outputNbChunk = 0; - std11::chrono::system_clock::time_point time; - //RIVER_SAVE_FILE_MACRO(int16_t,"aaa_test_INPUT.raw",&data[0],data.size()); - eq->process(time, &data[0], data.size(), outputVoid, outputNbChunk); - output = static_cast(outputVoid); - //RIVER_SAVE_FILE_MACRO(int16_t,"aaa_test_OUTPUT.raw",output,outputNbChunk); - float value = 0; - for (size_t iii=200; iii(float(freq),float(gain))); } m_displayer->setValue(pratic); } - - -std::vector > appl::Windows::calculateTheory(double _sampleRate, std::vector _coef) { - std::vector > out; - double norm; - float m_a[3]; - float m_b[2]; - - m_a[0] = _coef[0]; - m_a[1] = _coef[1]; - m_a[2] = _coef[2]; - m_b[0] = _coef[3]; - m_b[1] = _coef[4]; - - bool buildLinear = true; - +void appl::Windows::onCallbackStartFloat() { + APPL_INFO("start "); + // create biquad + drain::BiQuadFloat bq; + // configure parameter + bq.setBiquad(m_type, m_cutFrequency, m_quality, m_gain, m_sampleRate); + std::vector > pratic; size_t len = 512; for (size_t iii=0; iii < len; iii++) { - double w; - if (buildLinear == true) { - // 0 to pi, linear scale - w = iii / (len - 1.0) * M_PI; - } else { - // 0.001 to 1, times pi, log scale - w = std::exp(std::log(1.0 / 0.001) * iii / (len - 1.0)) * 0.001 * M_PI; + float freq = iii / (len - 1.0) * m_sampleRate / 2.0; + // To reset filter + bq.reset(); + double m_phase = 0; + double baseCycle = 2.0*M_PI/double(m_sampleRate) * double(freq); + float gain = 0; + std::vector data; + // create sinus + data.resize(16000, 0); + for (int32_t iii=0; iii= 2*M_PI) { + m_phase -= 2*M_PI; + } } - double freq = iii / (len - 1.0) * _sampleRate / 2.0; - double phi = std::pow(std::sin(w/2.0), 2.0); - double y = std::log( std::pow(m_a[0]+m_a[1]+m_a[2], 2.0) - - 4.0*(m_a[0]*m_a[1] + 4.0*m_a[0]*m_a[2] + m_a[1]*m_a[2])*phi - + 16.0*m_a[0]*m_a[2]*phi*phi) - - std::log( std::pow(1.0+m_b[0]+m_b[1], 2.0) - - 4.0*(m_b[0] + 4.0*m_b[1] + m_b[0]*m_b[1])*phi - + 16.0*m_b[1]*phi*phi); - y = y * 10.0 / M_LN10; - - if (y <= -200) { - y = -200.0; + //RIVER_SAVE_FILE_MACRO(float,"aaa_test_INPUT_F.raw",&data[0],data.size()); + bq.processFloat(&data[0], &data[0], data.size(), 1, 1); + //RIVER_SAVE_FILE_MACRO(float,"aaa_test_OUTPUT_F.raw",&data[0],data.size()); + float value = 0; + for (size_t iii=200; iii(float(freq),float(gain))); } - return out; + m_displayer->setValue(pratic); } + diff --git a/tools/drainEqualizerProfiling/appl/Windows.h b/tools/drainEqualizerProfiling/appl/Windows.h index 4d4b938..ca3f173 100644 --- a/tools/drainEqualizerProfiling/appl/Windows.h +++ b/tools/drainEqualizerProfiling/appl/Windows.h @@ -36,6 +36,8 @@ namespace appl { void onCallbackQuality(const std::string& _value); void onCallbackQualitySlider(const float& _value); void onCallbackStart(); + void onCallbackStart16(); + void onCallbackStartFloat(); protected: int32_t m_sampleRate; std::vector m_listSampleRate; @@ -44,7 +46,6 @@ namespace appl { float m_cutFrequency; float m_gain; float m_quality; - std::vector > calculateTheory(double _sampleRate, std::vector _coef); }; }; diff --git a/tools/drainEqualizerProfiling/appl/widget/DisplayFrequency.cpp b/tools/drainEqualizerProfiling/appl/widget/DisplayFrequency.cpp index ab70d0b..84c971e 100644 --- a/tools/drainEqualizerProfiling/appl/widget/DisplayFrequency.cpp +++ b/tools/drainEqualizerProfiling/appl/widget/DisplayFrequency.cpp @@ -65,10 +65,7 @@ void appl::widget::DisplayFrequency::onRegenerateDisplay() { // remove previous data m_draw.clear(); m_text.clear(); - m_borderSize = m_size * 0.05; - - // set background m_draw.setColor(etk::color::black); m_draw.setPos(vec2(0,0)); @@ -80,9 +77,7 @@ void appl::widget::DisplayFrequency::onRegenerateDisplay() { m_draw.lineTo(vec2(m_borderSize.x(), plop.y())); m_draw.lineTo(m_size-m_borderSize); m_draw.lineTo(vec2(plop.x(), m_borderSize.y())); - m_draw.lineTo(m_borderSize); - if (m_data.size() == 0) { return; } @@ -91,15 +86,27 @@ void appl::widget::DisplayFrequency::onRegenerateDisplay() { m_gainMin = 9999999999.9; m_frequencyMin = 99999999.0; m_frequencyMax = -99999999.0; + bool displayLog = true; for (size_t kkk=0; kkk::infinity()) { m_gainMax = std::max(m_gainMax, m_data[kkk][iii].second); m_gainMin = std::min(m_gainMin, m_data[kkk][iii].second); } - if (std::abs(m_data[kkk][iii].first) != std::numeric_limits::infinity()) { - m_frequencyMax = std::max(m_frequencyMax, m_data[kkk][iii].first); - m_frequencyMin = std::min(m_frequencyMin, m_data[kkk][iii].first); + if (displayLog == false) { + if (std::abs(m_data[kkk][iii].first) != std::numeric_limits::infinity()) { + m_frequencyMax = std::max(m_frequencyMax, m_data[kkk][iii].first); + m_frequencyMin = std::min(m_frequencyMin, m_data[kkk][iii].first); + } + } else { + if (std::abs(m_data[kkk][iii].first) != std::numeric_limits::infinity()) { + if (m_data[kkk][iii].first == 0) { + continue; + } + m_frequencyMax = std::max(m_frequencyMax, std::log(m_data[kkk][iii].first)); + m_frequencyMin = std::min(m_frequencyMin, std::log(m_data[kkk][iii].first)); + APPL_INFO("plop " << m_data[kkk][iii].first << " " << std::log(m_data[kkk][iii].first)); + } } } } @@ -124,14 +131,26 @@ void appl::widget::DisplayFrequency::onRegenerateDisplay() { float ratioX = (m_size.x()-m_borderSize.x()*2.0) / (m_frequencyMax - m_frequencyMin); float ratioY = (m_size.y()-m_borderSize.y()*2.0) / (m_gainMax - m_gainMin); - m_draw.setPos( m_borderSize - + vec2(ratioX*(m_data[kkk][0].first - m_frequencyMin), - ratioY*(m_data[kkk][0].second - m_gainMin))); - float baseX = 0; - for (size_t iii=1; iii - +