diff --git a/drain/Equalizer.cpp b/drain/Equalizer.cpp index f9c716c..b2fd917 100644 --- a/drain/Equalizer.cpp +++ b/drain/Equalizer.cpp @@ -9,6 +9,7 @@ #include // see http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt +// see http://www.earlevel.com/main/2013/10/13/biquad-calculator-v2/ drain::Equalizer::Equalizer() { @@ -18,17 +19,18 @@ 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 = 0; - m_frequency = 1000; - m_bandWidth = 200; + m_gain = 6; + m_frequencyCut = 1000; + m_qualityFactor = 0.707; 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[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() { @@ -58,46 +60,58 @@ bool drain::Equalizer::process(std11::chrono::system_clock::time_point& _time, 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(); + if (getOutputFormat().getFormat() == audio::format_float) { + 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. + *data = processFloat(*data, m_history[jjj]); + // move to the sample on the same channel. + data += getOutputFormat().getMap().size(); + } + } + } else if (getOutputFormat().getFormat() == audio::format_int16) { + 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) { + //DRAIN_WARNING("set : " << _parameter << " " << _value); if (_parameter == "type") { if (_value == "none") { m_type = drain::filterType_none; } else if (_value == "LPF") { - m_type = drain::filterType_LPF; + m_type = drain::filterType_lowPass; } else if (_value == "HPF") { - m_type = drain::filterType_HPF; + m_type = drain::filterType_highPass; } else if (_value == "BPF") { - m_type = drain::filterType_BPF; + m_type = drain::filterType_bandPass; } else if (_value == "NOTCH") { - m_type = drain::filterType_NOTCH; - } else if (_value == "APF") { - m_type = drain::filterType_APF; + m_type = drain::filterType_notch; } else if (_value == "PeakingEQ") { - m_type = drain::filterType_PeakingEQ; + m_type = drain::filterType_peak; } else if (_value == "LSH") { - m_type = drain::filterType_LSH; + m_type = drain::filterType_lowShelf; } else if (_value == "HSH") { - m_type = drain::filterType_HSH; - } else if (_value == "EQU"){ - m_type = drain::filterType_EQU; + m_type = drain::filterType_highShelf; } else { DRAIN_ERROR("Can not set equalizer type : " << _value); return false; @@ -105,17 +119,21 @@ bool drain::Equalizer::setParameter(const std::string& _parameter, const std::st configureBiQuad(); return true; } else if (_parameter == "gain") { - m_gain = etk::string_to_int32_t(_value); + m_gain = etk::string_to_double(_value); configureBiQuad(); return true; } else if (_parameter == "frequency") { - m_frequency = etk::string_to_int32_t(_value); + m_frequencyCut = etk::string_to_double(_value); configureBiQuad(); return true; - } else if (_parameter == "band-width") { - m_bandWidth = etk::string_to_int32_t(_value); + } else if (_parameter == "quality") { + m_qualityFactor = etk::string_to_double(_value); configureBiQuad(); return true; + } else if (_parameter == "reset") { + m_history.clear(); + m_history.resize(getOutputFormat().getMap().size()); + return true; } return false; } @@ -131,116 +149,162 @@ std::string drain::Equalizer::getParameterProperty(const std::string& _parameter 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]; + result = m_a[0] * _sample + + m_a[1] * _history.m_x[0] + + m_a[2] * _history.m_x[1] + - m_b[0] * _history.m_y[0] + - m_b[1] * _history.m_y[1]; //update history of X - _history.m_x[0] = _history.m_x[1]; - _history.m_x[1] = _sample; + _history.m_x[1] = _history.m_x[0]; + _history.m_x[0] = _sample; //update history of Y - _history.m_y[0] = _history.m_y[1]; - _history.m_y[1] = result; + _history.m_y[1] = _history.m_y[0]; + _history.m_y[0] = 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; + 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; + 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; + } + 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; + } +} diff --git a/drain/Equalizer.h b/drain/Equalizer.h index 78b9eef..e3b33db 100644 --- a/drain/Equalizer.h +++ b/drain/Equalizer.h @@ -12,16 +12,14 @@ 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 + 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: @@ -64,18 +62,33 @@ namespace drain { //----------------------------------------- // 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 + 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[2]; //!< A bi-Quad coef - float m_b[3]; //!< B bi-Quad coef + 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. */ bool configureBiQuad(); + public: + /** + * @brief Configure the current biquad. + */ + 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; + } }; }; diff --git a/tools/drainEqualizerProfiling/appl/Windows.cpp b/tools/drainEqualizerProfiling/appl/Windows.cpp index 3b85dc0..cb12851 100644 --- a/tools/drainEqualizerProfiling/appl/Windows.cpp +++ b/tools/drainEqualizerProfiling/appl/Windows.cpp @@ -18,10 +18,10 @@ appl::Windows::Windows() : m_sampleRate(48000), - m_type(drain::filterType::filterType_LPF), - m_cutFrequency(2000), - m_gain(2), - m_bandWidth(200) { + m_type(drain::filterType::filterType_lowPass), + m_cutFrequency(8000.0), + m_gain(6.0), + m_bandWidth(0.1) { addObjectType("appl::Windows"); } @@ -39,6 +39,7 @@ void appl::Windows::init() { subBind(ewol::widget::Entry, "frequency", signalModify, shared_from_this(), &appl::Windows::onCallbackFrequency); subBind(ewol::widget::Entry, "band-width", signalModify, shared_from_this(), &appl::Windows::onCallbackBandWidth); subBind(ewol::widget::Button, "display", signalPressed, shared_from_this(), &appl::Windows::onCallbackStart); + m_displayer = std11::dynamic_pointer_cast(getSubObjectNamed("displayer")); } void appl::Windows::onCallbackSampleRate(const std::string& _value) { @@ -63,7 +64,7 @@ void appl::Windows::onCallbackType(const std::string& _value) { std::vector list; list.push_back("HPF"); list.push_back("LPF"); - if (etk::isIn(etk::string_to_int32_t(_value), list) == true) { + if (etk::isIn(_value, list) == true) { ewol::parameterSetOnObjectNamed("type-valid", "color", "green"); } else { ewol::parameterSetOnObjectNamed("type-valid", "color", "red"); @@ -82,30 +83,161 @@ void appl::Windows::onCallbackBandWidth(const std::string& _value) { APPL_INFO("BandWidth " << _value); } +#include + void appl::Windows::onCallbackStart() { APPL_INFO("start "); - m_data.clear(); - int32_t iii = 200; - while (iii < m_sampleRate/2) { - APPl_INFO("TEST : " << iii); - // create equalizer - std11::shared_ptr eq = drain::Equalizer::create(); - // configure parameter - eq->setParameter("type", "LPF"); - eq->setParameter("gain", etk::to_string(m_gain)); - eq->setParameter("frequency", etk::to_string(m_cutFrequency)); - eq->setParameter("band-width", etk::to_string(m_bandWidth)); - // configure input - - // configure outpur + int32_t iii = 10; + std::vector map; + map.push_back(audio::channel_frontCenter); + drain::IOFormatInterface format(map, audio::format_int16, m_sampleRate); + // create equalizer + std11::shared_ptr eq = drain::Equalizer::create(); + // configure input + eq->setInputFormat(format); + // configure output + eq->setOutputFormat(format); + // configure parameter + /* + eq->setParameter("type", "APF"); + eq->setParameter("gain", etk::to_string(m_gain)); + eq->setParameter("frequency", etk::to_string(m_cutFrequency)); + eq->setParameter("band-width", etk::to_string(m_bandWidth)); + */ + //eq->calcBiquad(drain::filterType_none, m_cutFrequency, 0.707, m_gain); + eq->calcBiquad(drain::filterType_lowPass, m_cutFrequency, 0.707, m_gain); + //eq->calcBiquad(drain::filterType_highPass, m_cutFrequency, 0.707, m_gain); + std::vector > theory = calculateTheory(48000, eq->getCoef()); + m_displayer->clear(); + m_displayer->setValue(theory); + 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; + //} + double freq = iii / (len - 1.0) * 48000 / 2.0; + //while (iii < m_sampleRate/2) { + std::vector data; + //APPL_INFO("TEST : " << iii); + // To reset filter + eq->setParameter("reset", ""); // create sinus - + data.resize(4096, 0); + double m_phase = 0; + double baseCycle = 2.0*M_PI/double(m_sampleRate) * double(freq); + for (int32_t iii=0; iii= 2*M_PI) { + m_phase -= 2*M_PI; + } + } // process - - iii += 200; + 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=20; iii(iii,float(value)/30000.0f)); + iii += 10; } - + /* + while (iii < m_sampleRate/2) { + std::vector data; + //APPL_INFO("TEST : " << iii); + // To reset filter + eq->setParameter("reset", ""); + // create sinus + data.resize(4096, 0); + double m_phase = 0; + double baseCycle = 2.0*M_PI/double(m_sampleRate) * double(iii); + 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(float,"aaa_test_INPUT_F.raw",&data[0],data.size()); + eq->process(time, &data[0], data.size(), outputVoid, outputNbChunk); + output = static_cast(outputVoid); + RIVER_SAVE_FILE_MACRO(float,"aaa_test_OUTPUT_F.raw",output,outputNbChunk); + double value = 0; + for (size_t iii=0; iii(iii,float(value))); + iii += 10; + } + */ + 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; + + 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 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_INFO("theory = " << iii / (len - 1.0) * _sampleRate / 2.0 << " power=" << y); + out.push_back(std::make_pair(iii / (len - 1.0) * _sampleRate / 2.0, y + 0.5)); + } + return out; +} diff --git a/tools/drainEqualizerProfiling/appl/Windows.h b/tools/drainEqualizerProfiling/appl/Windows.h index 3acc8a4..bb339b1 100644 --- a/tools/drainEqualizerProfiling/appl/Windows.h +++ b/tools/drainEqualizerProfiling/appl/Windows.h @@ -13,6 +13,7 @@ #include #include #include +#include namespace appl { class Windows : public ewol::widget::Windows { @@ -23,6 +24,7 @@ namespace appl { DECLARE_FACTORY(Windows); protected: std::shared_ptr m_gui; + std::shared_ptr m_displayer; void onCallbackSampleRate(const std::string& _value); void onCallbackType(const std::string& _value); void onCallbackGain(const std::string& _value); @@ -35,7 +37,7 @@ namespace appl { float m_cutFrequency; float m_gain; float m_bandWidth; - std::vector > m_data; + 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 1143ce7..37669bb 100644 --- a/tools/drainEqualizerProfiling/appl/widget/DisplayFrequency.cpp +++ b/tools/drainEqualizerProfiling/appl/widget/DisplayFrequency.cpp @@ -34,7 +34,7 @@ appl::widget::DisplayFrequency::~DisplayFrequency() { void appl::widget::DisplayFrequency::setValue(const std::vector >& _data) { - m_data = _data; + m_data.push_back(_data); markToRedraw(); } @@ -62,25 +62,67 @@ void appl::widget::DisplayFrequency::onRegenerateDisplay() { } // remove previous data m_draw.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; } - // set all the line: - m_draw.setColor(etk::color::white); - m_draw.setThickness(1); - - float ratioX = m_size.x() / (m_frequencyMax - m_frequencyMin); - float ratioY = m_size.y() / (m_gainMax - m_gainMin); - m_draw.setPos(vec2(ratioX*(m_data[0].first - m_gainMin), - ratioY*(m_data[0].second - m_gainMin))); - float baseX = 0; - for (size_t iii=1; iii > m_data; //!< data that might be displayed + 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 @@ -44,6 +47,8 @@ namespace appl { public: // herited function virtual void onDraw(); virtual void onRegenerateDisplay(); + private: + vec2 m_borderSize; }; } } diff --git a/tools/drainEqualizerProfiling/lutin_drain_equalizer_profiling.py b/tools/drainEqualizerProfiling/lutin_drain_equalizer_profiling.py index ccbd602..4b6ffe8 100644 --- a/tools/drainEqualizerProfiling/lutin_drain_equalizer_profiling.py +++ b/tools/drainEqualizerProfiling/lutin_drain_equalizer_profiling.py @@ -17,7 +17,7 @@ def create(target): 'appl/widget/DisplayFrequency.cpp', ]) # add Library dependency name - myModule.add_module_depend(['ewol', 'drain']) + myModule.add_module_depend(['ewol', 'drain', 'river']) # add application C flags myModule.compile_flags_CC([ "-DPROJECT_NAME=\"\\\""+myModule.name+"\\\"\""])