[DEV] add basic equalizer with biquad Not tested
This commit is contained in:
parent
68c2174fb0
commit
9a5490580a
64
.gitignore
vendored
Normal file
64
.gitignore
vendored
Normal file
@ -0,0 +1,64 @@
|
||||
|
||||
###################################
|
||||
# folders
|
||||
###################################
|
||||
CVS
|
||||
.svn
|
||||
Object_*
|
||||
doxygen/API/
|
||||
doxygen/ALL/
|
||||
|
||||
###################################
|
||||
# backup files
|
||||
###################################
|
||||
*~
|
||||
*.swp
|
||||
*.old
|
||||
*.bck
|
||||
|
||||
###################################
|
||||
# Compiled source #
|
||||
###################################
|
||||
*.com
|
||||
*.class
|
||||
*.dll
|
||||
*.exe
|
||||
*.o
|
||||
*.so
|
||||
*.pyc
|
||||
tags
|
||||
#ewol
|
||||
out
|
||||
ewol_debug
|
||||
ewol_release
|
||||
|
||||
###################################
|
||||
# Packages #
|
||||
###################################
|
||||
# it's better to unpack these files and commit the raw source
|
||||
# git has its own built in compression methods
|
||||
*.7z
|
||||
*.dmg
|
||||
*.gz
|
||||
*.iso
|
||||
*.jar
|
||||
*.rar
|
||||
*.tar
|
||||
*.zip
|
||||
|
||||
###################################
|
||||
# Logs and databases #
|
||||
###################################
|
||||
*.log
|
||||
*.sql
|
||||
*.sqlite
|
||||
|
||||
###################################
|
||||
# OS generated files #
|
||||
###################################
|
||||
.DS_Store?
|
||||
ehthumbs.db
|
||||
Icon?
|
||||
Thumbs.db
|
||||
Sources/libewol/ewol/os/AndroidAbstraction.cpp
|
||||
org_ewol_EwolConstants.h
|
9
audio/algo/drain/BiQuad.cpp
Normal file
9
audio/algo/drain/BiQuad.cpp
Normal file
@ -0,0 +1,9 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
*/
|
||||
|
||||
#include <etk/types.h>
|
||||
#include <audio/algo/drain/debug.h>
|
||||
#include <audio/algo/drain/BiQuad.h>
|
282
audio/algo/drain/BiQuad.h
Normal file
282
audio/algo/drain/BiQuad.h
Normal file
@ -0,0 +1,282 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
*/
|
||||
|
||||
#ifndef __AUDIO_ALGO_DRAIN_ALGO_BIQUAD_H__
|
||||
#define __AUDIO_ALGO_DRAIN_ALGO_BIQUAD_H__
|
||||
|
||||
#include <etk/memory.h>
|
||||
#include <audio/algo/drain/BiQuadType.h>
|
||||
|
||||
namespace audio {
|
||||
namespace algo {
|
||||
namespace drain {
|
||||
template<typename TYPE> class BiQuad {
|
||||
public:
|
||||
BiQuad() {
|
||||
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;
|
||||
}
|
||||
protected:
|
||||
TYPE m_x[2]; //!< X history
|
||||
TYPE m_y[2]; //!< Y histiry
|
||||
TYPE m_a[3]; //!< A bi-Quad coef
|
||||
TYPE 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 audio::algo::drain::biQuadType _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 = std11::pow(10.0, std11::abs(_gain) / 20.0);
|
||||
double K = std11::tan(M_PI * _frequencyCut / _sampleRate);
|
||||
switch (_type) {
|
||||
case biQuadType_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 biQuadType_lowPass:
|
||||
norm = 1.0 / (1.0 + K / _qualityFactor + K * K);
|
||||
m_a[0] = K * K * norm;
|
||||
m_a[1] = m_a[0] * 2.0;
|
||||
m_a[2] = m_a[0];
|
||||
m_b[0] = 2.0 * (K * K - 1.0) * norm;
|
||||
m_b[1] = (1.0 - K / _qualityFactor + K * K) * norm;
|
||||
break;
|
||||
case biQuadType_highPass:
|
||||
norm = 1.0 / (1.0 + K / _qualityFactor + K * K);
|
||||
m_a[0] = 1.0 * norm;
|
||||
m_a[1] = m_a[0] * -2.0;
|
||||
m_a[2] = m_a[0];
|
||||
m_b[0] = 2.0 * (K * K - 1.0) * norm;
|
||||
m_b[1] = (1.0 - K / _qualityFactor + K * K) * norm;
|
||||
break;
|
||||
case biQuadType_bandPass:
|
||||
norm = 1.0 / (1.0 + K / _qualityFactor + K * K);
|
||||
m_a[0] = K / _qualityFactor * norm;
|
||||
m_a[1] = 0.0;
|
||||
m_a[2] = m_a[0] * -1.0;
|
||||
m_b[0] = 2.0 * (K * K - 1.0) * norm;
|
||||
m_b[1] = (1.0 - K / _qualityFactor + K * K) * norm;
|
||||
break;
|
||||
case biQuadType_notch:
|
||||
norm = 1.0 / (1.0 + K / _qualityFactor + K * K);
|
||||
m_a[0] = (1.0 + K * K) * norm;
|
||||
m_a[1] = 2.0 * (K * K - 1.0) * norm;
|
||||
m_a[2] = m_a[0];
|
||||
m_b[0] = m_a[1];
|
||||
m_b[1] = (1.0 - K / _qualityFactor + K * K) * norm;
|
||||
break;
|
||||
case biQuadType_peak:
|
||||
if (_gain >= 0.0) {
|
||||
norm = 1.0 / (1.0 + 1.0/_qualityFactor * K + K * K);
|
||||
m_a[0] = (1.0 + V/_qualityFactor * K + K * K) * norm;
|
||||
m_a[1] = 2.0 * (K * K - 1.0) * norm;
|
||||
m_a[2] = (1.0 - V/_qualityFactor * K + K * K) * norm;
|
||||
m_b[0] = m_a[1];
|
||||
m_b[1] = (1.0 - 1.0/_qualityFactor * K + K * K) * norm;
|
||||
} else {
|
||||
norm = 1.0 / (1.0 + V/_qualityFactor * K + K * K);
|
||||
m_a[0] = (1.0 + 1.0/_qualityFactor * K + K * K) * norm;
|
||||
m_a[1] = 2.0 * (K * K - 1.0) * norm;
|
||||
m_a[2] = (1.0 - 1.0/_qualityFactor * K + K * K) * norm;
|
||||
m_b[0] = m_a[1];
|
||||
m_b[1] = (1.0 - V/_qualityFactor * K + K * K) * norm;
|
||||
}
|
||||
break;
|
||||
case biQuadType_lowShelf:
|
||||
if (_gain >= 0) {
|
||||
norm = 1.0 / (1.0 + M_SQRT2 * K + K * K);
|
||||
m_a[0] = (1.0 + std11::sqrt(2.0*V) * K + V * K * K) * norm;
|
||||
m_a[1] = 2.0 * (V * K * K - 1.0) * norm;
|
||||
m_a[2] = (1.0 - std11::sqrt(2.0*V) * K + V * K * K) * norm;
|
||||
m_b[0] = 2.0 * (K * K - 1.0) * norm;
|
||||
m_b[1] = (1.0 - M_SQRT2 * K + K * K) * norm;
|
||||
} else {
|
||||
norm = 1.0 / (1.0 + std11::sqrt(2.0*V) * K + V * K * K);
|
||||
m_a[0] = (1.0 + M_SQRT2 * K + K * K) * norm;
|
||||
m_a[1] = 2.0 * (K * K - 1.0) * norm;
|
||||
m_a[2] = (1.0 - M_SQRT2 * K + K * K) * norm;
|
||||
m_b[0] = 2.0 * (V * K * K - 1.0) * norm;
|
||||
m_b[1] = (1.0 - std11::sqrt(2.0*V) * K + V * K * K) * norm;
|
||||
}
|
||||
break;
|
||||
case biQuadType_highShelf:
|
||||
if (_gain >= 0) {
|
||||
norm = 1.0 / (1.0 + M_SQRT2 * K + K * K);
|
||||
m_a[0] = (V + std11::sqrt(2.0*V) * K + K * K) * norm;
|
||||
m_a[1] = 2.0 * (K * K - V) * norm;
|
||||
m_a[2] = (V - std11::sqrt(2.0*V) * K + K * K) * norm;
|
||||
m_b[0] = 2.0 * (K * K - 1.0) * norm;
|
||||
m_b[1] = (1.0 - M_SQRT2 * K + K * K) * norm;
|
||||
} else {
|
||||
norm = 1.0 / (V + std11::sqrt(2.0*V) * K + K * K);
|
||||
m_a[0] = (1.0 + M_SQRT2 * K + K * K) * norm;
|
||||
m_a[1] = 2.0 * (K * K - 1.0) * norm;
|
||||
m_a[2] = (1.0 - M_SQRT2 * K + K * K) * norm;
|
||||
m_b[0] = 2.0 * (K * K - V) * norm;
|
||||
m_b[1] = (V - std11::sqrt(2.0*V) * K + K * K) * norm;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @brief Set direct Coefficients
|
||||
*/
|
||||
void setBiquadCoef(TYPE _a0, TYPE _a1, TYPE _a2, TYPE _b0, TYPE _b1) {
|
||||
m_a[0] = _a0;
|
||||
m_a[1] = _a1;
|
||||
m_a[2] = _a2;
|
||||
m_b[0] = _b0;
|
||||
m_b[1] = _b1;
|
||||
reset();
|
||||
}
|
||||
/**
|
||||
* @brief Get direct Coefficients
|
||||
*/
|
||||
void getBiquadCoef(TYPE& _a0, TYPE& _a1, TYPE& _a2, TYPE& _b0, TYPE& _b1) {
|
||||
_a0 = m_a[0];
|
||||
_a1 = m_a[1];
|
||||
_a2 = m_a[2];
|
||||
_b0 = m_b[0];
|
||||
_b1 = m_b[1];
|
||||
}
|
||||
/**
|
||||
* @brief Get direct Coefficients
|
||||
*/
|
||||
std::vector<TYPE> getCoef() {
|
||||
std::vector<TYPE> 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;
|
||||
}
|
||||
/**
|
||||
* @brief Reset bequad filter (only history not value).
|
||||
*/
|
||||
void reset() {
|
||||
m_x[0] = 0;
|
||||
m_y[1] = 0;
|
||||
m_x[0] = 0;
|
||||
m_y[1] = 0;
|
||||
}
|
||||
protected:
|
||||
/**
|
||||
* @brief process single sample in float.
|
||||
* @param[in] _sample Sample to process
|
||||
* @return updataed value
|
||||
*/
|
||||
TYPE process(TYPE _sample) {
|
||||
TYPE 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;
|
||||
}
|
||||
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 process(const TYPE* _input,
|
||||
TYPE* _output,
|
||||
size_t _nbChunk,
|
||||
int32_t _inputOffset,
|
||||
int32_t _outputOffset) {
|
||||
for (size_t iii=0; iii<_nbChunk; ++iii) {
|
||||
// process in float the biquad.
|
||||
*_output = process(*_input);
|
||||
// move to the sample on the same channel.
|
||||
_input += _inputOffset;
|
||||
_output += _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){
|
||||
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 = std11::exp(std11::log(1.0 / 0.001) * iii / (len - 1.0)) * 0.001 * M_PI;
|
||||
}
|
||||
double freq = iii / (len - 1.0) * _sampleRate / 2.0;
|
||||
double phi = std11::pow(std11::sin(w/2.0), 2.0);
|
||||
double y = std11::log( std11::pow((m_a[0]+m_a[1]+m_a[2]).getDouble(), 2.0)
|
||||
- 4.0*((m_a[0]*m_a[1]).getDouble() + 4.0*(m_a[0]*m_a[2]).getDouble() + (m_a[1]*m_a[2]).getDouble())*phi
|
||||
+ 16.0*(m_a[0]*m_a[2]).getDouble()*phi*phi)
|
||||
- std11::log( std11::pow(1.0+(m_b[0]+m_b[1]).getDouble(), 2.0)
|
||||
- 4.0*((m_b[0]).getDouble() + 4.0*(m_b[1]).getDouble() + (m_b[0]*m_b[1]).getDouble())*phi
|
||||
+ 16.0*m_b[1].getDouble()*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;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
38
audio/algo/drain/BiQuadType.cpp
Normal file
38
audio/algo/drain/BiQuadType.cpp
Normal file
@ -0,0 +1,38 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
*/
|
||||
|
||||
#include <etk/types.h>
|
||||
#include <audio/algo/drain/debug.h>
|
||||
#include <audio/algo/drain/BiQuadType.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 audio::algo::drain::biQuadType>(const enum audio::algo::drain::biQuadType& _variable) {
|
||||
return listValues[_variable];
|
||||
}
|
||||
template <> bool from_string<enum audio::algo::drain::biQuadType>(enum audio::algo::drain::biQuadType& _variableRet, const std::string& _value) {
|
||||
for (int32_t iii=0; iii<listValuesSize; ++iii) {
|
||||
if (_value == listValues[iii]) {
|
||||
_variableRet = static_cast<enum audio::algo::drain::biQuadType>(iii);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
_variableRet = audio::algo::drain::biQuadType_none;
|
||||
return false;
|
||||
}
|
||||
}
|
29
audio/algo/drain/BiQuadType.h
Normal file
29
audio/algo/drain/BiQuadType.h
Normal file
@ -0,0 +1,29 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
*/
|
||||
|
||||
#ifndef __AUDIO_ALGO_DRAIN_ALGO_BIQUAD_TYPE_H__
|
||||
#define __AUDIO_ALGO_DRAIN_ALGO_BIQUAD_TYPE_H__
|
||||
|
||||
#include <etk/memory.h>
|
||||
|
||||
namespace audio {
|
||||
namespace algo {
|
||||
namespace drain {
|
||||
enum biQuadType {
|
||||
biQuadType_none, //!< no filter (pass threw...)
|
||||
biQuadType_lowPass, //!< low pass filter
|
||||
biQuadType_highPass, //!< High pass filter
|
||||
biQuadType_bandPass, //!< band pass filter
|
||||
biQuadType_notch, //!< Notch Filter
|
||||
biQuadType_peak, //!< Peaking band EQ filter
|
||||
biQuadType_lowShelf, //!< Low shelf filter
|
||||
biQuadType_highShelf, //!< High shelf filter
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
359
audio/algo/drain/Equalizer.cpp
Normal file
359
audio/algo/drain/Equalizer.cpp
Normal file
@ -0,0 +1,359 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
*/
|
||||
|
||||
#include <audio/algo/drain/Equalizer.h>
|
||||
#include <audio/algo/drain/debug.h>
|
||||
#include <audio/algo/drain/BiQuad.h>
|
||||
#include <audio/types.h>
|
||||
|
||||
|
||||
// see http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt
|
||||
// see http://www.earlevel.com/main/2013/10/13/biquad-calculator-v2/
|
||||
|
||||
namespace audio {
|
||||
namespace algo {
|
||||
namespace drain {
|
||||
class EqualizerPrivate {
|
||||
protected:
|
||||
float m_sampleRate;
|
||||
int8_t m_nbChannel;
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor
|
||||
*/
|
||||
EqualizerPrivate() :
|
||||
m_sampleRate(48000),
|
||||
m_nbChannel(2) {
|
||||
|
||||
}
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
virtual ~EqualizerPrivate() {
|
||||
|
||||
}
|
||||
public:
|
||||
/**
|
||||
* @brief Initialize the Algorithm
|
||||
* @param[in] _sampleRate Sample rate of the stream.
|
||||
* @param[in] _nbChannel Number of channel in the stream.
|
||||
*/
|
||||
virtual void init(float _sampleRate=48000, int8_t _nbChannel=2) {
|
||||
m_sampleRate = _sampleRate;
|
||||
m_nbChannel = _nbChannel;
|
||||
};
|
||||
/**
|
||||
* @brief Main input algo process.
|
||||
* @param[in,out] _output Output data.
|
||||
* @param[in] _input Input data.
|
||||
* @param[in] _nbChunk Number of chunk in the input buffer.
|
||||
*/
|
||||
virtual void process(void* _output, const void* _input, size_t _nbChunk) = 0;
|
||||
public:
|
||||
/**
|
||||
* @brief add a biquad with his value.
|
||||
*/
|
||||
virtual bool addBiquad(double _a0, double _a1, double _a2, double _b0, double _b1) = 0;
|
||||
virtual bool addBiquad(int32_t _idChannel, double _a0, double _a1, double _a2, double _b0, double _b1) = 0;
|
||||
/**
|
||||
* @brief add a 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
|
||||
*/
|
||||
virtual bool addBiquad(audio::algo::drain::biQuadType _type, double _frequencyCut, double _qualityFactor, double _gain) = 0;
|
||||
virtual bool addBiquad(int32_t _idChannel, audio::algo::drain::biQuadType _type, double _frequencyCut, double _qualityFactor, double _gain) = 0;
|
||||
public:
|
||||
// for debug & tools only
|
||||
virtual std::vector<std::pair<float,float> > calculateTheory() = 0;
|
||||
};
|
||||
template<typename TYPE> class EqualizerPrivateType : public audio::algo::drain::EqualizerPrivate {
|
||||
protected:
|
||||
std::vector<std::vector<audio::algo::drain::BiQuad<TYPE> > > m_biquads;
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor
|
||||
*/
|
||||
EqualizerPrivateType() {
|
||||
|
||||
}
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
virtual ~EqualizerPrivateType() {
|
||||
|
||||
}
|
||||
virtual void init(float _sampleRate=48000, int8_t _nbChannel=2) {
|
||||
audio::algo::drain::EqualizerPrivate::init(_sampleRate, _nbChannel);
|
||||
m_biquads.clear();
|
||||
m_biquads.resize(_nbChannel);
|
||||
}
|
||||
virtual void process(void* _output, const void* _input, size_t _nbChunk) {
|
||||
for (size_t jjj=0; jjj<m_nbChannel; ++jjj) {
|
||||
// get pointer on data:
|
||||
const TYPE* input = reinterpret_cast<const TYPE*>(_input);
|
||||
TYPE* output = reinterpret_cast<TYPE*>(_output);
|
||||
// move to sample offset:
|
||||
input += jjj;
|
||||
output += jjj;
|
||||
for (size_t iii=0; iii<m_biquads[jjj].size(); ++iii) {
|
||||
m_biquads[jjj][iii].process(input, output, _nbChunk, m_nbChannel, m_nbChannel);
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual bool addBiquad(double _a0, double _a1, double _a2, double _b0, double _b1) {
|
||||
audio::algo::drain::BiQuad<TYPE> bq;
|
||||
bq.setBiquadCoef(_a0, _a1, _a2, _b0, _b1);
|
||||
// add this bequad for every Channel:
|
||||
for (size_t iii=0; iii<m_biquads.size(); ++iii) {
|
||||
m_biquads[iii].push_back(bq);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
virtual bool addBiquad(audio::algo::drain::biQuadType _type, double _frequencyCut, double _qualityFactor, double _gain) {
|
||||
audio::algo::drain::BiQuad<TYPE> bq;
|
||||
bq.setBiquad(_type, _frequencyCut, _qualityFactor, _gain, m_sampleRate);
|
||||
// add this bequad for every Channel:
|
||||
for (size_t iii=0; iii<m_biquads.size(); ++iii) {
|
||||
m_biquads[iii].push_back(bq);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
virtual bool addBiquad(int32_t _idChannel, double _a0, double _a1, double _a2, double _b0, double _b1) {
|
||||
audio::algo::drain::BiQuad<TYPE> bq;
|
||||
bq.setBiquadCoef(_a0, _a1, _a2, _b0, _b1);
|
||||
if (_idChannel<m_biquads.size()) {
|
||||
m_biquads[_idChannel].push_back(bq);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
virtual bool addBiquad(int32_t _idChannel, audio::algo::drain::biQuadType _type, double _frequencyCut, double _qualityFactor, double _gain) {
|
||||
audio::algo::drain::BiQuad<TYPE> bq;
|
||||
bq.setBiquad(_type, _frequencyCut, _qualityFactor, _gain, m_sampleRate);
|
||||
if (_idChannel<m_biquads.size()) {
|
||||
m_biquads[_idChannel].push_back(bq);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
virtual std::vector<std::pair<float,float> > calculateTheory() {
|
||||
std::vector<std::pair<float,float> > out;
|
||||
for (size_t iii=0; iii<m_biquads[0].size(); ++iii) {
|
||||
if (iii == 0) {
|
||||
out = m_biquads[0][iii].calculateTheory(m_sampleRate);
|
||||
} else {
|
||||
std::vector<std::pair<float,float> > tmp = m_biquads[0][iii].calculateTheory(m_sampleRate);
|
||||
for (size_t jjj=0; jjj< out.size(); ++jjj) {
|
||||
out[jjj].second += tmp[jjj].second;
|
||||
}
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
audio::algo::drain::Equalizer::Equalizer() {
|
||||
|
||||
}
|
||||
|
||||
audio::algo::drain::Equalizer::~Equalizer() {
|
||||
|
||||
}
|
||||
|
||||
void audio::algo::drain::Equalizer::init(float _sampleRate, int8_t _nbChannel, enum audio::format _format) {
|
||||
switch (_format) {
|
||||
default:
|
||||
AA_DRAIN_CRITICAL("Request format for equalizer that not exist ... : " << _format);
|
||||
break;
|
||||
case audio::format_double:
|
||||
{
|
||||
std11::unique_ptr<EqualizerPrivateType<audio::double_t> > value(new EqualizerPrivateType<audio::double_t>());
|
||||
if (value == nullptr) {
|
||||
AA_DRAIN_ERROR("can not allocate private data...");
|
||||
return;
|
||||
}
|
||||
value->init(_sampleRate, _nbChannel);
|
||||
// net value:
|
||||
m_private = std11::move(value);
|
||||
}
|
||||
break;
|
||||
case audio::format_float:
|
||||
{
|
||||
std11::unique_ptr<EqualizerPrivateType<audio::float_t> > value(new EqualizerPrivateType<audio::float_t>());
|
||||
if (value == nullptr) {
|
||||
AA_DRAIN_ERROR("can not allocate private data...");
|
||||
return;
|
||||
}
|
||||
value->init(_sampleRate, _nbChannel);
|
||||
// net value:
|
||||
m_private = std11::move(value);
|
||||
}
|
||||
break;
|
||||
case audio::format_int8:
|
||||
{
|
||||
std11::unique_ptr<EqualizerPrivateType<audio::int8_8_t> > value(new EqualizerPrivateType<audio::int8_8_t>());
|
||||
if (value == nullptr) {
|
||||
AA_DRAIN_ERROR("can not allocate private data...");
|
||||
return;
|
||||
}
|
||||
value->init(_sampleRate, _nbChannel);
|
||||
// net value:
|
||||
m_private = std11::move(value);
|
||||
}
|
||||
break;
|
||||
case audio::format_int8_on_int16:
|
||||
{
|
||||
std11::unique_ptr<EqualizerPrivateType<audio::int8_16_t> > value(new EqualizerPrivateType<audio::int8_16_t>());
|
||||
if (value == nullptr) {
|
||||
AA_DRAIN_ERROR("can not allocate private data...");
|
||||
return;
|
||||
}
|
||||
value->init(_sampleRate, _nbChannel);
|
||||
// net value:
|
||||
m_private = std11::move(value);
|
||||
}
|
||||
break;
|
||||
case audio::format_int16:
|
||||
{
|
||||
std11::unique_ptr<EqualizerPrivateType<audio::int16_16_t> > value(new EqualizerPrivateType<audio::int16_16_t>());
|
||||
if (value == nullptr) {
|
||||
AA_DRAIN_ERROR("can not allocate private data...");
|
||||
return;
|
||||
}
|
||||
value->init(_sampleRate, _nbChannel);
|
||||
// net value:
|
||||
m_private = std11::move(value);
|
||||
}
|
||||
break;
|
||||
case audio::format_int16_on_int32:
|
||||
{
|
||||
std11::unique_ptr<EqualizerPrivateType<audio::int16_32_t> > value(new EqualizerPrivateType<audio::int16_32_t>());
|
||||
if (value == nullptr) {
|
||||
AA_DRAIN_ERROR("can not allocate private data...");
|
||||
return;
|
||||
}
|
||||
value->init(_sampleRate, _nbChannel);
|
||||
// net value:
|
||||
m_private = std11::move(value);
|
||||
}
|
||||
break;
|
||||
case audio::format_int24_on_int32:
|
||||
{
|
||||
std11::unique_ptr<EqualizerPrivateType<audio::int24_32_t> > value(new EqualizerPrivateType<audio::int24_32_t>());
|
||||
if (value == nullptr) {
|
||||
AA_DRAIN_ERROR("can not allocate private data...");
|
||||
return;
|
||||
}
|
||||
value->init(_sampleRate, _nbChannel);
|
||||
// net value:
|
||||
m_private = std11::move(value);
|
||||
}
|
||||
break;
|
||||
case audio::format_int32:
|
||||
{
|
||||
std11::unique_ptr<EqualizerPrivateType<audio::int32_32_t> > value(new EqualizerPrivateType<audio::int32_32_t>());
|
||||
if (value == nullptr) {
|
||||
AA_DRAIN_ERROR("can not allocate private data...");
|
||||
return;
|
||||
}
|
||||
value->init(_sampleRate, _nbChannel);
|
||||
// net value:
|
||||
m_private = std11::move(value);
|
||||
}
|
||||
break;
|
||||
case audio::format_int32_on_int64:
|
||||
{
|
||||
std11::unique_ptr<EqualizerPrivateType<audio::int32_64_t> > value(new EqualizerPrivateType<audio::int32_64_t>());
|
||||
if (value == nullptr) {
|
||||
AA_DRAIN_ERROR("can not allocate private data...");
|
||||
return;
|
||||
}
|
||||
value->init(_sampleRate, _nbChannel);
|
||||
// net value:
|
||||
m_private = std11::move(value);
|
||||
}
|
||||
break;
|
||||
case audio::format_int64:
|
||||
{
|
||||
std11::unique_ptr<EqualizerPrivateType<audio::int32_64_t> > value(new EqualizerPrivateType<audio::int32_64_t>());
|
||||
if (value == nullptr) {
|
||||
AA_DRAIN_ERROR("can not allocate private data...");
|
||||
return;
|
||||
}
|
||||
value->init(_sampleRate, _nbChannel);
|
||||
// net value:
|
||||
m_private = std11::move(value);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<enum audio::format> audio::algo::drain::Equalizer::getSupportedFormat() {
|
||||
std::vector<enum audio::format> out = audio::algo::drain::Equalizer::getNativeSupportedFormat();
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
std::vector<enum audio::format> audio::algo::drain::Equalizer::getNativeSupportedFormat() {
|
||||
std::vector<enum audio::format> out;
|
||||
out.push_back(audio::format_float);
|
||||
return out;
|
||||
}
|
||||
|
||||
void audio::algo::drain::Equalizer::process(void* _output, const void* _input, size_t _nbChunk) {
|
||||
if (m_private == nullptr) {
|
||||
AA_DRAIN_ERROR("Equalizer does not init ...");
|
||||
return;
|
||||
}
|
||||
m_private->process(_output, _input, _nbChunk);
|
||||
}
|
||||
|
||||
bool audio::algo::drain::Equalizer::addBiquad(double _a0, double _a1, double _a2, double _b0, double _b1) {
|
||||
if (m_private == nullptr) {
|
||||
AA_DRAIN_ERROR("Equalizer does not init ...");
|
||||
return false;
|
||||
}
|
||||
return m_private->addBiquad(_a0, _a1, _a2, _b0, _b1);
|
||||
}
|
||||
bool audio::algo::drain::Equalizer::addBiquad(int32_t _idChannel, double _a0, double _a1, double _a2, double _b0, double _b1) {
|
||||
if (m_private == nullptr) {
|
||||
AA_DRAIN_ERROR("Equalizer does not init ...");
|
||||
return false;
|
||||
}
|
||||
return m_private->addBiquad(_idChannel, _a0, _a1, _a2, _b0, _b1);
|
||||
}
|
||||
|
||||
bool audio::algo::drain::Equalizer::addBiquad(audio::algo::drain::biQuadType _type, double _frequencyCut, double _qualityFactor, double _gain) {
|
||||
if (m_private == nullptr) {
|
||||
AA_DRAIN_ERROR("Equalizer does not init ...");
|
||||
return false;
|
||||
}
|
||||
return m_private->addBiquad(_type, _frequencyCut, _qualityFactor, _gain);
|
||||
}
|
||||
bool audio::algo::drain::Equalizer::addBiquad(int32_t _idChannel, audio::algo::drain::biQuadType _type, double _frequencyCut, double _qualityFactor, double _gain) {
|
||||
if (m_private == nullptr) {
|
||||
AA_DRAIN_ERROR("Equalizer does not init ...");
|
||||
return false;
|
||||
}
|
||||
return m_private->addBiquad(_idChannel, _type, _frequencyCut, _qualityFactor, _gain);
|
||||
}
|
||||
|
||||
std::vector<std::pair<float,float> > audio::algo::drain::Equalizer::calculateTheory() {
|
||||
if (m_private == nullptr) {
|
||||
AA_DRAIN_ERROR("Equalizer does not init ...");
|
||||
return std::vector<std::pair<float,float> >();
|
||||
}
|
||||
return m_private->calculateTheory();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
81
audio/algo/drain/Equalizer.h
Normal file
81
audio/algo/drain/Equalizer.h
Normal file
@ -0,0 +1,81 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
*/
|
||||
|
||||
#ifndef __AUDIO_ALGO_DRAIN_ALGO_EQUALIZER_H__
|
||||
#define __AUDIO_ALGO_DRAIN_ALGO_EQUALIZER_H__
|
||||
|
||||
#include <etk/types.h>
|
||||
#include <etk/memory.h>
|
||||
#include <vector>
|
||||
#include <audio/format.h>
|
||||
#include <audio/algo/drain/BiQuadType.h>
|
||||
|
||||
namespace audio {
|
||||
namespace algo {
|
||||
namespace drain {
|
||||
class EqualizerPrivate;
|
||||
class Equalizer {
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor
|
||||
*/
|
||||
Equalizer();
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
virtual ~Equalizer();
|
||||
public:
|
||||
/**
|
||||
* @brief Initialize the Algorithm
|
||||
* @param[in] _sampleRate Sample rate of the stream.
|
||||
* @param[in] _nbChannel Number of channel in the stream.
|
||||
* @param[in] _format Input data format.
|
||||
*/
|
||||
virtual void init(float _sampleRate=48000, int8_t _nbChannel=2, enum audio::format _format=audio::format_float);
|
||||
/**
|
||||
* @brief Get list of format suported in input.
|
||||
* @return list of supported format
|
||||
*/
|
||||
virtual std::vector<enum audio::format> getSupportedFormat();
|
||||
/**
|
||||
* @brief Get list of algorithm format suported. No format convertion.
|
||||
* @return list of supported format
|
||||
*/
|
||||
virtual std::vector<enum audio::format> getNativeSupportedFormat();
|
||||
/**
|
||||
* @brief Main input algo process.
|
||||
* @param[in,out] _output Output data.
|
||||
* @param[in] _input Input data.
|
||||
* @param[in] _nbChunk Number of chunk in the input buffer.
|
||||
*/
|
||||
virtual void process(void* _output, const void* _input, size_t _nbChunk);
|
||||
public:
|
||||
/**
|
||||
* @brief add a biquad with his value.
|
||||
*/
|
||||
bool addBiquad(double _a0, double _a1, double _a2, double _b0, double _b1);
|
||||
bool addBiquad(int32_t _idChannel, double _a0, double _a1, double _a2, double _b0, double _b1);
|
||||
/**
|
||||
* @brief add a 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
|
||||
*/
|
||||
bool addBiquad(audio::algo::drain::biQuadType _type, double _frequencyCut, double _qualityFactor, double _gain);
|
||||
bool addBiquad(int32_t _idChannel, audio::algo::drain::biQuadType _type, double _frequencyCut, double _qualityFactor, double _gain);
|
||||
public:
|
||||
// for debug & tools only
|
||||
std::vector<std::pair<float,float> > calculateTheory();
|
||||
protected:
|
||||
std11::unique_ptr<EqualizerPrivate> m_private; //!< private data (abstract the type of the data flow).
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
14
audio/algo/drain/debug.cpp
Normal file
14
audio/algo/drain/debug.cpp
Normal file
@ -0,0 +1,14 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
*/
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
|
||||
int32_t audio::algo::drain::getLogId() {
|
||||
static int32_t g_val = etk::log::registerInstance("audio-algo-drain");
|
||||
return g_val;
|
||||
}
|
||||
|
46
audio/algo/drain/debug.h
Normal file
46
audio/algo/drain/debug.h
Normal file
@ -0,0 +1,46 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
*/
|
||||
|
||||
#ifndef __AUDIO_ALGO_DRAIN_DEBUG_H__
|
||||
#define __AUDIO_ALGO_DRAIN_DEBUG_H__
|
||||
|
||||
#include <etk/log.h>
|
||||
|
||||
namespace audio {
|
||||
namespace algo {
|
||||
namespace drain {
|
||||
int32_t getLogId();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define AA_DRAIN_BASE(info,data) TK_LOG_BASE(audio::algo::drain::getLogId(),info,data)
|
||||
|
||||
#define AA_DRAIN_PRINT(data) AA_DRAIN_BASE(-1, data)
|
||||
#define AA_DRAIN_CRITICAL(data) AA_DRAIN_BASE(1, data)
|
||||
#define AA_DRAIN_ERROR(data) AA_DRAIN_BASE(2, data)
|
||||
#define AA_DRAIN_WARNING(data) AA_DRAIN_BASE(3, data)
|
||||
#ifdef DEBUG
|
||||
#define AA_DRAIN_INFO(data) AA_DRAIN_BASE(4, data)
|
||||
#define AA_DRAIN_DEBUG(data) AA_DRAIN_BASE(5, data)
|
||||
#define AA_DRAIN_VERBOSE(data) AA_DRAIN_BASE(6, data)
|
||||
#define AA_DRAIN_TODO(data) AA_DRAIN_BASE(4, "TODO : " << data)
|
||||
#else
|
||||
#define AA_DRAIN_INFO(data) do { } while(false)
|
||||
#define AA_DRAIN_DEBUG(data) do { } while(false)
|
||||
#define AA_DRAIN_VERBOSE(data) do { } while(false)
|
||||
#define AA_DRAIN_TODO(data) do { } while(false)
|
||||
#endif
|
||||
|
||||
#define AA_DRAIN_ASSERT(cond,data) \
|
||||
do { \
|
||||
if (!(cond)) { \
|
||||
AA_DRAIN_CRITICAL(data); \
|
||||
assert(!#cond); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#endif
|
37
lutin_audio_algo_drain.py
Normal file
37
lutin_audio_algo_drain.py
Normal file
@ -0,0 +1,37 @@
|
||||
#!/usr/bin/python
|
||||
import lutinModule as module
|
||||
import lutinTools as tools
|
||||
import lutinDebug as debug
|
||||
|
||||
def get_desc():
|
||||
return "audio_algo_drain : drain basic algorithm"
|
||||
|
||||
def get_licence():
|
||||
# return a table with : "Licence Name", contamination if link static, contamination if link dynamic, "Licence string description / FileName / auto for classicle licence"]
|
||||
return ["APACHE-2", False, False, "auto"]
|
||||
|
||||
|
||||
def create(target):
|
||||
myModule = module.Module(__file__, 'audio_algo_drain', 'LIBRARY')
|
||||
myModule.add_src_file([
|
||||
'audio/algo/drain/debug.cpp',
|
||||
'audio/algo/drain/BiQuad.cpp',
|
||||
'audio/algo/drain/BiQuadType.cpp',
|
||||
'audio/algo/drain/Equalizer.cpp'
|
||||
])
|
||||
myModule.add_module_depend(['etk', 'audio'])
|
||||
|
||||
myModule.add_export_path(tools.get_current_path(__file__))
|
||||
|
||||
#myModule.set_licence(module.APACHE_2)
|
||||
|
||||
return myModule
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
26
lutin_audio_algo_drain_test.py
Normal file
26
lutin_audio_algo_drain_test.py
Normal file
@ -0,0 +1,26 @@
|
||||
#!/usr/bin/python
|
||||
import lutinModule as module
|
||||
import lutinTools as tools
|
||||
import lutinDebug as debug
|
||||
|
||||
def get_desc():
|
||||
return "audio_algo_drain_test: test for speex ALGO"
|
||||
|
||||
|
||||
def create(target):
|
||||
myModule = module.Module(__file__, 'audio_algo_drain_test', 'BINARY')
|
||||
myModule.add_src_file([
|
||||
'test/main.cpp',
|
||||
'test/debug.cpp'
|
||||
])
|
||||
myModule.add_module_depend(['audio_algo_drain'])
|
||||
return myModule
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
13
test/debug.cpp
Normal file
13
test/debug.cpp
Normal file
@ -0,0 +1,13 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
*/
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
int32_t appl::getLogId() {
|
||||
static int32_t g_val = etk::log::registerInstance("test-drain");
|
||||
return g_val;
|
||||
}
|
||||
|
41
test/debug.h
Normal file
41
test/debug.h
Normal file
@ -0,0 +1,41 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (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_PRINT(data) APPL_BASE(-1, 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)
|
||||
#define APPL_INFO(data) APPL_BASE(4, data)
|
||||
#ifdef DEBUG
|
||||
#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_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
|
228
test/main.cpp
Normal file
228
test/main.cpp
Normal file
@ -0,0 +1,228 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
*/
|
||||
|
||||
#include <test/debug.h>
|
||||
#include <etk/etk.h>
|
||||
#include <audio/algo/drain/Equalizer.h>
|
||||
#include <etk/os/FSNode.h>
|
||||
#include <etk/chrono.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#undef __class__
|
||||
#define __class__ "test"
|
||||
|
||||
|
||||
class Performance {
|
||||
private:
|
||||
std11::chrono::steady_clock::time_point m_timeStart;
|
||||
std11::chrono::steady_clock::time_point m_timeStop;
|
||||
std11::chrono::nanoseconds m_totalTimeProcessing;
|
||||
std11::chrono::nanoseconds m_minProcessing;
|
||||
std11::chrono::nanoseconds m_maxProcessing;
|
||||
int32_t m_totalIteration;
|
||||
public:
|
||||
Performance() :
|
||||
m_totalTimeProcessing(0),
|
||||
m_minProcessing(99999999999999LL),
|
||||
m_maxProcessing(0),
|
||||
m_totalIteration(0) {
|
||||
|
||||
}
|
||||
void tic() {
|
||||
m_timeStart = std11::chrono::steady_clock::now();
|
||||
}
|
||||
void toc() {
|
||||
m_timeStop = std11::chrono::steady_clock::now();
|
||||
std11::chrono::nanoseconds time = m_timeStop - m_timeStart;
|
||||
m_minProcessing = std::min(m_minProcessing, time);
|
||||
m_maxProcessing = std::max(m_maxProcessing, time);
|
||||
m_totalTimeProcessing += time;
|
||||
m_totalIteration++;
|
||||
|
||||
}
|
||||
|
||||
std11::chrono::nanoseconds getTotalTimeProcessing() {
|
||||
return m_totalTimeProcessing;
|
||||
}
|
||||
std11::chrono::nanoseconds getMinProcessing() {
|
||||
return m_minProcessing;
|
||||
}
|
||||
std11::chrono::nanoseconds getMaxProcessing() {
|
||||
return m_maxProcessing;
|
||||
}
|
||||
int32_t getTotalIteration() {
|
||||
return m_totalIteration;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
float performanceEqualizerType(audio::format _type) {
|
||||
std::vector<float> input;
|
||||
input.resize(1024, 0);
|
||||
std::vector<float> output;
|
||||
output.resize(input.size()*10, 0);
|
||||
double sampleRate = 48000;
|
||||
{
|
||||
double phase = 0;
|
||||
double baseCycle = 2.0*M_PI/sampleRate * 480.0;
|
||||
for (int32_t iii=0; iii<input.size(); iii++) {
|
||||
input[iii] = cos(phase) * 5.0;
|
||||
phase += baseCycle;
|
||||
if (phase >= 2*M_PI) {
|
||||
phase -= 2*M_PI;
|
||||
}
|
||||
}
|
||||
}
|
||||
APPL_INFO("Start Equalizer (1 biquad) ... " << _type);
|
||||
Performance perfo;
|
||||
audio::algo::drain::Equalizer algo;
|
||||
// configure in float
|
||||
algo.init(48000, 1, _type);
|
||||
// add basic biquad ...
|
||||
algo.addBiquad(0.01, 0.02, 0.03, 0.05, 0.06);
|
||||
// set 1024 test
|
||||
for (int32_t iii=0; iii<1024; ++iii) {
|
||||
perfo.tic();
|
||||
size_t sizeOut = output.size();
|
||||
algo.process(&output[0], &input[0], input.size());
|
||||
perfo.toc();
|
||||
usleep(1000);
|
||||
}
|
||||
APPL_INFO(" blockSize=" << input.size() << " sample");
|
||||
APPL_INFO(" min < avg < max =" << perfo.getMinProcessing().count() << "ns < "
|
||||
<< perfo.getTotalTimeProcessing().count()/perfo.getTotalIteration() << "ns < "
|
||||
<< perfo.getMaxProcessing().count() << "ns ");
|
||||
float avg = (float(((perfo.getTotalTimeProcessing().count()/perfo.getTotalIteration())*sampleRate)/double(input.size()))/1000000000.0)*100.0;
|
||||
APPL_INFO(" min < avg < max= " << (float((perfo.getMinProcessing().count()*sampleRate)/double(input.size()))/1000000000.0)*100.0 << "% < "
|
||||
<< avg << "% < "
|
||||
<< (float((perfo.getMaxProcessing().count()*sampleRate)/double(input.size()))/1000000000.0)*100.0 << "%");
|
||||
APPL_PRINT("type=" << _type << ": " << avg << "%");
|
||||
return avg;
|
||||
}
|
||||
|
||||
void performanceEqualizer() {
|
||||
performanceEqualizerType(audio::format_double);
|
||||
performanceEqualizerType(audio::format_float);
|
||||
performanceEqualizerType(audio::format_int8);
|
||||
performanceEqualizerType(audio::format_int8_on_int16);
|
||||
performanceEqualizerType(audio::format_int16);
|
||||
performanceEqualizerType(audio::format_int16_on_int32);
|
||||
performanceEqualizerType(audio::format_int32);
|
||||
performanceEqualizerType(audio::format_int32_on_int64);
|
||||
performanceEqualizerType(audio::format_int64);
|
||||
}
|
||||
|
||||
int main(int _argc, const char** _argv) {
|
||||
// the only one init for etk:
|
||||
etk::init(_argc, _argv);
|
||||
std::string inputName = "";
|
||||
std::string outputName = "output.raw";
|
||||
bool performance = false;
|
||||
bool perf = false;
|
||||
int64_t sampleRateIn = 48000;
|
||||
int64_t sampleRateOut = 48000;
|
||||
int32_t nbChan = 1;
|
||||
int32_t quality = 4;
|
||||
std::string test = "";
|
||||
for (int32_t iii=0; iii<_argc ; ++iii) {
|
||||
std::string data = _argv[iii];
|
||||
if (etk::start_with(data,"--in=")) {
|
||||
inputName = &data[5];
|
||||
} else if (etk::start_with(data,"--out=")) {
|
||||
outputName = &data[6];
|
||||
} else if (data == "--performance") {
|
||||
performance = true;
|
||||
} else if (data == "--perf") {
|
||||
perf = true;
|
||||
} else if (etk::start_with(data,"--test=")) {
|
||||
data = &data[7];
|
||||
sampleRateIn = etk::string_to_int32_t(data);
|
||||
} else if (etk::start_with(data,"--sample-rate-in=")) {
|
||||
data = &data[17];
|
||||
sampleRateIn = etk::string_to_int32_t(data);
|
||||
} else if (etk::start_with(data,"--sample-rate-out=")) {
|
||||
data = &data[18];
|
||||
sampleRateOut = etk::string_to_int32_t(data);
|
||||
} else if (etk::start_with(data,"--nb=")) {
|
||||
data = &data[5];
|
||||
nbChan = etk::string_to_int32_t(data);
|
||||
} else if (etk::start_with(data,"--quality=")) {
|
||||
data = &data[10];
|
||||
quality = etk::string_to_int32_t(data);
|
||||
} else if ( data == "-h"
|
||||
|| data == "--help") {
|
||||
APPL_PRINT("Help : ");
|
||||
APPL_PRINT(" ./xxx --fb=file.raw --mic=file.raw");
|
||||
APPL_PRINT(" --in=YYY.raw input file");
|
||||
APPL_PRINT(" --out=zzz.raw output file");
|
||||
APPL_PRINT(" --performance Generate signal to force algo to maximum process time");
|
||||
APPL_PRINT(" --perf Enable performence test (little slower but real performence test)");
|
||||
APPL_PRINT(" --test=XXXX some test availlable ...");
|
||||
APPL_PRINT(" EQUALIZER Test resampling data 16 bit mode");
|
||||
APPL_PRINT(" --sample-rate=XXXX Input signal sample rate (default 48000)");
|
||||
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
// PERFORMANCE test only ....
|
||||
if (performance == true) {
|
||||
performanceEqualizer();
|
||||
return 0;
|
||||
}
|
||||
if (test == "EQUALIZER") {
|
||||
/*
|
||||
APPL_INFO("Start resampling test ... ");
|
||||
if (inputName == "") {
|
||||
APPL_ERROR("Can not Process missing parameters...");
|
||||
exit(-1);
|
||||
}
|
||||
APPL_INFO("Read input:");
|
||||
std::vector<int16_t> inputData = etk::FSNodeReadAllDataType<int16_t>(inputName);
|
||||
APPL_INFO(" " << inputData.size() << " samples");
|
||||
// resize output :
|
||||
std::vector<int16_t> output;
|
||||
output.resize(inputData.size()*sampleRateOut/sampleRateIn+5000, 0);
|
||||
// process in chunk of 256 samples
|
||||
int32_t blockSize = 256*nbChan;
|
||||
|
||||
Performance perfo;
|
||||
audio::algo::speex::Resampler algo;
|
||||
algo.init(nbChan, sampleRateIn, sampleRateOut, quality);
|
||||
int32_t lastPourcent = -1;
|
||||
size_t outputPosition = 0;
|
||||
for (int32_t iii=0; iii<inputData.size()/blockSize; ++iii) {
|
||||
if (lastPourcent != 100*iii / (inputData.size()/blockSize)) {
|
||||
lastPourcent = 100*iii / (inputData.size()/blockSize);
|
||||
APPL_INFO("Process : " << iii*blockSize << "/" << int32_t(inputData.size()/blockSize)*blockSize << " " << lastPourcent << "/100");
|
||||
} else {
|
||||
APPL_VERBOSE("Process : " << iii*blockSize << "/" << int32_t(inputData.size()/blockSize)*blockSize);
|
||||
}
|
||||
size_t availlableSize = (output.size() - outputPosition) / nbChan;
|
||||
perfo.tic();
|
||||
algo.process(&output[outputPosition], availlableSize, &inputData[iii*blockSize], blockSize, audio::format_int16);
|
||||
if (perf == true) {
|
||||
perfo.toc();
|
||||
usleep(1000);
|
||||
}
|
||||
outputPosition += availlableSize*nbChan;
|
||||
}
|
||||
if (perf == true) {
|
||||
APPL_INFO("Performance Result: ");
|
||||
APPL_INFO(" blockSize=" << blockSize << " sample");
|
||||
APPL_INFO(" min=" << perfo.getMinProcessing().count() << " ns");
|
||||
APPL_INFO(" max=" << perfo.getMaxProcessing().count() << " ns");
|
||||
APPL_INFO(" avg=" << perfo.getTotalTimeProcessing().count()/perfo.getTotalIteration() << " ns");
|
||||
|
||||
APPL_INFO(" min=" << (float((perfo.getMinProcessing().count()*sampleRateIn)/blockSize)/1000000000.0)*100.0 << " %");
|
||||
APPL_INFO(" max=" << (float((perfo.getMaxProcessing().count()*sampleRateIn)/blockSize)/1000000000.0)*100.0 << " %");
|
||||
APPL_INFO(" avg=" << (float(((perfo.getTotalTimeProcessing().count()/perfo.getTotalIteration())*sampleRateIn)/blockSize)/1000000000.0)*100.0 << " %");
|
||||
}
|
||||
etk::FSNodeWriteAllDataType<int16_t>(outputName, output);
|
||||
*/
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user