[DEV] create single handle of bequad
This commit is contained in:
parent
0c2b9f7323
commit
20275009b3
284
drain/BiQuadFloat.cpp
Normal file
284
drain/BiQuadFloat.cpp
Normal 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
95
drain/BiQuadFloat.h
Normal 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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
305
tools/drainBiQuadProfiling/appl/Windows.cpp
Normal file
305
tools/drainBiQuadProfiling/appl/Windows.cpp
Normal 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);
|
||||
}
|
||||
|
53
tools/drainBiQuadProfiling/appl/Windows.h
Normal file
53
tools/drainBiQuadProfiling/appl/Windows.h
Normal 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
|
15
tools/drainBiQuadProfiling/appl/debug.cpp
Normal file
15
tools/drainBiQuadProfiling/appl/debug.cpp
Normal 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;
|
||||
}
|
43
tools/drainBiQuadProfiling/appl/debug.h
Normal file
43
tools/drainBiQuadProfiling/appl/debug.h
Normal 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
|
60
tools/drainBiQuadProfiling/appl/main.cpp
Normal file
60
tools/drainBiQuadProfiling/appl/main.cpp
Normal 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);
|
||||
}
|
||||
|
||||
|
14
tools/drainBiQuadProfiling/appl/main.h
Normal file
14
tools/drainBiQuadProfiling/appl/main.h
Normal 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
|
||||
|
176
tools/drainBiQuadProfiling/appl/widget/DisplayFrequency.cpp
Normal file
176
tools/drainBiQuadProfiling/appl/widget/DisplayFrequency.cpp
Normal 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);
|
||||
}
|
58
tools/drainBiQuadProfiling/appl/widget/DisplayFrequency.h
Normal file
58
tools/drainBiQuadProfiling/appl/widget/DisplayFrequency.h
Normal 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
|
76
tools/drainBiQuadProfiling/data/gui.xml
Normal file
76
tools/drainBiQuadProfiling/data/gui.xml
Normal 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>
|
34
tools/drainBiQuadProfiling/lutin_drain_biquad_profiling.py
Normal file
34
tools/drainBiQuadProfiling/lutin_drain_biquad_profiling.py
Normal 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
|
||||
|
||||
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -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()));
|
||||
|
@ -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>
|
||||
|
Loading…
Reference in New Issue
Block a user