[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::init();
|
||||||
drain::Algo::m_type = "Equalizer";
|
drain::Algo::m_type = "Equalizer";
|
||||||
m_supportedFormat.push_back(audio::format_int16);
|
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();
|
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() {
|
std11::shared_ptr<drain::Equalizer> drain::Equalizer::create() {
|
||||||
@ -45,9 +34,9 @@ drain::Equalizer::~Equalizer() {
|
|||||||
|
|
||||||
void drain::Equalizer::configurationChange() {
|
void drain::Equalizer::configurationChange() {
|
||||||
drain::Algo::configurationChange();
|
drain::Algo::configurationChange();
|
||||||
// Resize the configuration ouput of algirithm
|
if (m_biquads.size() != getOutputFormat().getMap().size()) {
|
||||||
m_history.clear();
|
configureBiQuad();
|
||||||
m_history.resize(getOutputFormat().getMap().size());
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool drain::Equalizer::process(std11::chrono::system_clock::time_point& _time,
|
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);
|
float* data = static_cast<float*>(_input);
|
||||||
// move to sample offset:
|
// move to sample offset:
|
||||||
data += jjj;
|
data += jjj;
|
||||||
for (size_t iii=0; iii<_inputNbChunk; ++iii) {
|
for (size_t iii=0; iii<m_biquads[jjj].size(); ++iii) {
|
||||||
// process in float the biquad.
|
m_biquads[jjj][iii].processFloat(data, data, _inputNbChunk, getInputFormat().getMap().size(), getOutputFormat().getMap().size() );
|
||||||
*data = processFloat(*data, m_history[jjj]);
|
|
||||||
// move to the sample on the same channel.
|
|
||||||
data += getOutputFormat().getMap().size();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (getOutputFormat().getFormat() == audio::format_int16) {
|
} 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);
|
int16_t* data = static_cast<int16_t*>(_input);
|
||||||
// move to sample offset:
|
// move to sample offset:
|
||||||
data += jjj;
|
data += jjj;
|
||||||
for (size_t iii=0; iii<_inputNbChunk; ++iii) {
|
for (size_t iii=0; iii<m_biquads[jjj].size(); ++iii) {
|
||||||
// process in float the biquad.
|
m_biquads[jjj][iii].processInt16(data, data, _inputNbChunk, getInputFormat().getMap().size(), getOutputFormat().getMap().size() );
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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) {
|
bool drain::Equalizer::setParameter(const std::string& _parameter, const std::string& _value) {
|
||||||
//DRAIN_WARNING("set : " << _parameter << " " << _value);
|
//DRAIN_WARNING("set : " << _parameter << " " << _value);
|
||||||
if (_parameter == "type") {
|
if (_parameter == "config") {
|
||||||
if (_value == "none") {
|
m_config = ejson::Object::create(_value);
|
||||||
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;
|
|
||||||
}
|
|
||||||
configureBiQuad();
|
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") {
|
} else if (_parameter == "reset") {
|
||||||
m_history.clear();
|
for (int32_t iii=0; iii<m_biquads.size(); ++iii) {
|
||||||
m_history.resize(getOutputFormat().getMap().size());
|
for (int32_t jjj=0; jjj<m_biquads[iii].size(); ++jjj) {
|
||||||
|
m_biquads[iii][jjj].reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -146,194 +97,75 @@ std::string drain::Equalizer::getParameterProperty(const std::string& _parameter
|
|||||||
return "error";
|
return "error";
|
||||||
}
|
}
|
||||||
|
|
||||||
float drain::Equalizer::processFloat(float _sample, drain::BGHistory& _history) {
|
static drain::BiQuadFloat getBiquad(const std11::shared_ptr<const ejson::Object>& _object, float _frequency) {
|
||||||
float result;
|
drain::BiQuadFloat out;
|
||||||
// compute
|
// get type:
|
||||||
result = m_a[0] * _sample
|
std::string typeString = _object->getStringValue("type", "none");
|
||||||
+ m_a[1] * _history.m_x[0]
|
if (typeString == "direct-value") {
|
||||||
+ m_a[2] * _history.m_x[1]
|
double a0 = _object->getNumberValue("a0", 0.0);
|
||||||
- m_b[0] * _history.m_y[0]
|
double a1 = _object->getNumberValue("a1", 0.0);
|
||||||
- m_b[1] * _history.m_y[1];
|
double a2 = _object->getNumberValue("a2", 0.0);
|
||||||
//update history of X
|
double b0 = _object->getNumberValue("b0", 0.0);
|
||||||
_history.m_x[1] = _history.m_x[0];
|
double b1 = _object->getNumberValue("b1", 0.0);
|
||||||
_history.m_x[0] = _sample;
|
out.setBiquadCoef(a0, a1, a2, b0, b1);
|
||||||
//update history of Y
|
} else {
|
||||||
_history.m_y[1] = _history.m_y[0];
|
enum drain::filterType type;
|
||||||
_history.m_y[0] = result;
|
if (etk::from_string(type, typeString) == false) {
|
||||||
return result;
|
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() {
|
void drain::Equalizer::configureBiQuad() {
|
||||||
calcBiquad(m_type, m_frequencyCut, m_qualityFactor, m_gain);
|
m_biquads.clear();
|
||||||
return true;
|
m_biquads.resize(getOutputFormat().getMap().size());
|
||||||
}
|
if (m_config == nullptr) {
|
||||||
|
|
||||||
void drain::Equalizer::calcBiquad(enum drain::filterType _type, double _frequencyCut, double _qualityFactor, double _gain) {
|
|
||||||
m_type = _type;
|
|
||||||
m_frequencyCut = _frequencyCut;
|
|
||||||
m_qualityFactor = _qualityFactor;
|
|
||||||
m_gain = _gain;
|
|
||||||
|
|
||||||
if (getOutputFormat().getFrequency() < 1) {
|
|
||||||
m_a[0] = 1.0;
|
|
||||||
m_a[1] = 0.0;
|
|
||||||
m_a[2] = 0.0;
|
|
||||||
m_b[0] = 0.0;
|
|
||||||
m_b[1] = 0.0;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (m_frequencyCut > getOutputFormat().getFrequency()/2) {
|
// check for a global config:
|
||||||
m_frequencyCut = getOutputFormat().getFrequency()/2;
|
const std11::shared_ptr<const ejson::Array> global = m_config->getArray("global");
|
||||||
} else if (m_frequencyCut < 0) {
|
if (global != nullptr) {
|
||||||
m_frequencyCut = 0;
|
// only global configuration get all elements:
|
||||||
}
|
for (size_t kkk=0; kkk<global->size(); ++kkk) {
|
||||||
if (m_qualityFactor < 0.01) {
|
const std11::shared_ptr<const ejson::Object> tmpObject = global->getObject(kkk);
|
||||||
m_qualityFactor = 0.01;
|
if (tmpObject == nullptr) {
|
||||||
}
|
DRAIN_ERROR("Parse the configuration error : not a correct parameter:" << kkk);
|
||||||
switch (m_type) {
|
continue;
|
||||||
case filterType_lowPass:
|
|
||||||
case filterType_highPass:
|
|
||||||
case filterType_bandPass:
|
|
||||||
case filterType_notch:
|
|
||||||
// Quality : USE IT
|
|
||||||
// Gain : Not USE IT
|
|
||||||
break;
|
|
||||||
case filterType_peak:
|
|
||||||
// Quality : USE IT
|
|
||||||
// Gain : USE IT
|
|
||||||
break;
|
|
||||||
case filterType_lowShelf:
|
|
||||||
case filterType_highShelf:
|
|
||||||
// Quality : NOT USE IT
|
|
||||||
// Gain : USE IT
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
// Quality : USE IT
|
|
||||||
// Gain : USE IT
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
double norm;
|
|
||||||
double V = std::pow(10.0, std::abs(m_gain) / 20.0);
|
|
||||||
double K = std::tan(M_PI * m_frequencyCut / getOutputFormat().getFrequency());
|
|
||||||
switch (m_type) {
|
|
||||||
case filterType_none:
|
|
||||||
m_a[0] = 1.0;
|
|
||||||
m_a[1] = 0.0;
|
|
||||||
m_a[2] = 0.0;
|
|
||||||
m_b[0] = 0.0;
|
|
||||||
m_b[1] = 0.0;
|
|
||||||
break;
|
|
||||||
case filterType_lowPass:
|
|
||||||
norm = 1 / (1 + K / m_qualityFactor + K * K);
|
|
||||||
m_a[0] = K * K * norm;
|
|
||||||
m_a[1] = 2 * m_a[0];
|
|
||||||
m_a[2] = m_a[0];
|
|
||||||
m_b[0] = 2 * (K * K - 1) * norm;
|
|
||||||
m_b[1] = (1 - K / m_qualityFactor + K * K) * norm;
|
|
||||||
break;
|
|
||||||
case filterType_highPass:
|
|
||||||
norm = 1 / (1 + K / m_qualityFactor + K * K);
|
|
||||||
m_a[0] = 1 * norm;
|
|
||||||
m_a[1] = -2 * m_a[0];
|
|
||||||
m_a[2] = m_a[0];
|
|
||||||
m_b[0] = 2 * (K * K - 1) * norm;
|
|
||||||
m_b[1] = (1 - K / m_qualityFactor + K * K) * norm;
|
|
||||||
break;
|
|
||||||
case filterType_bandPass:
|
|
||||||
norm = 1 / (1 + K / m_qualityFactor + K * K);
|
|
||||||
m_a[0] = K / m_qualityFactor * norm;
|
|
||||||
m_a[1] = 0;
|
|
||||||
m_a[2] = -m_a[0];
|
|
||||||
m_b[0] = 2 * (K * K - 1) * norm;
|
|
||||||
m_b[1] = (1 - K / m_qualityFactor + K * K) * norm;
|
|
||||||
break;
|
|
||||||
case filterType_notch:
|
|
||||||
norm = 1 / (1 + K / m_qualityFactor + K * K);
|
|
||||||
m_a[0] = (1 + K * K) * norm;
|
|
||||||
m_a[1] = 2 * (K * K - 1) * norm;
|
|
||||||
m_a[2] = m_a[0];
|
|
||||||
m_b[0] = m_a[1];
|
|
||||||
m_b[1] = (1 - K / m_qualityFactor + K * K) * norm;
|
|
||||||
break;
|
|
||||||
case filterType_peak:
|
|
||||||
if (m_gain >= 0) {
|
|
||||||
norm = 1 / (1 + 1/m_qualityFactor * K + K * K);
|
|
||||||
m_a[0] = (1 + V/m_qualityFactor * K + K * K) * norm;
|
|
||||||
m_a[1] = 2 * (K * K - 1) * norm;
|
|
||||||
m_a[2] = (1 - V/m_qualityFactor * K + K * K) * norm;
|
|
||||||
m_b[0] = m_a[1];
|
|
||||||
m_b[1] = (1 - 1/m_qualityFactor * K + K * K) * norm;
|
|
||||||
} else {
|
|
||||||
norm = 1 / (1 + V/m_qualityFactor * K + K * K);
|
|
||||||
m_a[0] = (1 + 1/m_qualityFactor * K + K * K) * norm;
|
|
||||||
m_a[1] = 2 * (K * K - 1) * norm;
|
|
||||||
m_a[2] = (1 - 1/m_qualityFactor * K + K * K) * norm;
|
|
||||||
m_b[0] = m_a[1];
|
|
||||||
m_b[1] = (1 - V/m_qualityFactor * K + K * K) * norm;
|
|
||||||
}
|
}
|
||||||
break;
|
// declare biquad:
|
||||||
case filterType_lowShelf:
|
drain::BiQuadFloat biquad = getBiquad(tmpObject, getOutputFormat().getFrequency());
|
||||||
if (m_gain >= 0) {
|
// add this bequad for every Channel:
|
||||||
norm = 1 / (1 + M_SQRT2 * K + K * K);
|
for (size_t iii=0; iii<m_biquads.size(); ++iii) {
|
||||||
m_a[0] = (1 + std::sqrt(2*V) * K + V * K * K) * norm;
|
m_biquads[iii].push_back(biquad);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_variableRet = drain::filterType_none;
|
return;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
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 <drain/Algo.h>
|
||||||
#include <etk/memory.h>
|
#include <etk/memory.h>
|
||||||
|
#include <ejson/Object.h>
|
||||||
|
#include <drain/BiQuadFloat.h>
|
||||||
|
|
||||||
namespace drain {
|
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 {
|
class Equalizer : public Algo {
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
@ -53,42 +34,24 @@ namespace drain {
|
|||||||
size_t _inputNbChunk,
|
size_t _inputNbChunk,
|
||||||
void*& _output,
|
void*& _output,
|
||||||
size_t& _outputNbChunk);
|
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 bool setParameter(const std::string& _parameter, const std::string& _value);
|
||||||
virtual std::string getParameter(const std::string& _parameter) const;
|
virtual std::string getParameter(const std::string& _parameter) const;
|
||||||
virtual std::string getParameterProperty(const std::string& _parameter) const;
|
virtual std::string getParameterProperty(const std::string& _parameter) const;
|
||||||
|
|
||||||
protected:
|
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();
|
std::vector<std::vector<BiQuadFloat> > m_biquads;
|
||||||
public:
|
|
||||||
/**
|
/**
|
||||||
* @brief Configure the current biquad.
|
* @brief Configure biquad with the user spec.
|
||||||
*/
|
*/
|
||||||
void calcBiquad(enum drain::filterType _type, double _frequencyCut, double _qualityFactor, double _gain);
|
void configureBiQuad();
|
||||||
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;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ def create(target):
|
|||||||
'drain/debug.cpp',
|
'drain/debug.cpp',
|
||||||
'drain/airtalgo.cpp',
|
'drain/airtalgo.cpp',
|
||||||
'drain/Algo.cpp',
|
'drain/Algo.cpp',
|
||||||
|
'drain/BiQuadFloat.cpp',
|
||||||
'drain/ChannelReorder.cpp',
|
'drain/ChannelReorder.cpp',
|
||||||
'drain/CircularBuffer.cpp',
|
'drain/CircularBuffer.cpp',
|
||||||
'drain/EndPointCallback.cpp',
|
'drain/EndPointCallback.cpp',
|
||||||
@ -32,7 +33,7 @@ def create(target):
|
|||||||
|
|
||||||
# TODO: myModule.add_optional_module_depend('speexdsp', "HAVE_SPEEX_DSP_RESAMPLE")
|
# TODO: myModule.add_optional_module_depend('speexdsp', "HAVE_SPEEX_DSP_RESAMPLE")
|
||||||
myModule.compile_flags_CC("-DHAVE_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__))
|
myModule.add_export_path(tools.get_current_path(__file__))
|
||||||
|
|
||||||
# add the currrent module at the
|
# 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::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::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"));
|
m_displayer = std11::dynamic_pointer_cast<appl::widget::DisplayFrequency>(getSubObjectNamed("displayer"));
|
||||||
onCallbackStart();
|
onCallbackStart();
|
||||||
}
|
}
|
||||||
@ -179,7 +180,7 @@ void appl::Windows::onCallbackQuality(const std::string& _value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void appl::Windows::onCallbackQualitySlider(const float& _value) {
|
void appl::Windows::onCallbackQualitySlider(const float& _value) {
|
||||||
m_gain = _value;
|
m_quality = _value;
|
||||||
ewol::parameterSetOnObjectNamed("quality", "value", etk::to_string(_value));
|
ewol::parameterSetOnObjectNamed("quality", "value", etk::to_string(_value));
|
||||||
APPL_INFO("quality " << m_quality);
|
APPL_INFO("quality " << m_quality);
|
||||||
onCallbackStart();
|
onCallbackStart();
|
||||||
@ -209,126 +210,96 @@ void appl::Windows::onCallbackStart() {
|
|||||||
map.push_back(audio::channel_frontCenter);
|
map.push_back(audio::channel_frontCenter);
|
||||||
//drain::IOFormatInterface format(map, audio::format_int16, m_sampleRate);
|
//drain::IOFormatInterface format(map, audio::format_int16, m_sampleRate);
|
||||||
drain::IOFormatInterface format(map, audio::format_float, m_sampleRate);
|
drain::IOFormatInterface format(map, audio::format_float, m_sampleRate);
|
||||||
// create equalizer
|
// create biquad
|
||||||
std11::shared_ptr<drain::Equalizer> eq = drain::Equalizer::create();
|
drain::BiQuadFloat bq;
|
||||||
// configure input
|
|
||||||
eq->setInputFormat(format);
|
|
||||||
// configure output
|
|
||||||
eq->setOutputFormat(format);
|
|
||||||
// configure parameter
|
// configure parameter
|
||||||
eq->calcBiquad(m_type, m_cutFrequency, m_quality, m_gain);
|
bq.setBiquad(m_type, m_cutFrequency, m_quality, m_gain, m_sampleRate);
|
||||||
std::vector<std::pair<float,float> > theory = calculateTheory(m_sampleRate, eq->getCoef());
|
std::vector<std::pair<float,float> > theory = bq.calculateTheory(m_sampleRate);
|
||||||
m_displayer->clear();
|
m_displayer->clear();
|
||||||
m_displayer->setValue(theory);
|
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;
|
std::vector<std::pair<float,float> > pratic;
|
||||||
size_t len = 512;
|
size_t len = 512;
|
||||||
for (size_t iii=0; iii < len; iii++) {
|
for (size_t iii=0; iii < len; iii++) {
|
||||||
float freq = iii / (len - 1.0) * m_sampleRate / 2.0;
|
float freq = iii / (len - 1.0) * m_sampleRate / 2.0;
|
||||||
// To reset filter
|
// To reset filter
|
||||||
eq->setParameter("reset", "");
|
bq.reset();
|
||||||
double m_phase = 0;
|
double m_phase = 0;
|
||||||
double baseCycle = 2.0*M_PI/double(m_sampleRate) * double(freq);
|
double baseCycle = 2.0*M_PI/double(m_sampleRate) * double(freq);
|
||||||
float gain = 0;
|
float gain = 0;
|
||||||
if (format.getFormat() == audio::format_int16) {
|
std::vector<int16_t> data;
|
||||||
std::vector<int16_t> data;
|
// create sinus
|
||||||
// create sinus
|
data.resize(16000, 0);
|
||||||
data.resize(16000, 0);
|
for (int32_t iii=0; iii<data.size(); iii++) {
|
||||||
for (int32_t iii=0; iii<data.size(); iii++) {
|
data[iii] = cos(m_phase) * 32000;
|
||||||
data[iii] = cos(m_phase) * 32000;
|
m_phase += baseCycle;
|
||||||
m_phase += baseCycle;
|
if (m_phase >= 2*M_PI) {
|
||||||
if (m_phase >= 2*M_PI) {
|
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)));
|
pratic.push_back(std::make_pair<float, float>(float(freq),float(gain)));
|
||||||
}
|
}
|
||||||
m_displayer->setValue(pratic);
|
m_displayer->setValue(pratic);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void appl::Windows::onCallbackStartFloat() {
|
||||||
|
APPL_INFO("start ");
|
||||||
std::vector<std::pair<float,float> > appl::Windows::calculateTheory(double _sampleRate, std::vector<float> _coef) {
|
// create biquad
|
||||||
std::vector<std::pair<float,float> > out;
|
drain::BiQuadFloat bq;
|
||||||
double norm;
|
// configure parameter
|
||||||
float m_a[3];
|
bq.setBiquad(m_type, m_cutFrequency, m_quality, m_gain, m_sampleRate);
|
||||||
float m_b[2];
|
std::vector<std::pair<float,float> > pratic;
|
||||||
|
|
||||||
m_a[0] = _coef[0];
|
|
||||||
m_a[1] = _coef[1];
|
|
||||||
m_a[2] = _coef[2];
|
|
||||||
m_b[0] = _coef[3];
|
|
||||||
m_b[1] = _coef[4];
|
|
||||||
|
|
||||||
bool buildLinear = true;
|
|
||||||
|
|
||||||
size_t len = 512;
|
size_t len = 512;
|
||||||
for (size_t iii=0; iii < len; iii++) {
|
for (size_t iii=0; iii < len; iii++) {
|
||||||
double w;
|
float freq = iii / (len - 1.0) * m_sampleRate / 2.0;
|
||||||
if (buildLinear == true) {
|
// To reset filter
|
||||||
// 0 to pi, linear scale
|
bq.reset();
|
||||||
w = iii / (len - 1.0) * M_PI;
|
double m_phase = 0;
|
||||||
} else {
|
double baseCycle = 2.0*M_PI/double(m_sampleRate) * double(freq);
|
||||||
// 0.001 to 1, times pi, log scale
|
float gain = 0;
|
||||||
w = std::exp(std::log(1.0 / 0.001) * iii / (len - 1.0)) * 0.001 * M_PI;
|
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;
|
//RIVER_SAVE_FILE_MACRO(float,"aaa_test_INPUT_F.raw",&data[0],data.size());
|
||||||
double phi = std::pow(std::sin(w/2.0), 2.0);
|
bq.processFloat(&data[0], &data[0], data.size(), 1, 1);
|
||||||
double y = std::log( std::pow(m_a[0]+m_a[1]+m_a[2], 2.0)
|
//RIVER_SAVE_FILE_MACRO(float,"aaa_test_OUTPUT_F.raw",&data[0],data.size());
|
||||||
- 4.0*(m_a[0]*m_a[1] + 4.0*m_a[0]*m_a[2] + m_a[1]*m_a[2])*phi
|
float value = 0;
|
||||||
+ 16.0*m_a[0]*m_a[2]*phi*phi)
|
for (size_t iii=200; iii<data.size()-200; ++iii) {
|
||||||
- std::log( std::pow(1.0+m_b[0]+m_b[1], 2.0)
|
value = std::max(value, data[iii]);
|
||||||
- 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;
|
|
||||||
}
|
}
|
||||||
|
gain = 20.0 * std::log10(double(value)/1.0);
|
||||||
APPL_DEBUG("theory = " << freq << " power=" << y);
|
APPL_VERBOSE("LEVEL " << iii << " out = " << value << " % : " << gain);
|
||||||
out.push_back(std::make_pair<float,float>(freq, y));
|
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 onCallbackQuality(const std::string& _value);
|
||||||
void onCallbackQualitySlider(const float& _value);
|
void onCallbackQualitySlider(const float& _value);
|
||||||
void onCallbackStart();
|
void onCallbackStart();
|
||||||
|
void onCallbackStart16();
|
||||||
|
void onCallbackStartFloat();
|
||||||
protected:
|
protected:
|
||||||
int32_t m_sampleRate;
|
int32_t m_sampleRate;
|
||||||
std::vector<int32_t> m_listSampleRate;
|
std::vector<int32_t> m_listSampleRate;
|
||||||
@ -44,7 +46,6 @@ namespace appl {
|
|||||||
float m_cutFrequency;
|
float m_cutFrequency;
|
||||||
float m_gain;
|
float m_gain;
|
||||||
float m_quality;
|
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
|
// remove previous data
|
||||||
m_draw.clear();
|
m_draw.clear();
|
||||||
m_text.clear();
|
m_text.clear();
|
||||||
|
|
||||||
m_borderSize = m_size * 0.05;
|
m_borderSize = m_size * 0.05;
|
||||||
|
|
||||||
|
|
||||||
// set background
|
// set background
|
||||||
m_draw.setColor(etk::color::black);
|
m_draw.setColor(etk::color::black);
|
||||||
m_draw.setPos(vec2(0,0));
|
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(vec2(m_borderSize.x(), plop.y()));
|
||||||
m_draw.lineTo(m_size-m_borderSize);
|
m_draw.lineTo(m_size-m_borderSize);
|
||||||
m_draw.lineTo(vec2(plop.x(), m_borderSize.y()));
|
m_draw.lineTo(vec2(plop.x(), m_borderSize.y()));
|
||||||
|
|
||||||
m_draw.lineTo(m_borderSize);
|
m_draw.lineTo(m_borderSize);
|
||||||
|
|
||||||
if (m_data.size() == 0) {
|
if (m_data.size() == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -91,15 +86,27 @@ void appl::widget::DisplayFrequency::onRegenerateDisplay() {
|
|||||||
m_gainMin = 9999999999.9;
|
m_gainMin = 9999999999.9;
|
||||||
m_frequencyMin = 99999999.0;
|
m_frequencyMin = 99999999.0;
|
||||||
m_frequencyMax = -99999999.0;
|
m_frequencyMax = -99999999.0;
|
||||||
|
bool displayLog = true;
|
||||||
for (size_t kkk=0; kkk<m_data.size(); kkk++) {
|
for (size_t kkk=0; kkk<m_data.size(); kkk++) {
|
||||||
for (size_t iii=0; iii<m_data[kkk].size(); ++iii) {
|
for (size_t iii=0; iii<m_data[kkk].size(); ++iii) {
|
||||||
if (std::abs(m_data[kkk][iii].second) != std::numeric_limits<float>::infinity()) {
|
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_gainMax = std::max(m_gainMax, m_data[kkk][iii].second);
|
||||||
m_gainMin = std::min(m_gainMin, 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()) {
|
if (displayLog == false) {
|
||||||
m_frequencyMax = std::max(m_frequencyMax, m_data[kkk][iii].first);
|
if (std::abs(m_data[kkk][iii].first) != std::numeric_limits<float>::infinity()) {
|
||||||
m_frequencyMin = std::min(m_frequencyMin, m_data[kkk][iii].first);
|
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 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);
|
float ratioY = (m_size.y()-m_borderSize.y()*2.0) / (m_gainMax - m_gainMin);
|
||||||
m_draw.setPos( m_borderSize
|
if (displayLog == false) {
|
||||||
+ vec2(ratioX*(m_data[kkk][0].first - m_frequencyMin),
|
m_draw.setPos( m_borderSize
|
||||||
ratioY*(m_data[kkk][0].second - m_gainMin)));
|
+ vec2(ratioX*(m_data[kkk][0].first - m_frequencyMin),
|
||||||
float baseX = 0;
|
ratioY*(m_data[kkk][0].second - m_gainMin)));
|
||||||
for (size_t iii=1; iii<m_data[kkk].size(); ++iii) {
|
float baseX = 0;
|
||||||
m_draw.lineTo( m_borderSize
|
for (size_t iii=1; iii<m_data[kkk].size(); ++iii) {
|
||||||
+ vec2(ratioX*(m_data[kkk][iii].first - m_frequencyMin),
|
m_draw.lineTo( m_borderSize
|
||||||
ratioY*(m_data[kkk][iii].second - m_gainMin)));
|
+ 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);
|
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.setPos(vec2(m_size.x()-m_borderSize.x()-size.x(), m_borderSize.y()-size.y()));
|
||||||
m_text.print(textToDisplay);
|
m_text.print(textToDisplay);
|
||||||
|
|
||||||
m_text.setDefaultColorFg(etk::color::blue);
|
|
||||||
textToDisplay = etk::to_string(m_gainMin) + " dB";
|
textToDisplay = etk::to_string(m_gainMin) + " dB";
|
||||||
size = m_text.calculateSize(textToDisplay);
|
size = m_text.calculateSize(textToDisplay);
|
||||||
m_text.setPos(vec2(m_borderSize.x(), m_borderSize.y()));
|
m_text.setPos(vec2(m_borderSize.x(), m_borderSize.y()));
|
||||||
|
@ -64,8 +64,11 @@
|
|||||||
</sizer>
|
</sizer>
|
||||||
<slider expand="true" name="quality-slider" value="0.707" min="0.001" max="50" step="0.001"/>
|
<slider expand="true" name="quality-slider" value="0.707" min="0.001" max="50" step="0.001"/>
|
||||||
</sizer>
|
</sizer>
|
||||||
<button name="display">
|
<button name="display16">
|
||||||
<label>Display</label>
|
<label>test int16_t</label>
|
||||||
|
</button>
|
||||||
|
<button name="displayFloat">
|
||||||
|
<label>test float</label>
|
||||||
</button>
|
</button>
|
||||||
<Spacer expand="true,true"/>
|
<Spacer expand="true,true"/>
|
||||||
</sizer>
|
</sizer>
|
||||||
|
Loading…
Reference in New Issue
Block a user