[DEV] start to work

This commit is contained in:
Edouard DUPIN 2015-03-27 21:40:54 +01:00
parent abce0fc900
commit cdfb632a9e
7 changed files with 451 additions and 193 deletions

View File

@ -9,6 +9,7 @@
#include <drain/Algo.h>
// see http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt
// see http://www.earlevel.com/main/2013/10/13/biquad-calculator-v2/
drain::Equalizer::Equalizer() {
@ -18,17 +19,18 @@ void drain::Equalizer::init() {
drain::Algo::init();
drain::Algo::m_type = "Equalizer";
m_supportedFormat.push_back(audio::format_int16);
m_supportedFormat.push_back(audio::format_float);
m_type = drain::filterType_none;
m_gain = 0;
m_frequency = 1000;
m_bandWidth = 200;
m_gain = 6;
m_frequencyCut = 1000;
m_qualityFactor = 0.707;
configureBiQuad();
// reset coefficients
m_b[0] = 1.0;
m_b[1] = 0.0;
m_b[2] = 0.0;
m_a[0] = 0.0;
m_a[0] = 1.0;
m_a[1] = 0.0;
m_a[2] = 0.0;
m_b[0] = 0.0;
m_b[1] = 0.0;
}
std11::shared_ptr<drain::Equalizer> drain::Equalizer::create() {
@ -58,46 +60,58 @@ bool drain::Equalizer::process(std11::chrono::system_clock::time_point& _time,
if (_input == nullptr) {
return false;
}
for (size_t jjj=0; jjj<getOutputFormat().getMap().size(); ++jjj) {
// get pointer on data:
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();
if (getOutputFormat().getFormat() == audio::format_float) {
for (size_t jjj=0; jjj<getOutputFormat().getMap().size(); ++jjj) {
// get pointer on data:
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();
}
}
} else if (getOutputFormat().getFormat() == audio::format_int16) {
for (size_t jjj=0; jjj<getOutputFormat().getMap().size(); ++jjj) {
// get pointer on data:
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();
}
}
}
return true;
}
bool drain::Equalizer::setParameter(const std::string& _parameter, const std::string& _value) {
//DRAIN_WARNING("set : " << _parameter << " " << _value);
if (_parameter == "type") {
if (_value == "none") {
m_type = drain::filterType_none;
} else if (_value == "LPF") {
m_type = drain::filterType_LPF;
m_type = drain::filterType_lowPass;
} else if (_value == "HPF") {
m_type = drain::filterType_HPF;
m_type = drain::filterType_highPass;
} else if (_value == "BPF") {
m_type = drain::filterType_BPF;
m_type = drain::filterType_bandPass;
} else if (_value == "NOTCH") {
m_type = drain::filterType_NOTCH;
} else if (_value == "APF") {
m_type = drain::filterType_APF;
m_type = drain::filterType_notch;
} else if (_value == "PeakingEQ") {
m_type = drain::filterType_PeakingEQ;
m_type = drain::filterType_peak;
} else if (_value == "LSH") {
m_type = drain::filterType_LSH;
m_type = drain::filterType_lowShelf;
} else if (_value == "HSH") {
m_type = drain::filterType_HSH;
} else if (_value == "EQU"){
m_type = drain::filterType_EQU;
m_type = drain::filterType_highShelf;
} else {
DRAIN_ERROR("Can not set equalizer type : " << _value);
return false;
@ -105,17 +119,21 @@ bool drain::Equalizer::setParameter(const std::string& _parameter, const std::st
configureBiQuad();
return true;
} else if (_parameter == "gain") {
m_gain = etk::string_to_int32_t(_value);
m_gain = etk::string_to_double(_value);
configureBiQuad();
return true;
} else if (_parameter == "frequency") {
m_frequency = etk::string_to_int32_t(_value);
m_frequencyCut = etk::string_to_double(_value);
configureBiQuad();
return true;
} else if (_parameter == "band-width") {
m_bandWidth = etk::string_to_int32_t(_value);
} else if (_parameter == "quality") {
m_qualityFactor = etk::string_to_double(_value);
configureBiQuad();
return true;
} else if (_parameter == "reset") {
m_history.clear();
m_history.resize(getOutputFormat().getMap().size());
return true;
}
return false;
}
@ -131,116 +149,162 @@ std::string drain::Equalizer::getParameterProperty(const std::string& _parameter
float drain::Equalizer::processFloat(float _sample, drain::BGHistory& _history) {
float result;
// compute
result = m_b[0] * _sample
+ m_b[1] * _history.m_x[0]
+ m_b[2] * _history.m_x[1]
- m_a[0] * _history.m_y[0]
- m_a[1] * _history.m_y[1];
result = m_a[0] * _sample
+ m_a[1] * _history.m_x[0]
+ m_a[2] * _history.m_x[1]
- m_b[0] * _history.m_y[0]
- m_b[1] * _history.m_y[1];
//update history of X
_history.m_x[0] = _history.m_x[1];
_history.m_x[1] = _sample;
_history.m_x[1] = _history.m_x[0];
_history.m_x[0] = _sample;
//update history of Y
_history.m_y[0] = _history.m_y[1];
_history.m_y[1] = result;
_history.m_y[1] = _history.m_y[0];
_history.m_y[0] = result;
return result;
}
bool drain::Equalizer::configureBiQuad() {
// reset biQuad.
m_b[0] = 1.0;
m_b[1] = 0.0;
m_b[2] = 0.0;
m_a[0] = 0.0;
m_a[1] = 0.0;
if (m_type == filterType_none) {
return true;
}
double a0, a1, a2, b0, b1, b2;
/* setup variables */
double A = std::pow(10, m_gain /40); // used for peaking and shelving EQ filters only
double w0 = 2.0 * M_PI * double(m_frequency) / double(getOutputFormat().getFrequency());
// 2*sqrt(A)*alpha = sin(w0) * sqrt( (A^2 + 1)*(1/S - 1) + 2*A )
// is a handy intermediate variable for shelving EQ filters.
double alpha = std::sin(w0) * std::sqrt((A*A+1.0)*(1.0/m_bandWidth - 1.0) + 2*A);
alpha /= 2.0*std::sqrt(A);
switch (m_type) {
case drain::filterType_LPF:
b0 = (1.0 - std::cos(w0)) * 0.5;
b1 = 1.0 - std::cos(w0);
b2 = (1.0 - std::cos(w0)) * 0.5;
a0 = 1.0 + alpha;
a1 = -2.0 * std::cos(w0);
a2 = 1.0 - alpha;
break;
case drain::filterType_HPF:
b0 = (1.0 + std::cos(w0)) * 0.5;
b1 = -(1.0 + std::cos(w0));
b2 = (1.0 + std::cos(w0)) * 0.5;
a0 = 1.0 + alpha;
a1 = -2.0 * std::cos(w0);
a2 = 1.0 - alpha;
break;
case drain::filterType_BPF: // constant 0dB peak gain
b0 = alpha;
b1 = 0.0;
b2 = -alpha;
a0 = 1.0 + alpha;
a1 = -2.0 * std::cos(w0);
a2 = 1.0 - alpha;
break;
case drain::filterType_NOTCH:
b0 = 1.0;
b1 = -2.0 * std::cos(w0);
b2 = 1.0;
a0 = 1.0 + alpha;
a1 = -2.0 * std::cos(w0);
a2 = 1.0 - alpha;
break;
case drain::filterType_APF:
b0 = 1.0 - alpha;
b1 = -2.0 * std::cos(w0);
b2 = 1.0 + alpha;
a0 = 1.0 + alpha;
a1 = -2.0 * std::cos(w0);
a2 = 1.0 - alpha;
break;
case drain::filterType_PeakingEQ:
b0 = 1.0 + (alpha * A);
b1 = -2.0 * std::cos(w0);
b2 = 1.0 - (alpha * A);
a0 = 1.0 + (alpha /A);
a1 = -2.0 * std::cos(w0);
a2 = 1.0 - (alpha /A);
break;
case drain::filterType_LSH:
b0 = A*( (A+1.0) - (A-1.0)*std::cos(w0) + 2.0*std::sqrt(A)*alpha );
b1 = 2.0*A*( (A-1.0) - (A+1.0)*std::cos(w0) );
b2 = A*( (A+1.0) - (A-1.0)*std::cos(w0) - 2.0*std::sqrt(A)*alpha );
a0 = (A+1.0) + (A-1.0)*std::cos(w0) + 2.0*std::sqrt(A)*alpha;
a1 = -2.0*( (A-1.0) + (A+1.0)*std::cos(w0) );
a2 = (A+1.0) + (A-1.0)*std::cos(w0) - 2.0*std::sqrt(A)*alpha;
break;
case drain::filterType_HSH:
b0 = A*( (A+1.0) + (A-1.0) * std::cos(w0) + 2.0*std::sqrt(A)*alpha );
b1 = -2.0*A*( (A-1.0) + (A+1.0) * std::cos(w0) );
b2 = A*( (A+1.0) + (A-1.0) * std::cos(w0) - 2.0*std::sqrt(A)*alpha );
a0 = (A+1.0) - (A-1.0) * std::cos(w0) + 2.0*std::sqrt(A)*alpha;
a1 = 2.0*( (A-1.0) - (A+1.0) * std::cos(w0) );
a2 = (A+1.0) - (A-1.0) * std::cos(w0) - 2.0*std::sqrt(A)*alpha;
break;
default:
DRAIN_CRITICAL("Impossible case ...");
return false;
}
// precalculate coefficients:
m_b[0] = b0 /a0;
m_b[1] = b1 /a0;
m_b[2] = b2 /a0;
m_a[0] = a1 /a0;
m_a[1] = a2 /a0;
calcBiquad(m_type, m_frequencyCut, m_qualityFactor, m_gain);
return true;
}
void drain::Equalizer::calcBiquad(enum drain::filterType _type, double _frequencyCut, double _qualityFactor, double _gain) {
m_type = _type;
m_frequencyCut = _frequencyCut;
m_qualityFactor = _qualityFactor;
m_gain = _gain;
if (getOutputFormat().getFrequency() < 1) {
m_a[0] = 1.0;
m_a[1] = 0.0;
m_a[2] = 0.0;
m_b[0] = 0.0;
m_b[1] = 0.0;
return;
}
if (m_frequencyCut > getOutputFormat().getFrequency()/2) {
m_frequencyCut = getOutputFormat().getFrequency()/2;
} else if (m_frequencyCut < 0) {
m_frequencyCut = 0;
}
if (m_qualityFactor < 0.01) {
m_qualityFactor = 0.01;
}
switch (m_type) {
case filterType_lowPass:
case filterType_highPass:
case filterType_bandPass:
case filterType_notch:
// Quality : USE IT
// Gain : Not USE IT
break;
case filterType_peak:
// Quality : USE IT
// Gain : USE IT
break;
case filterType_lowShelf:
case filterType_highShelf:
// Quality : NOT USE IT
// Gain : USE IT
break;
default:
// Quality : USE IT
// Gain : USE IT
break;
}
double norm;
double V = std::pow(10.0, std::abs(m_gain) / 20.0);
double K = std::tan(M_PI * m_frequencyCut / getOutputFormat().getFrequency());
switch (m_type) {
case filterType_none:
m_a[0] = 1.0;
m_a[1] = 0.0;
m_a[2] = 0.0;
m_b[0] = 0.0;
m_b[1] = 0.0;
break;
case filterType_lowPass:
norm = 1 / (1 + K / m_qualityFactor + K * K);
m_a[0] = K * K * norm;
m_a[1] = 2 * m_a[0];
m_a[2] = m_a[0];
m_b[0] = 2 * (K * K - 1) * norm;
m_b[1] = (1 - K / m_qualityFactor + K * K) * norm;
break;
case filterType_highPass:
norm = 1 / (1 + K / m_qualityFactor + K * K);
m_a[0] = 1 * norm;
m_a[1] = -2 * m_a[0];
m_a[2] = m_a[0];
m_b[0] = 2 * (K * K - 1) * norm;
m_b[1] = (1 - K / m_qualityFactor + K * K) * norm;
break;
case filterType_bandPass:
norm = 1 / (1 + K / m_qualityFactor + K * K);
m_a[0] = K / m_qualityFactor * norm;
m_a[1] = 0;
m_a[2] = -m_a[0];
m_b[0] = 2 * (K * K - 1) * norm;
m_b[1] = (1 - K / m_qualityFactor + K * K) * norm;
break;
case filterType_notch:
norm = 1 / (1 + K / m_qualityFactor + K * K);
m_a[0] = (1 + K * K) * norm;
m_a[1] = 2 * (K * K - 1) * norm;
m_a[2] = m_a[0];
m_b[0] = m_a[1];
m_b[1] = (1 - K / m_qualityFactor + K * K) * norm;
break;
case filterType_peak:
if (m_gain >= 0) {
norm = 1 / (1 + 1/m_qualityFactor * K + K * K);
m_a[0] = (1 + V/m_qualityFactor * K + K * K) * norm;
m_a[1] = 2 * (K * K - 1) * norm;
m_a[2] = (1 - V/m_qualityFactor * K + K * K) * norm;
m_b[0] = m_a[1];
m_b[1] = (1 - 1/m_qualityFactor * K + K * K) * norm;
} else {
norm = 1 / (1 + V/m_qualityFactor * K + K * K);
m_a[0] = (1 + 1/m_qualityFactor * K + K * K) * norm;
m_a[1] = 2 * (K * K - 1) * norm;
m_a[2] = (1 - 1/m_qualityFactor * K + K * K) * norm;
m_b[0] = m_a[1];
m_b[1] = (1 - V/m_qualityFactor * K + K * K) * norm;
}
break;
case filterType_lowShelf:
if (m_gain >= 0) {
norm = 1 / (1 + M_SQRT2 * K + K * K);
m_a[0] = (1 + std::sqrt(2*V) * K + V * K * K) * norm;
m_a[1] = 2 * (V * K * K - 1) * norm;
m_a[2] = (1 - std::sqrt(2*V) * K + V * K * K) * norm;
m_b[0] = 2 * (K * K - 1) * norm;
m_b[1] = (1 - M_SQRT2 * K + K * K) * norm;
} else {
norm = 1 / (1 + std::sqrt(2*V) * K + V * K * K);
m_a[0] = (1 + M_SQRT2 * K + K * K) * norm;
m_a[1] = 2 * (K * K - 1) * norm;
m_a[2] = (1 - M_SQRT2 * K + K * K) * norm;
m_b[0] = 2 * (V * K * K - 1) * norm;
m_b[1] = (1 - std::sqrt(2*V) * K + V * K * K) * norm;
}
break;
case filterType_highShelf:
if (m_gain >= 0) {
norm = 1 / (1 + M_SQRT2 * K + K * K);
m_a[0] = (V + std::sqrt(2*V) * K + K * K) * norm;
m_a[1] = 2 * (K * K - V) * norm;
m_a[2] = (V - std::sqrt(2*V) * K + K * K) * norm;
m_b[0] = 2 * (K * K - 1) * norm;
m_b[1] = (1 - M_SQRT2 * K + K * K) * norm;
} else {
norm = 1 / (V + std::sqrt(2*V) * K + K * K);
m_a[0] = (1 + M_SQRT2 * K + K * K) * norm;
m_a[1] = 2 * (K * K - 1) * norm;
m_a[2] = (1 - M_SQRT2 * K + K * K) * norm;
m_b[0] = 2 * (K * K - V) * norm;
m_b[1] = (V - std::sqrt(2*V) * K + K * K) * norm;
}
break;
}
}

View File

@ -12,16 +12,14 @@
namespace drain {
enum filterType {
filterType_none, //!< no filter
filterType_LPF, //!< low pass filter
filterType_HPF, //!< High pass filter
filterType_BPF, //!< band pass filter
filterType_NOTCH, //!< Notch Filter
filterType_APF, //!< All pass Filter
filterType_PeakingEQ, //!< Peaking band EQ filter
filterType_LSH, //!< Low shelf filter
filterType_HSH, //!< High shelf filter
filterType_EQU //!< Equalizer
filterType_none, //!< no filter (pass threw...)
filterType_lowPass, //!< low pass filter
filterType_highPass, //!< High pass filter
filterType_bandPass, //!< band pass filter
filterType_notch, //!< Notch Filter
filterType_peak, //!< Peaking band EQ filter
filterType_lowShelf, //!< Low shelf filter
filterType_highShelf, //!< High shelf filter
};
class BGHistory {
public:
@ -64,18 +62,33 @@ namespace drain {
//-----------------------------------------
// START parameters:
enum filterType m_type; //!< current filter type.
float m_gain; //!< Gain to apply in dB
float m_frequency; //!< Frequency to apply filter
float m_bandWidth; //!< Band With to apply filter
float m_gain; //!< Gain to apply in dB ??? limit : -30, +30
float m_frequencyCut; //!< Frequency to apply filter ???? LIMIT : [0..sampleRate/2]
// good value of 0.707 ==> permit to not ower gain
float m_qualityFactor; //!< Quality factor ??? limit [0.01 .. 10]
// END parameters:
//-----------------------------------------
float m_a[2]; //!< A bi-Quad coef
float m_b[3]; //!< B bi-Quad coef
float m_a[3]; //!< A bi-Quad coef
float m_b[2]; //!< B bi-Quad coef
std::vector<BGHistory> m_history;
/**
* @brief Configure the current biquad.
*/
bool configureBiQuad();
public:
/**
* @brief Configure the current biquad.
*/
void calcBiquad(enum drain::filterType _type, double _frequencyCut, double _qualityFactor, double _gain);
std::vector<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;
}
};
};

View File

@ -18,10 +18,10 @@
appl::Windows::Windows() :
m_sampleRate(48000),
m_type(drain::filterType::filterType_LPF),
m_cutFrequency(2000),
m_gain(2),
m_bandWidth(200) {
m_type(drain::filterType::filterType_lowPass),
m_cutFrequency(8000.0),
m_gain(6.0),
m_bandWidth(0.1) {
addObjectType("appl::Windows");
}
@ -39,6 +39,7 @@ void appl::Windows::init() {
subBind(ewol::widget::Entry, "frequency", signalModify, shared_from_this(), &appl::Windows::onCallbackFrequency);
subBind(ewol::widget::Entry, "band-width", signalModify, shared_from_this(), &appl::Windows::onCallbackBandWidth);
subBind(ewol::widget::Button, "display", signalPressed, shared_from_this(), &appl::Windows::onCallbackStart);
m_displayer = std11::dynamic_pointer_cast<appl::widget::DisplayFrequency>(getSubObjectNamed("displayer"));
}
void appl::Windows::onCallbackSampleRate(const std::string& _value) {
@ -63,7 +64,7 @@ void appl::Windows::onCallbackType(const std::string& _value) {
std::vector<std::string> list;
list.push_back("HPF");
list.push_back("LPF");
if (etk::isIn(etk::string_to_int32_t(_value), list) == true) {
if (etk::isIn(_value, list) == true) {
ewol::parameterSetOnObjectNamed("type-valid", "color", "green");
} else {
ewol::parameterSetOnObjectNamed("type-valid", "color", "red");
@ -82,30 +83,161 @@ void appl::Windows::onCallbackBandWidth(const std::string& _value) {
APPL_INFO("BandWidth " << _value);
}
#include <river/debug.h>
void appl::Windows::onCallbackStart() {
APPL_INFO("start ");
m_data.clear();
int32_t iii = 200;
while (iii < m_sampleRate/2) {
APPl_INFO("TEST : " << iii);
// create equalizer
std11::shared_ptr<drain::Equalizer> eq = drain::Equalizer::create();
// configure parameter
eq->setParameter("type", "LPF");
eq->setParameter("gain", etk::to_string(m_gain));
eq->setParameter("frequency", etk::to_string(m_cutFrequency));
eq->setParameter("band-width", etk::to_string(m_bandWidth));
// configure input
// configure outpur
int32_t iii = 10;
std::vector<audio::channel> map;
map.push_back(audio::channel_frontCenter);
drain::IOFormatInterface format(map, audio::format_int16, m_sampleRate);
// create equalizer
std11::shared_ptr<drain::Equalizer> eq = drain::Equalizer::create();
// configure input
eq->setInputFormat(format);
// configure output
eq->setOutputFormat(format);
// configure parameter
/*
eq->setParameter("type", "APF");
eq->setParameter("gain", etk::to_string(m_gain));
eq->setParameter("frequency", etk::to_string(m_cutFrequency));
eq->setParameter("band-width", etk::to_string(m_bandWidth));
*/
//eq->calcBiquad(drain::filterType_none, m_cutFrequency, 0.707, m_gain);
eq->calcBiquad(drain::filterType_lowPass, m_cutFrequency, 0.707, m_gain);
//eq->calcBiquad(drain::filterType_highPass, m_cutFrequency, 0.707, m_gain);
std::vector<std::pair<float,float> > theory = calculateTheory(48000, eq->getCoef());
m_displayer->clear();
m_displayer->setValue(theory);
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;
//}
double freq = iii / (len - 1.0) * 48000 / 2.0;
//while (iii < m_sampleRate/2) {
std::vector<int16_t> data;
//APPL_INFO("TEST : " << iii);
// To reset filter
eq->setParameter("reset", "");
// create sinus
data.resize(4096, 0);
double m_phase = 0;
double baseCycle = 2.0*M_PI/double(m_sampleRate) * double(freq);
for (int32_t iii=0; iii<data.size(); iii++) {
data[iii] = cos(m_phase) * 30000;
m_phase += baseCycle;
if (m_phase >= 2*M_PI) {
m_phase -= 2*M_PI;
}
}
// process
iii += 200;
int16_t* output = nullptr;
void* outputVoid = nullptr;
size_t outputNbChunk = 0;
std11::chrono::system_clock::time_point time;
RIVER_SAVE_FILE_MACRO(int16_t,"aaa_test_INPUT.raw",&data[0],data.size());
eq->process(time, &data[0], data.size(), outputVoid, outputNbChunk);
output = static_cast<int16_t*>(outputVoid);
RIVER_SAVE_FILE_MACRO(int16_t,"aaa_test_OUTPUT.raw",output,outputNbChunk);
int16_t value = 0;
for (size_t iii=20; iii<outputNbChunk-20; ++iii) {
value = std::max(value, output[iii]);
}
float gain = 20.0 * std::log10(double(value)/30000.0);
APPL_INFO("LEVEL " << iii << " out = " << value << " % : " << gain);
pratic.push_back(std::make_pair<float, float>(iii,float(value)/30000.0f));
iii += 10;
}
/*
while (iii < m_sampleRate/2) {
std::vector<float> data;
//APPL_INFO("TEST : " << iii);
// To reset filter
eq->setParameter("reset", "");
// create sinus
data.resize(4096, 0);
double m_phase = 0;
double baseCycle = 2.0*M_PI/double(m_sampleRate) * double(iii);
for (int32_t iii=0; iii<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(float,"aaa_test_INPUT_F.raw",&data[0],data.size());
eq->process(time, &data[0], data.size(), outputVoid, outputNbChunk);
output = static_cast<float*>(outputVoid);
RIVER_SAVE_FILE_MACRO(float,"aaa_test_OUTPUT_F.raw",output,outputNbChunk);
double value = 0;
for (size_t iii=0; iii<outputNbChunk; ++iii) {
value += std::abs(output[iii]);
}
value /= (outputNbChunk);
float gain = 20.0 * std::log10(float(value));
APPL_INFO("LEVEL " << iii << " out = " << value << " % : " << gain);
pratic.push_back(std::make_pair<float, float>(iii,float(value)));
iii += 10;
}
*/
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;
size_t len = 512;
for (size_t iii=0; iii < len; iii++) {
double w;
if (buildLinear == true) {
// 0 to pi, linear scale
w = iii / (len - 1.0) * M_PI;
} else {
// 0.001 to 1, times pi, log scale
w = std::exp(std::log(1.0 / 0.001) * iii / (len - 1.0)) * 0.001 * M_PI;
}
double phi = std::pow(std::sin(w/2.0), 2.0);
double y = std::log( std::pow(m_a[0]+m_a[1]+m_a[2], 2.0)
- 4.0*(m_a[0]*m_a[1] + 4.0*m_a[0]*m_a[2] + m_a[1]*m_a[2])*phi
+ 16.0*m_a[0]*m_a[2]*phi*phi)
- std::log( std::pow(1.0+m_b[0]+m_b[1], 2.0)
- 4.0*(m_b[0] + 4.0*m_b[1] + m_b[0]*m_b[1])*phi
+ 16.0*m_b[1]*phi*phi);
y = y * 10.0 / M_LN10;
if (y <= -200) {
y = -200.0;
}
APPL_INFO("theory = " << iii / (len - 1.0) * _sampleRate / 2.0 << " power=" << y);
out.push_back(std::make_pair<float,float>(iii / (len - 1.0) * _sampleRate / 2.0, y + 0.5));
}
return out;
}

View File

@ -13,6 +13,7 @@
#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 {
@ -23,6 +24,7 @@ namespace appl {
DECLARE_FACTORY(Windows);
protected:
std::shared_ptr<ewol::widget::Composer> m_gui;
std::shared_ptr<appl::widget::DisplayFrequency> m_displayer;
void onCallbackSampleRate(const std::string& _value);
void onCallbackType(const std::string& _value);
void onCallbackGain(const std::string& _value);
@ -35,7 +37,7 @@ namespace appl {
float m_cutFrequency;
float m_gain;
float m_bandWidth;
std::vector<std::pair<float,float> > m_data;
std::vector<std::pair<float,float> > calculateTheory(double _sampleRate, std::vector<float> _coef);
};
};

View File

@ -34,7 +34,7 @@ appl::widget::DisplayFrequency::~DisplayFrequency() {
void appl::widget::DisplayFrequency::setValue(const std::vector<std::pair<float,float> >& _data) {
m_data = _data;
m_data.push_back(_data);
markToRedraw();
}
@ -62,25 +62,67 @@ void appl::widget::DisplayFrequency::onRegenerateDisplay() {
}
// remove previous data
m_draw.clear();
m_borderSize = m_size * 0.05;
// set background
m_draw.setColor(etk::color::black);
m_draw.setPos(vec2(0,0));
m_draw.rectangleWidth(m_size);
m_draw.setColor(etk::color::gray);
m_draw.setPos(m_borderSize);
m_draw.setThickness(1);
vec2 plop = m_size-m_borderSize;
m_draw.lineTo(vec2(m_borderSize.x(), plop.y()));
m_draw.lineTo(m_size-m_borderSize);
m_draw.lineTo(vec2(plop.x(), m_borderSize.y()));
m_draw.lineTo(m_borderSize);
if (m_data.size() == 0) {
return;
}
// set all the line:
m_draw.setColor(etk::color::white);
m_draw.setThickness(1);
float ratioX = m_size.x() / (m_frequencyMax - m_frequencyMin);
float ratioY = m_size.y() / (m_gainMax - m_gainMin);
m_draw.setPos(vec2(ratioX*(m_data[0].first - m_gainMin),
ratioY*(m_data[0].second - m_gainMin)));
float baseX = 0;
for (size_t iii=1; iii<m_data.size(); ++iii) {
m_draw.lineTo(vec2(ratioX*(m_data[0].first - m_gainMin),
ratioY*(m_data[0].second - m_gainMin)));
// calculate min and Max :
m_gainMax = -999999999.9;
m_gainMin = 9999999999.9;
m_frequencyMin = 99999999.0;
m_frequencyMax = -99999999.0;
for (size_t kkk=0; kkk<m_data.size(); kkk++) {
for (size_t iii=0; iii<m_data[kkk].size(); ++iii) {
m_gainMax = std::max(m_gainMax, m_data[kkk][iii].second);
m_gainMin = std::min(m_gainMin, m_data[kkk][iii].second);
m_frequencyMax = std::max(m_frequencyMax, m_data[kkk][iii].first);
m_frequencyMin = std::min(m_frequencyMin, m_data[kkk][iii].first);
}
}
m_gainMin = -20;
// 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);
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)));
}
}
// TODO : Draw text ...
}

View File

@ -28,8 +28,11 @@ namespace appl {
//! @brief destructor
virtual ~DisplayFrequency();
private:
std::vector<std::pair<float,float> > m_data; //!< data that might be displayed
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
@ -44,6 +47,8 @@ namespace appl {
public: // herited function
virtual void onDraw();
virtual void onRegenerateDisplay();
private:
vec2 m_borderSize;
};
}
}

View File

@ -17,7 +17,7 @@ def create(target):
'appl/widget/DisplayFrequency.cpp',
])
# add Library dependency name
myModule.add_module_depend(['ewol', 'drain'])
myModule.add_module_depend(['ewol', 'drain', 'river'])
# add application C flags
myModule.compile_flags_CC([
"-DPROJECT_NAME=\"\\\""+myModule.name+"\\\"\""])