[DEV] create single handle of bequad

This commit is contained in:
Edouard DUPIN 2015-03-30 21:00:12 +02:00
parent 0c2b9f7323
commit 20275009b3
19 changed files with 1417 additions and 415 deletions

284
drain/BiQuadFloat.cpp Normal file
View File

@ -0,0 +1,284 @@
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license APACHE v2.0 (see license file)
*/
#include <drain/debug.h>
#include <drain/BiQuadFloat.h>
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<enum drain::filterType>(const enum drain::filterType& _variable) {
return listValues[_variable];
}
template <> bool from_string<enum drain::filterType>(enum drain::filterType& _variableRet, const std::string& _value) {
for (int32_t iii=0; iii<listValuesSize; ++iii) {
if (_value == listValues[iii]) {
_variableRet = static_cast<enum drain::filterType>(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<int16_t>(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<float> drain::BiQuadFloat::getCoef() {
std::vector<float> 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<std::pair<float,float> > drain::BiQuadFloat::calculateTheory(double _sampleRate) {
std::vector<std::pair<float,float> > 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<float,float>(freq, y));
}
return out;
}

95
drain/BiQuadFloat.h Normal file
View File

@ -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 <drain/Algo.h>
#include <etk/memory.h>
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<float> 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<std::pair<float,float> > calculateTheory(double _sampleRate);
};
}
#endif

View File

@ -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> 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<float*>(_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<m_biquads[jjj].size(); ++iii) {
m_biquads[jjj][iii].processFloat(data, data, _inputNbChunk, getInputFormat().getMap().size(), getOutputFormat().getMap().size() );
}
}
} else if (getOutputFormat().getFormat() == audio::format_int16) {
@ -79,14 +65,8 @@ bool drain::Equalizer::process(std11::chrono::system_clock::time_point& _time,
int16_t* data = static_cast<int16_t*>(_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<int16_t>(out);
// move to the sample on the same channel.
data += getOutputFormat().getMap().size();
for (size_t iii=0; iii<m_biquads[jjj].size(); ++iii) {
m_biquads[jjj][iii].processInt16(data, data, _inputNbChunk, getInputFormat().getMap().size(), getOutputFormat().getMap().size() );
}
}
}
@ -95,44 +75,15 @@ bool drain::Equalizer::process(std11::chrono::system_clock::time_point& _time,
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_lowPass;
} else if (_value == "HPF") {
m_type = drain::filterType_highPass;
} else if (_value == "BPF") {
m_type = drain::filterType_bandPass;
} else if (_value == "NOTCH") {
m_type = drain::filterType_notch;
} else if (_value == "PeakingEQ") {
m_type = drain::filterType_peak;
} else if (_value == "LSH") {
m_type = drain::filterType_lowShelf;
} else if (_value == "HSH") {
m_type = drain::filterType_highShelf;
} else {
DRAIN_ERROR("Can not set equalizer type : " << _value);
return false;
}
if (_parameter == "config") {
m_config = ejson::Object::create(_value);
configureBiQuad();
return true;
} else if (_parameter == "gain") {
m_gain = etk::string_to_double(_value);
configureBiQuad();
return true;
} else if (_parameter == "frequency") {
m_frequencyCut = etk::string_to_double(_value);
configureBiQuad();
return true;
} 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());
for (int32_t iii=0; iii<m_biquads.size(); ++iii) {
for (int32_t jjj=0; jjj<m_biquads[iii].size(); ++jjj) {
m_biquads[iii][jjj].reset();
}
}
return true;
}
return false;
@ -146,194 +97,75 @@ std::string drain::Equalizer::getParameterProperty(const std::string& _parameter
return "error";
}
float drain::Equalizer::processFloat(float _sample, drain::BGHistory& _history) {
float result;
// compute
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[1] = _history.m_x[0];
_history.m_x[0] = _sample;
//update history of Y
_history.m_y[1] = _history.m_y[0];
_history.m_y[0] = result;
return result;
static drain::BiQuadFloat getBiquad(const std11::shared_ptr<const ejson::Object>& _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<const ejson::Array> global = m_config->getArray("global");
if (global != nullptr) {
// only global configuration get all elements:
for (size_t kkk=0; kkk<global->size(); ++kkk) {
const std11::shared_ptr<const ejson::Object> 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<enum drain::filterType>(const enum drain::filterType& _variable) {
return listValues[_variable];
}
template <> bool from_string<enum drain::filterType>(enum drain::filterType& _variableRet, const std::string& _value) {
for (int32_t iii=0; iii<listValuesSize; ++iii) {
if (_value == listValues[iii]) {
_variableRet = static_cast<enum drain::filterType>(iii);
return true;
// declare biquad:
drain::BiQuadFloat biquad = getBiquad(tmpObject, getOutputFormat().getFrequency());
// add this bequad for every Channel:
for (size_t iii=0; iii<m_biquads.size(); ++iii) {
m_biquads[iii].push_back(biquad);
}
}
_variableRet = drain::filterType_none;
return false;
return;
}
for (size_t iii=0; iii<getOutputFormat().getMap().size(); ++iii) {
std::string channelName = etk::to_string(getOutputFormat().getMap()[iii]);
const std11::shared_ptr<const ejson::Array> 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; kkk<channelConfig->size(); ++kkk) {
const std11::shared_ptr<const ejson::Object> 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;
}

View File

@ -9,29 +9,10 @@
#include <drain/Algo.h>
#include <etk/memory.h>
#include <ejson/Object.h>
#include <drain/BiQuadFloat.h>
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<ejson::Object> 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<BGHistory> 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<std::vector<BiQuadFloat> > 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<float> getCoef() {
std::vector<float> 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();
};
};

View File

@ -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

View File

@ -0,0 +1,305 @@
/**
* @author Edouard DUPIN
*
* @copyright 2010, Edouard DUPIN, all right reserved
*
* @license APACHE-2 (see license file)
*/
#include <ewol/ewol.h>
#include <appl/debug.h>
#include <appl/Windows.h>
#include <ewol/widget/Label.h>
#include <ewol/widget/Entry.h>
#include <ewol/widget/Button.h>
#include <ewol/widget/Slider.h>
#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<appl::widget::DisplayFrequency>(getSubObjectNamed("displayer"));
onCallbackStart();
}
void appl::Windows::onCallbackSampleRateUp() {
for (int32_t iii=0; iii<m_listSampleRate.size(); ++iii) {
if (m_sampleRate == m_listSampleRate[iii]) {
iii++;
if (iii<m_listSampleRate.size()) {
m_sampleRate = m_listSampleRate[iii];
} else {
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();
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::onCallbackSampleRateLow() {
for (int32_t iii=0; iii<m_listSampleRate.size(); ++iii) {
if (m_sampleRate == m_listSampleRate[iii]) {
iii--;
if (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<m_listType.size(); ++iii) {
if (m_type == m_listType[iii]) {
iii++;
if (iii<m_listType.size()) {
m_type = m_listType[iii];
} else {
m_type = m_listType[0];
}
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::onCallbackTypeLow() {
for (int32_t iii=0; iii<m_listType.size(); ++iii) {
if (m_type == m_listType[iii]) {
iii--;
if (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 <river/debug.h>
void appl::Windows::onCallbackStart() {
APPL_INFO("start ");
int32_t iii = 10;
std::vector<audio::channel> 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<std::pair<float,float> > 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<std::pair<float,float> > 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<int16_t> data;
// create sinus
data.resize(16000, 0);
for (int32_t iii=0; iii<data.size(); iii++) {
data[iii] = cos(m_phase) * 32000;
m_phase += baseCycle;
if (m_phase >= 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<data.size()-200; ++iii) {
value = std::max(value, data[iii]);
}
gain = 20.0 * std::log10(double(value)/32000.0);
APPL_VERBOSE("LEVEL " << iii << " out = " << value << " % : " << gain);
pratic.push_back(std::make_pair<float, float>(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<std::pair<float,float> > 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<float> data;
// create sinus
data.resize(16000, 0);
for (int32_t iii=0; iii<data.size(); iii++) {
data[iii] = cos(m_phase);
m_phase += baseCycle;
if (m_phase >= 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<data.size()-200; ++iii) {
value = std::max(value, data[iii]);
}
gain = 20.0 * std::log10(double(value)/1.0);
APPL_VERBOSE("LEVEL " << iii << " out = " << value << " % : " << gain);
pratic.push_back(std::make_pair<float, float>(float(freq),float(gain)));
}
m_displayer->setValue(pratic);
}

View File

@ -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 <ewol/widget/Windows.h>
#include <ewol/widget/Layer.h>
#include <ewol/widget/Composer.h>
#include <drain/Equalizer.h>
#include <appl/widget/DisplayFrequency.h>
namespace appl {
class Windows : public ewol::widget::Windows {
protected:
Windows();
void init();
public:
DECLARE_FACTORY(Windows);
protected:
std::shared_ptr<ewol::widget::Composer> m_gui;
std::shared_ptr<appl::widget::DisplayFrequency> 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<int32_t> m_listSampleRate;
enum drain::filterType m_type;
std::vector<enum drain::filterType> m_listType;
float m_cutFrequency;
float m_gain;
float m_quality;
};
};
#endif

View File

@ -0,0 +1,15 @@
/**
* @author Edouard DUPIN
*
* @copyright 2010, Edouard DUPIN, all right reserved
*
* @license APACHE-2 (see license file)
*/
#include <appl/debug.h>
int32_t appl::getLogId() {
static int32_t g_val = etk::log::registerInstance("drain-equalizer");
return g_val;
}

View File

@ -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 <etk/log.h>
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

View File

@ -0,0 +1,60 @@
/**
* @author Edouard DUPIN
*
* @copyright 2010, Edouard DUPIN, all right reserved
*
* @license GPL v3 (see license file)
*/
#include <etk/types.h>
#include <ewol/ewol.h>
#include <ewol/context/commandLine.h>
#include <appl/debug.h>
#include <appl/Windows.h>
#include <ewol/object/Object.h>
#include <ewol/widget/Manager.h>
#include <ewol/context/Context.h>
#include <appl/widget/DisplayFrequency.h>
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<ewol::widget::Windows> 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);
}

View File

@ -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

View File

@ -0,0 +1,176 @@
/**
* @author Edouard DUPIN
*
* @copyright 2010, Edouard DUPIN, all right reserved
*
* @license APACHE-2 (see license file)
*/
#include <appl/widget/DisplayFrequency.h>
#include <appl/debug.h>
#include <etk/tool.h>
#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<std::pair<float,float> >& _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<m_data.size(); kkk++) {
for (size_t iii=0; iii<m_data[kkk].size(); ++iii) {
if (std::abs(m_data[kkk][iii].second) != std::numeric_limits<float>::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<float>::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<float>::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<m_data[0].size() && m_data[1].size(); ++iii) {
APPL_INFO(" f=" << m_data[0][iii].first << " val=" << m_data[0][iii].second << " f=" << m_data[1][iii].first << " val=" << m_data[1][iii].second);
}
*/
// set all the line:
m_draw.setThickness(1);
//APPL_ERROR("---------------------------");
for (size_t kkk=0; kkk<m_data.size(); ++kkk) {
//APPL_ERROR("kjhkjhkj " << kkk << " " << m_data.size());
if (kkk == 0) {
m_draw.setColor(etk::color::green);
} else if (kkk == 0) {
m_draw.setColor(etk::color::orange);
} else {
m_draw.setColor(etk::color::red);
}
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);
if (displayLog == false) {
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<m_data[kkk].size(); ++iii) {
m_draw.lineTo( m_borderSize
+ vec2(ratioX*(m_data[kkk][iii].first - m_frequencyMin),
ratioY*(m_data[kkk][iii].second - m_gainMin)));
}
} else {
m_draw.setPos( m_borderSize
+ vec2(ratioX*(std::log(m_data[kkk][0].first) - m_frequencyMin),
ratioY*(m_data[kkk][0].second - m_gainMin)));
float baseX = 0;
for (size_t iii=1; iii<m_data[kkk].size(); ++iii) {
m_draw.lineTo( m_borderSize
+ vec2(ratioX*(std::log(m_data[kkk][iii].first) - m_frequencyMin),
ratioY*(m_data[kkk][iii].second - m_gainMin)));
}
}
}
m_text.setDefaultColorFg(etk::color::green);
std::string textToDisplay = etk::to_string(m_frequencyMin) + " Hz";
vec3 size = m_text.calculateSize(textToDisplay);
m_text.setPos(vec2(m_borderSize.x(), m_borderSize.y()-size.y()));
m_text.print(textToDisplay);
textToDisplay = etk::to_string(m_frequencyMax) + " Hz";
size = m_text.calculateSize(textToDisplay);
m_text.setPos(vec2(m_size.x()-m_borderSize.x()-size.x(), m_borderSize.y()-size.y()));
m_text.print(textToDisplay);
textToDisplay = etk::to_string(m_gainMin) + " dB";
size = m_text.calculateSize(textToDisplay);
m_text.setPos(vec2(m_borderSize.x(), m_borderSize.y()));
m_text.print(textToDisplay);
textToDisplay = etk::to_string(m_gainMax) + " dB";
size = m_text.calculateSize(textToDisplay);
m_text.setPos(vec2(m_borderSize.x(), m_size.y() - m_borderSize.y()));
m_text.print(textToDisplay);
}

View File

@ -0,0 +1,58 @@
/**
* @author Edouard DUPIN
*
* @copyright 2010, Edouard DUPIN, all right reserved
*
* @license APACHE-2 (see license file)
*/
#ifndef __APPL_WIDGET_DISPLAY_FREQUENCY_H__
#define __APPL_WIDGET_DISPLAY_FREQUENCY_H__
#include <ewol/widget/Widget.h>
#include <ewol/compositing/Drawing.h>
#include <ewol/compositing/Text.h>
#include <ewol/widget/Manager.h>
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<std::vector<std::pair<float,float> > > m_data; //!< data that might be displayed
public:
void clear() {
m_data.clear();
}
void setValue(const std::vector<std::pair<float,float> >& _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

View File

@ -0,0 +1,76 @@
<?xml version="1.0" encoding="UTF-8"?>
<sizer mode="hori" expand="true" fill="true" lock="true" max-size="20,100%">
<sizer mode="vert" expand="false,true" fill="true" lock="true" max-size="100%" addmode="invert">
<!--
<sizer mode="hori">
<button name="save">
<label>Save</label>
</button>
<button name="load">
<label>Load</label>
</button>
</sizer>
-->
<label>Global parameter: .........</label>
<sizer mode="vert" expand="true,false" lock="true" border="0.2%" addmode="invert">
<spacer min-size="5,5px"/>
<label>Sample rate:</label>
<sizer mode="hori">
<button name="sample-rate-low">
<label>---</label>
</button>
<label expand="true" fill="true" name="sample-rate">
48000
</label>
<button name="sample-rate-up">
<label>+++</label>
</button>
</sizer>
</sizer>
<label>Filter:</label>
<sizer mode="vert" expand="true,false" lock="true" border="0.2%" addmode="invert">
<spacer min-size="5,5px"/>
<label>type:</label>
<sizer mode="hori">
<button name="type-low">
<label>---</label>
</button>
<label expand="true" fill="true" name="type">
Low-pass
</label>
<button name="type-up">
<label>+++</label>
</button>
</sizer>
<spacer min-size="5,5px"/>
<sizer mode="hori">
<label>gain:</label>
<entry expand="true" fill="true" name="gain" regex="-?(\.|[0-9])*" value="0"/>
</sizer>
<slider expand="true" name="gain-slider" value="0" min="-30" max="+30" step="0.01"/>
<spacer min-size="5,5px"/>
<sizer mode="hori">
<label>cut frequency:</label>
<entry expand="true" fill="true" name="frequency" regex="[0-9]*" value="1000"/>
</sizer>
<slider expand="true" name="frequency-slider" value="8000" min="1" max="24000" step="0.01"/>
<spacer min-size="5,5px"/>
<sizer mode="hori">
<label>Quality factor:</label>
<entry expand="true" fill="true" name="quality" regex="[0-9]*" value="100"/>
</sizer>
<slider expand="true" name="quality-slider" value="0.707" min="0.001" max="50" step="0.001"/>
</sizer>
<button name="display16">
<label>test int16_t</label>
</button>
<button name="displayFloat">
<label>test float</label>
</button>
<Spacer expand="true,true"/>
</sizer>
<DisplayFrequency name="displayer" fill="true" expand="true"/>
</sizer>

View File

@ -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

View File

@ -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<appl::widget::DisplayFrequency>(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<drain::Equalizer> 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<std::pair<float,float> > theory = calculateTheory(m_sampleRate, eq->getCoef());
bq.setBiquad(m_type, m_cutFrequency, m_quality, m_gain, m_sampleRate);
std::vector<std::pair<float,float> > 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<std::pair<float,float> > 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<int16_t> data;
// create sinus
data.resize(16000, 0);
for (int32_t iii=0; iii<data.size(); iii++) {
data[iii] = cos(m_phase) * 32000;
m_phase += baseCycle;
if (m_phase >= 2*M_PI) {
m_phase -= 2*M_PI;
}
std::vector<int16_t> data;
// create sinus
data.resize(16000, 0);
for (int32_t iii=0; iii<data.size(); iii++) {
data[iii] = cos(m_phase) * 32000;
m_phase += baseCycle;
if (m_phase >= 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<int16_t*>(outputVoid);
//RIVER_SAVE_FILE_MACRO(int16_t,"aaa_test_OUTPUT.raw",output,outputNbChunk);
int16_t value = 0;
for (size_t iii=200; iii<outputNbChunk-200; ++iii) {
value = std::max(value, output[iii]);
}
gain = 20.0 * std::log10(double(value)/32000.0);
APPL_VERBOSE("LEVEL " << iii << " out = " << value << " % : " << gain);
} else if (format.getFormat() == audio::format_float) {
std::vector<float> data;
// create sinus
data.resize(16000, 0);
for (int32_t iii=0; iii<data.size(); iii++) {
data[iii] = cos(m_phase);
m_phase += baseCycle;
if (m_phase >= 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<float*>(outputVoid);
//RIVER_SAVE_FILE_MACRO(int16_t,"aaa_test_OUTPUT.raw",output,outputNbChunk);
float value = 0;
for (size_t iii=200; iii<outputNbChunk-200; ++iii) {
value = std::max(value, output[iii]);
}
gain = 20.0 * std::log10(double(value)/1.0);
APPL_VERBOSE("LEVEL " << iii << " out = " << value << " % : " << gain);
}
// 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<data.size()-200; ++iii) {
value = std::max(value, data[iii]);
}
gain = 20.0 * std::log10(double(value)/32000.0);
APPL_VERBOSE("LEVEL " << iii << " out = " << value << " % : " << gain);
pratic.push_back(std::make_pair<float, float>(float(freq),float(gain)));
}
m_displayer->setValue(pratic);
}
std::vector<std::pair<float,float> > appl::Windows::calculateTheory(double _sampleRate, std::vector<float> _coef) {
std::vector<std::pair<float,float> > 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<std::pair<float,float> > 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<float> data;
// create sinus
data.resize(16000, 0);
for (int32_t iii=0; iii<data.size(); iii++) {
data[iii] = cos(m_phase);
m_phase += baseCycle;
if (m_phase >= 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<data.size()-200; ++iii) {
value = std::max(value, data[iii]);
}
APPL_DEBUG("theory = " << freq << " power=" << y);
out.push_back(std::make_pair<float,float>(freq, y));
gain = 20.0 * std::log10(double(value)/1.0);
APPL_VERBOSE("LEVEL " << iii << " out = " << value << " % : " << gain);
pratic.push_back(std::make_pair<float, float>(float(freq),float(gain)));
}
return out;
m_displayer->setValue(pratic);
}

View File

@ -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<int32_t> m_listSampleRate;
@ -44,7 +46,6 @@ namespace appl {
float m_cutFrequency;
float m_gain;
float m_quality;
std::vector<std::pair<float,float> > calculateTheory(double _sampleRate, std::vector<float> _coef);
};
};

View File

@ -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<m_data.size(); kkk++) {
for (size_t iii=0; iii<m_data[kkk].size(); ++iii) {
if (std::abs(m_data[kkk][iii].second) != std::numeric_limits<float>::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<float>::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<float>::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<float>::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<m_data[kkk].size(); ++iii) {
m_draw.lineTo( m_borderSize
+ vec2(ratioX*(m_data[kkk][iii].first - m_frequencyMin),
ratioY*(m_data[kkk][iii].second - m_gainMin)));
if (displayLog == false) {
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<m_data[kkk].size(); ++iii) {
m_draw.lineTo( m_borderSize
+ vec2(ratioX*(m_data[kkk][iii].first - m_frequencyMin),
ratioY*(m_data[kkk][iii].second - m_gainMin)));
}
} else {
m_draw.setPos( m_borderSize
+ vec2(ratioX*(std::log(m_data[kkk][0].first) - m_frequencyMin),
ratioY*(m_data[kkk][0].second - m_gainMin)));
float baseX = 0;
for (size_t iii=1; iii<m_data[kkk].size(); ++iii) {
m_draw.lineTo( m_borderSize
+ vec2(ratioX*(std::log(m_data[kkk][iii].first) - m_frequencyMin),
ratioY*(m_data[kkk][iii].second - m_gainMin)));
}
}
}
m_text.setDefaultColorFg(etk::color::green);
@ -145,7 +164,6 @@ void appl::widget::DisplayFrequency::onRegenerateDisplay() {
m_text.setPos(vec2(m_size.x()-m_borderSize.x()-size.x(), m_borderSize.y()-size.y()));
m_text.print(textToDisplay);
m_text.setDefaultColorFg(etk::color::blue);
textToDisplay = etk::to_string(m_gainMin) + " dB";
size = m_text.calculateSize(textToDisplay);
m_text.setPos(vec2(m_borderSize.x(), m_borderSize.y()));

View File

@ -64,8 +64,11 @@
</sizer>
<slider expand="true" name="quality-slider" value="0.707" min="0.001" max="50" step="0.001"/>
</sizer>
<button name="display">
<label>Display</label>
<button name="display16">
<label>test int16_t</label>
</button>
<button name="displayFloat">
<label>test float</label>
</button>
<Spacer expand="true,true"/>
</sizer>