[DEV] update algo interface and add test

This commit is contained in:
Edouard DUPIN 2015-04-20 21:56:16 +02:00
parent e912b34365
commit 715957ac75
10 changed files with 359 additions and 104 deletions

View File

@ -29,14 +29,14 @@
audio::algo::chunkware::Compressor::Compressor() : audio::algo::chunkware::Compressor::Compressor() :
AttRelEnvelope(10.0, 100.0), AttRelEnvelope(10.0, 100.0),
m_isConfigured(false), m_isConfigured(false),
m_threshdB(0.0), m_thresholddB(0.0),
m_ratio(1.0), m_ratio(1.0),
m_overThresholdEnvelopeDB(DC_OFFSET) { m_overThresholdEnvelopeDB(DC_OFFSET) {
} }
void audio::algo::chunkware::Compressor::setThreshold(double _dB) { void audio::algo::chunkware::Compressor::setThreshold(double _dB) {
m_threshdB = _dB; m_thresholddB = _dB;
} }
void audio::algo::chunkware::Compressor::setRatio(double _ratio) { void audio::algo::chunkware::Compressor::setRatio(double _ratio) {
@ -115,7 +115,7 @@ void audio::algo::chunkware::Compressor::processDouble(double* _out, const doubl
_keyLinked += DC_OFFSET; // add DC offset to avoid log(0) _keyLinked += DC_OFFSET; // add DC offset to avoid log(0)
double keydB = lin2dB(_keyLinked); // convert linear -> dB double keydB = lin2dB(_keyLinked); // convert linear -> dB
// threshold // threshold
double overdB = keydB - m_threshdB; // delta over threshold double overdB = keydB - m_thresholddB; // delta over threshold
if (overdB < 0.0) { if (overdB < 0.0) {
overdB = 0.0; overdB = 0.0;
} }

View File

@ -50,12 +50,12 @@ namespace audio {
* @brief Get list of format suported in input. * @brief Get list of format suported in input.
* @return list of supported format * @return list of supported format
*/ */
std::vector<enum audio::format> getSupportedFormat(); virtual std::vector<enum audio::format> getSupportedFormat();
/** /**
* @brief Get list of algorithm format suported. No format convertion. * @brief Get list of algorithm format suported. No format convertion.
* @return list of supported format * @return list of supported format
*/ */
std::vector<enum audio::format> getNativeSupportedFormat(); virtual std::vector<enum audio::format> getNativeSupportedFormat();
/** /**
* @brief Main input algo process. * @brief Main input algo process.
* @param[in,out] _output Output data. * @param[in,out] _output Output data.
@ -64,24 +64,24 @@ namespace audio {
* @param[in] _nbChannel Number of channel in the stream. * @param[in] _nbChannel Number of channel in the stream.
* @param[in] _format Input data format. * @param[in] _format Input data format.
*/ */
void process(void* _output, const void* _input, size_t _nbChunk, int8_t _nbChannel = 2, enum audio::format _format = audio::format_double); virtual void process(void* _output, const void* _input, size_t _nbChunk, int8_t _nbChannel = 2, enum audio::format _format = audio::format_double);
protected: protected:
virtual void processDouble(double* _out, const double* _in, int8_t _nbChannel); virtual void processDouble(double* _out, const double* _in, int8_t _nbChannel);
void processDouble(double* _out, const double* _in, int8_t _nbChannel, double _value); virtual void processDouble(double* _out, const double* _in, int8_t _nbChannel, double _value);
/* /*
void process(float* _out, const float* _in, int8_t _nbChannel); virtual void processFloat(float* _out, const float* _in, int8_t _nbChannel);
void process(int16_16_t* _out, const int16_16_t* _in, int8_t _nbChannel); virtual void process16_16(int16_16_t* _out, const int16_16_t* _in, int8_t _nbChannel);
void process(int16_32_t* _out, const int16_32_t* _in, int8_t _nbChannel); virtual void process16_32(int16_32_t* _out, const int16_32_t* _in, int8_t _nbChannel);
void process(int24_32_t* _out, const int24_32_t* _in, int8_t _nbChannel); virtual void process24_32(int24_32_t* _out, const int24_32_t* _in, int8_t _nbChannel);
void process(int32_32_t* _out, const int32_32_t* _in, int8_t _nbChannel); virtual void process32_32(int32_32_t* _out, const int32_32_t* _in, int8_t _nbChannel);
void process(int32_64_t* _out, const int32_64_t* _in, int8_t _nbChannel); virtual void process32_64(int32_64_t* _out, const int32_64_t* _in, int8_t _nbChannel);
*/ */
protected: protected:
double m_threshdB;//!< threshold (dB) double m_thresholddB;//!< threshold (dB)
public: public:
virtual void setThreshold(double _dB); virtual void setThreshold(double _dB);
virtual double getThreshold() const { virtual double getThreshold() const {
return m_threshdB; return m_thresholddB;
} }
protected: protected:
double m_ratio; //!< ratio (compression: < 1 ; expansion: > 1) double m_ratio; //!< ratio (compression: < 1 ; expansion: > 1)

View File

@ -45,7 +45,7 @@ namespace audio {
} }
public: public:
virtual void init(); virtual void init();
void processDouble(double* _out, const double* _in, int8_t _nbChannel); virtual void processDouble(double* _out, const double* _in, int8_t _nbChannel);
protected: protected:
audio::algo::chunkware::EnvelopeDetector m_averager; //!< averager audio::algo::chunkware::EnvelopeDetector m_averager; //!< averager
double m_averageSuares; //!< average of squares double m_averageSuares; //!< average of squares

View File

@ -25,45 +25,97 @@
#include <audio/algo/chunkware/Gate.h> #include <audio/algo/chunkware/Gate.h>
#include <audio/algo/chunkware/debug.h>
audio::algo::chunkware::Gate::Gate() : audio::algo::chunkware::Gate::Gate() :
AttRelEnvelope(1.0, 100.0), AttRelEnvelope(1.0, 100.0),
m_threshdB(0.0), m_thresholddB(0.0),
m_threshold(1.0), m_threshold(1.0),
m_overThresholdEnvelope(DC_OFFSET) { m_overThresholdEnvelope(DC_OFFSET) {
} }
void audio::algo::chunkware::Gate::setThresh(double _dB) { void audio::algo::chunkware::Gate::setThreshold(double _dB) {
m_threshdB = _dB; m_thresholddB = _dB;
m_threshold = dB2lin(_dB); m_threshold = dB2lin(_dB);
} }
void audio::algo::chunkware::Gate::initRuntime() {
void audio::algo::chunkware::Gate::init() {
m_overThresholdEnvelope = DC_OFFSET; m_overThresholdEnvelope = DC_OFFSET;
m_isConfigured = true;
} }
std::vector<enum audio::format> audio::algo::chunkware::Gate::getSupportedFormat() {
void audio::algo::chunkware::Gate::process(double& _in1, double& _in2) { std::vector<enum audio::format> out = getNativeSupportedFormat();
// create sidechain out.push_back(audio::format_int16);
double rect1 = fabs(_in1); // rectify input return out;
double rect2 = fabs(_in2);
/* if desired, one could use another EnvelopeDetector to smooth
* the rectified signal.
*/
double link = std::max(rect1, rect2); // link channels with greater of 2
process(_in1, _in2, link); // rest of process
} }
void audio::algo::chunkware::Gate::process(double& _in1, double& _in2, double _keyLinked) { std::vector<enum audio::format> audio::algo::chunkware::Gate::getNativeSupportedFormat() {
_keyLinked = fabs(_keyLinked); // rectify (just in case) std::vector<enum audio::format> out;
out.push_back(audio::format_double);
return out;
}
void audio::algo::chunkware::Gate::process(void* _output, const void* _input, size_t _nbChunk, int8_t _nbChannel, enum audio::format _format) {
// TODO : Check init ...
if (_nbChannel != 1) {
AA_CHUNK_ERROR("Can not compress with Other than single channel: " << _nbChannel);
}
switch (_format) {
case audio::format_int16:
{
const int16_t* input = reinterpret_cast<const int16_t*>(_input);
int16_t* output = reinterpret_cast<int16_t*>(_output);
double vals[_nbChannel];
for (size_t iii=0; iii<_nbChunk ; ++iii) {
for (int8_t kkk=0; kkk<_nbChannel ; ++kkk) {
vals[kkk] = double(input[iii*_nbChannel+kkk]) / 32768.0;
}
processDouble(vals, vals, _nbChannel);
for (int8_t kkk=0; kkk<_nbChannel ; ++kkk) {
vals[kkk] *= 32768.0;
output[iii*_nbChannel+kkk] = int16_t(std::avg(-32768.0, vals[kkk], 32767.0));
}
}
}
break;
case audio::format_double:
{
const double* input = reinterpret_cast<const double*>(_input);
double* output = reinterpret_cast<double*>(_output);
for (size_t iii=0; iii<_nbChunk ; ++iii) {
processDouble(&output[iii*_nbChannel], &input[iii*_nbChannel], _nbChannel);
//AA_CHUNK_INFO(" in=" << input[iii] << " => " << output[iii]);
}
}
break;
default:
AA_CHUNK_ERROR("Can not compress with unsupported format : " << _format);
return;
}
}
void audio::algo::chunkware::Gate::processDouble(double* _out, const double* _in, int8_t _nbChannel) {
double keyLink = 0;
// get greater value;
for (int8_t iii=0; iii<_nbChannel; ++iii) {
double absValue = std::abs(_in[iii]);
keyLink = std::max(keyLink, absValue);
}
processDouble(_out, _in, _nbChannel, keyLink);
}
void audio::algo::chunkware::Gate::processDouble(double* _out, const double* _in, int8_t _nbChannel, double _keyLinked) {
// threshold // threshold
// key over threshold (0.0 or 1.0) // key over threshold (0.0 or 1.0)
double over = double(_keyLinked > m_threshold); double over = double(_keyLinked > m_threshold);
// attack/release // attack/release
over += DC_OFFSET; // add DC offset to avoid denormal over += DC_OFFSET; // add DC offset to avoid denormal
audio::algo::chunkware::AttRelEnvelope::run(over, m_overThresholdEnvelope); // run attack/release audio::algo::chunkware::AttRelEnvelope::run(over, m_overThresholdEnvelope); // run attack/release
over = m_overThresholdEnvelope - DC_OFFSET; // subtract DC offset over = m_overThresholdEnvelope - DC_OFFSET; // subtract DC offset
/* REGARDING THE DC OFFSET: In this case, since the offset is added before /* REGARDING THE DC OFFSET: In this case, since the offset is added before
* the attack/release processes, the envelope will never fall below the offset, * the attack/release processes, the envelope will never fall below the offset,
* thereby avoiding denormals. However, to prevent the offset from causing * thereby avoiding denormals. However, to prevent the offset from causing
@ -71,6 +123,7 @@ void audio::algo::chunkware::Gate::process(double& _in1, double& _in2, double _k
* a minimum value of 0dB. * a minimum value of 0dB.
*/ */
// output gain // output gain
_in1 *= over; // apply gain reduction to input for (int8_t iii=0; iii<_nbChannel; ++iii) {
_in2 *= over; _out[iii] = _in[iii] * over;
}
} }

View File

@ -30,29 +30,61 @@
#include <etk/types.h> #include <etk/types.h>
#include <audio/algo/chunkware/AttRelEnvelope.h> #include <audio/algo/chunkware/AttRelEnvelope.h>
#include <audio/algo/chunkware/Gain.h> #include <audio/algo/chunkware/Gain.h>
#include <audio/format.h>
namespace audio { namespace audio {
namespace algo { namespace algo {
namespace chunkware { namespace chunkware {
class Gate : public AttRelEnvelope { class Gate : public AttRelEnvelope {
protected:
bool m_isConfigured;
public: public:
Gate(); Gate();
virtual ~Gate() {} virtual ~Gate() {}
public:
/**
* @brief Initialize the Algorithm
*/
virtual void init();
/**
* @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.
* @param[in] _nbChannel Number of channel in the stream.
* @param[in] _format Input data format.
*/
virtual void process(void* _output, const void* _input, size_t _nbChunk, int8_t _nbChannel = 2, enum audio::format _format = audio::format_double);
protected:
virtual void processDouble(double* _out, const double* _in, int8_t _nbChannel);
virtual void processDouble(double* _out, const double* _in, int8_t _nbChannel, double _value);
/*
virtual void processFloat(float* _out, const float* _in, int8_t _nbChannel);
virtual void process16_16(int16_16_t* _out, const int16_16_t* _in, int8_t _nbChannel);
virtual void process16_32(int16_32_t* _out, const int16_32_t* _in, int8_t _nbChannel);
virtual void process24_32(int24_32_t* _out, const int24_32_t* _in, int8_t _nbChannel);
virtual void process32_32(int32_32_t* _out, const int32_32_t* _in, int8_t _nbChannel);
virtual void process32_64(int32_64_t* _out, const int32_64_t* _in, int8_t _nbChannel);
*/
public:
// parameters // parameters
virtual void setThresh(double _dB); virtual void setThreshold(double _dB);
virtual double getThresh() const { virtual double getThreshold() const {
return m_threshdB; return m_thresholddB;
} }
// runtime
// call before runtime (in resume())
virtual void initRuntime();
// gate runtime process
void process(double& _in1, double& _in2);
// with stereo-linked key in
void process(double& _in1, double& _in2, double _keyLinked);
private: private:
// transfer function // transfer function
double m_threshdB; //!< threshold (dB) double m_thresholddB; //!< threshold (dB)
double m_threshold; //!< threshold (linear) double m_threshold; //!< threshold (linear)
// runtime variables // runtime variables
double m_overThresholdEnvelope; //!< over-threshold envelope (linear) double m_overThresholdEnvelope; //!< over-threshold envelope (linear)

View File

@ -28,7 +28,7 @@
audio::algo::chunkware::GateRms::GateRms() : audio::algo::chunkware::GateRms::GateRms() :
m_averager(5.0), m_averager(5.0),
m_averageSuares(DC_OFFSET) { m_averageSquares(DC_OFFSET) {
} }
@ -41,24 +41,26 @@ void audio::algo::chunkware::GateRms::setWindow(double _ms) {
m_averager.setTc(_ms); m_averager.setTc(_ms);
} }
void audio::algo::chunkware::GateRms::initRuntime() { void audio::algo::chunkware::GateRms::init() {
audio::algo::chunkware::Gate::initRuntime(); m_averageSquares = DC_OFFSET;
m_averageSuares = DC_OFFSET; audio::algo::chunkware::Gate::init();
} }
void audio::algo::chunkware::GateRms::process(double& _in1, double& _in2) { void audio::algo::chunkware::GateRms::processDouble(double* _out, const double* _in, int8_t _nbChannel) {
double sum = 0.0;
// create sidechain // create sidechain
double inSq1 = _in1 * _in1; // square input for (int8_t iii=0; iii<_nbChannel; ++iii) {
double inSq2 = _in2 * _in2; sum += _in[iii] * _in[iii]; // square input
double sum = inSq1 + inSq2; // power summing }
sum += DC_OFFSET; // DC offset, to prevent denormal sum += DC_OFFSET; // DC offset, to prevent denormal
m_averager.run(sum, m_averageSuares); // average of squares m_averager.run(sum, m_averageSquares); // average of squares
double rms = sqrt(m_averageSuares); // rms (sort of ...) double rms = sqrt(m_averageSquares); // rms (sort of ...)
/* REGARDING THE RMS AVERAGER: Ok, so this isn't a REAL RMS /* REGARDING THE RMS AVERAGER: Ok, so this isn't a REAL RMS
* calculation. A true RMS is an FIR moving average. This * calculation. A true RMS is an FIR moving average. This
* approximation is a 1-pole IIR. Nonetheless, in practice, * approximation is a 1-pole IIR. Nonetheless, in practice,
* and in the interest of simplicity, this method will suffice, * and in the interest of simplicity, this method will suffice,
* giving comparable results. * giving comparable results.
*/ */
audio::algo::chunkware::Gate::process(_in1, _in2, rms); // rest of process // rest of process
audio::algo::chunkware::Gate::processDouble(_out, _in, _nbChannel, rms);
} }

View File

@ -42,14 +42,13 @@ namespace audio {
virtual double getWindow() const { virtual double getWindow() const {
return m_averager.getTc(); return m_averager.getTc();
} }
// runtime process public:
// call before runtime (in resume()) virtual void init();
virtual void initRuntime(); protected:
// gate runtime process virtual void processDouble(double* _out, const double* _in, int8_t _nbChannel);
void process(double& _in1, double& _in2);
private: private:
audio::algo::chunkware::EnvelopeDetector m_averager; //!< averager audio::algo::chunkware::EnvelopeDetector m_averager; //!< averager
double m_averageSuares; //!< average of squares double m_averageSquares; //!< average of squares
}; };
} }
} }

View File

@ -29,7 +29,7 @@
audio::algo::chunkware::Limiter::Limiter() : audio::algo::chunkware::Limiter::Limiter() :
m_isConfigured(false), m_isConfigured(false),
m_threshdB(0.0), m_thresholddB(0.0),
m_threshold(1.0), m_threshold(1.0),
m_peakHold(0), m_peakHold(0),
m_peakTimer(0), m_peakTimer(0),
@ -45,7 +45,7 @@ audio::algo::chunkware::Limiter::Limiter() :
} }
void audio::algo::chunkware::Limiter::setThreshold(double _dB) { void audio::algo::chunkware::Limiter::setThreshold(double _dB) {
m_threshdB = _dB; m_thresholddB = _dB;
m_threshold = dB2lin(_dB); m_threshold = dB2lin(_dB);
} }

View File

@ -66,12 +66,12 @@ namespace audio {
* @brief Get list of format suported in input. * @brief Get list of format suported in input.
* @return list of supported format * @return list of supported format
*/ */
std::vector<enum audio::format> getSupportedFormat(); virtual std::vector<enum audio::format> getSupportedFormat();
/** /**
* @brief Get list of algorithm format suported. No format convertion. * @brief Get list of algorithm format suported. No format convertion.
* @return list of supported format * @return list of supported format
*/ */
std::vector<enum audio::format> getNativeSupportedFormat(); virtual std::vector<enum audio::format> getNativeSupportedFormat();
/** /**
* @brief Main input algo process. * @brief Main input algo process.
* @param[in,out] _output Output data. * @param[in,out] _output Output data.
@ -80,23 +80,23 @@ namespace audio {
* @param[in] _nbChannel Number of channel in the stream. * @param[in] _nbChannel Number of channel in the stream.
* @param[in] _format Input data format. * @param[in] _format Input data format.
*/ */
void process(void* _output, const void* _input, size_t _nbChunk, int8_t _nbChannel = 2, enum audio::format _format = audio::format_double); virtual void process(void* _output, const void* _input, size_t _nbChunk, int8_t _nbChannel = 2, enum audio::format _format = audio::format_double);
protected: protected:
void processDouble(double* _out, const double* _in, int8_t _nbChannel); virtual void processDouble(double* _out, const double* _in, int8_t _nbChannel);
/* /*
void process(float* _out, const float* _in, int8_t _nbChannel); virtual void processFloat(float* _out, const float* _in, int8_t _nbChannel);
void process(int16_16_t* _out, const int16_16_t* _in, int8_t _nbChannel); virtual void process16_16(int16_16_t* _out, const int16_16_t* _in, int8_t _nbChannel);
void process(int16_32_t* _out, const int16_32_t* _in, int8_t _nbChannel); virtual void process16_32(int16_32_t* _out, const int16_32_t* _in, int8_t _nbChannel);
void process(int24_32_t* _out, const int24_32_t* _in, int8_t _nbChannel); virtual void process24_32(int24_32_t* _out, const int24_32_t* _in, int8_t _nbChannel);
void process(int32_32_t* _out, const int32_32_t* _in, int8_t _nbChannel); virtual void process32_32(int32_32_t* _out, const int32_32_t* _in, int8_t _nbChannel);
void process(int32_64_t* _out, const int32_64_t* _in, int8_t _nbChannel); virtual void process32_64(int32_64_t* _out, const int32_64_t* _in, int8_t _nbChannel);
*/ */
protected: protected:
double m_threshdB; //!< threshold (dB) double m_thresholddB; //!< threshold (dB)
public: public:
virtual void setThreshold(double _dB); virtual void setThreshold(double _dB);
virtual double getThreshold() const { virtual double getThreshold() const {
return m_threshdB; return m_thresholddB;
} }
protected: protected:

View File

@ -8,6 +8,7 @@
#include <etk/etk.h> #include <etk/etk.h>
#include <audio/algo/chunkware/Compressor.h> #include <audio/algo/chunkware/Compressor.h>
#include <audio/algo/chunkware/Limiter.h> #include <audio/algo/chunkware/Limiter.h>
#include <audio/algo/chunkware/Gate.h>
#include <etk/os/FSNode.h> #include <etk/os/FSNode.h>
#include <etk/chrono.h> #include <etk/chrono.h>
@ -37,16 +38,190 @@ static std::vector<int16_t> convert(const std::vector<double>& _data) {
return out; return out;
} }
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;
}
};
void performanceCompressor() {
std::vector<double> input;
input.resize(8192, 0);
std::vector<double> output;
output.resize(8192, 0);
double sampleRate = 48000.0;
{
double phase = 0;
double baseCycle = 2.0*M_PI/sampleRate * 1280.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_PRINT("Start compressor performance ...");
Performance perfo;
audio::algo::chunkware::Compressor algo;
algo.setThreshold(-10);
algo.setRatio(-5);
int32_t lastPourcent = -1;
for (int32_t iii=0; iii<4096; ++iii) {
perfo.tic();
algo.process(&output[0], &input[0], input.size(), 1, audio::format_double);
perfo.toc();
usleep(1000);
}
APPL_INFO("Performance Compressor (double): ");
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 ");
APPL_INFO(" min < avg < max= " << (float((perfo.getMinProcessing().count()*sampleRate)/double(input.size()))/1000000000.0)*100.0 << "% < "
<< (float(((perfo.getTotalTimeProcessing().count()/perfo.getTotalIteration())*sampleRate)/double(input.size()))/1000000000.0)*100.0 << "% < "
<< (float((perfo.getMaxProcessing().count()*sampleRate)/double(input.size()))/1000000000.0)*100.0 << "%");
}
void performanceLimiter() {
std::vector<double> input;
input.resize(8192, 0);
std::vector<double> output;
output.resize(8192, 0);
double sampleRate = 48000.0;
{
double phase = 0;
double baseCycle = 2.0*M_PI/sampleRate * 1280.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_PRINT("Start Limiter performance ...");
Performance perfo;
audio::algo::chunkware::Limiter algo;
algo.setSampleRate(48000);
algo.setThreshold(0);
algo.setAttack(0.1);
algo.setRelease(2);
algo.init(1);
int32_t lastPourcent = -1;
for (int32_t iii=0; iii<4096; ++iii) {
perfo.tic();
algo.process(&output[0], &input[0], input.size(), 1, audio::format_double);
perfo.toc();
usleep(1000);
}
APPL_INFO("Performance Limiter (double): ");
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 ");
APPL_INFO(" min < avg < max = " << (float((perfo.getMinProcessing().count()*sampleRate)/double(input.size()))/1000000000.0)*100.0 << "% < "
<< (float(((perfo.getTotalTimeProcessing().count()/perfo.getTotalIteration())*sampleRate)/double(input.size()))/1000000000.0)*100.0 << "% < "
<< (float((perfo.getMaxProcessing().count()*sampleRate)/double(input.size()))/1000000000.0)*100.0 << "%");
}
void performanceGate() {
std::vector<double> input;
input.resize(8192, 0);
std::vector<double> output;
output.resize(8192, 0);
double sampleRate = 48000.0;
{
double phase = 0;
double baseCycle = 2.0*M_PI/sampleRate * 1280.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_PRINT("Start Gate performance ...");
Performance perfo;
audio::algo::chunkware::Gate algo;
algo.setSampleRate(48000);
algo.setThreshold(0);
algo.setAttack(0.1);
algo.setRelease(2);
algo.init();
int32_t lastPourcent = -1;
for (int32_t iii=0; iii<4096; ++iii) {
perfo.tic();
algo.process(&output[0], &input[0], input.size(), 1, audio::format_double);
perfo.toc();
usleep(1000);
}
APPL_INFO("Performance Gate (double): ");
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 ");
APPL_INFO(" min < avg < max = " << (float((perfo.getMinProcessing().count()*sampleRate)/double(input.size()))/1000000000.0)*100.0 << "% < "
<< (float(((perfo.getTotalTimeProcessing().count()/perfo.getTotalIteration())*sampleRate)/double(input.size()))/1000000000.0)*100.0 << "% < "
<< (float((perfo.getMaxProcessing().count()*sampleRate)/double(input.size()))/1000000000.0)*100.0 << "%");
}
int main(int _argc, const char** _argv) { int main(int _argc, const char** _argv) {
// the only one init for etk: // the only one init for etk:
etk::init(_argc, _argv); etk::init(_argc, _argv);
std::string inputName = ""; std::string inputName = "";
bool performance = false;
bool perf = false; bool perf = false;
int64_t sampleRate = 48000; int64_t sampleRate = 48000;
for (int32_t iii=0; iii<_argc ; ++iii) { for (int32_t iii=0; iii<_argc ; ++iii) {
std::string data = _argv[iii]; std::string data = _argv[iii];
if (etk::start_with(data,"--in=")) { if (etk::start_with(data,"--in=")) {
inputName = &data[5]; inputName = &data[5];
} else if (data == "--performance") {
performance = true;
} else if (data == "--perf") { } else if (data == "--perf") {
perf = true; perf = true;
} else if (etk::start_with(data,"--sample-rate=")) { } else if (etk::start_with(data,"--sample-rate=")) {
@ -57,11 +232,19 @@ int main(int _argc, const char** _argv) {
APPL_PRINT("Help : "); APPL_PRINT("Help : ");
APPL_PRINT(" ./xxx --fb=file.raw --mic=file.raw"); APPL_PRINT(" ./xxx --fb=file.raw --mic=file.raw");
APPL_PRINT(" --in=YYY.raw inout file"); APPL_PRINT(" --in=YYY.raw inout 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(" --perf Enable performence test (little slower but real performence test)");
APPL_PRINT(" --sample-rate=XXXX Signal sample rate (default 48000)"); APPL_PRINT(" --sample-rate=XXXX Signal sample rate (default 48000)");
exit(0); exit(0);
} }
} }
// PERFORMANCE test only ....
if (performance == true) {
performanceCompressor();
performanceLimiter();
performanceGate();
return 0;
}
if (inputName == "") { if (inputName == "") {
APPL_ERROR("Can not Process missing parameters..."); APPL_ERROR("Can not Process missing parameters...");
exit(-1); exit(-1);
@ -74,12 +257,8 @@ int main(int _argc, const char** _argv) {
output.resize(inputData.size(), 0); output.resize(inputData.size(), 0);
// process in chunk of 256 samples // process in chunk of 256 samples
int32_t blockSize = 256; int32_t blockSize = 256;
// for CPU consomtion:
std11::chrono::nanoseconds totalTimeProcessing(0);
std11::chrono::nanoseconds minProcessing(99999999999999LL);
std11::chrono::nanoseconds maxProcessing(0);
int32_t totalIteration = 0;
Performance perfo;
/* /*
audio::algo::chunkware::Compressor algo; audio::algo::chunkware::Compressor algo;
algo.setThreshold(-10); algo.setThreshold(-10);
@ -92,15 +271,10 @@ int main(int _argc, const char** _argv) {
} else { } else {
APPL_VERBOSE("Process : " << iii*blockSize << "/" << int32_t(output.size()/blockSize)*blockSize); APPL_VERBOSE("Process : " << iii*blockSize << "/" << int32_t(output.size()/blockSize)*blockSize);
} }
std11::chrono::steady_clock::time_point timeStart = std11::chrono::steady_clock::now(); perfo.tic();
algo.process(audio::format_double, &output[iii*blockSize], &inputData[iii*blockSize], blockSize, 1); algo.process(audio::format_double, &output[iii*blockSize], &inputData[iii*blockSize], blockSize, 1);
if (perf == true) { if (perf == true) {
std11::chrono::steady_clock::time_point timeEnd = std11::chrono::steady_clock::now(); perfo.toc();
std11::chrono::nanoseconds time = timeEnd - timeStart;
minProcessing = std::min(minProcessing, time);
maxProcessing = std::max(maxProcessing, time);
totalTimeProcessing += time;
totalIteration++;
usleep(1000); usleep(1000);
} }
} }
@ -119,15 +293,10 @@ int main(int _argc, const char** _argv) {
} else { } else {
APPL_VERBOSE("Process : " << iii*blockSize << "/" << int32_t(output.size()/blockSize)*blockSize); APPL_VERBOSE("Process : " << iii*blockSize << "/" << int32_t(output.size()/blockSize)*blockSize);
} }
std11::chrono::steady_clock::time_point timeStart = std11::chrono::steady_clock::now(); perfo.tic();
algo.process(&output[iii*blockSize], &inputData[iii*blockSize], blockSize, 1, audio::format_double); algo.process(&output[iii*blockSize], &inputData[iii*blockSize], blockSize, 1, audio::format_double);
if (perf == true) { if (perf == true) {
std11::chrono::steady_clock::time_point timeEnd = std11::chrono::steady_clock::now(); perfo.toc();
std11::chrono::nanoseconds time = timeEnd - timeStart;
minProcessing = std::min(minProcessing, time);
maxProcessing = std::max(maxProcessing, time);
totalTimeProcessing += time;
totalIteration++;
usleep(1000); usleep(1000);
} }
} }
@ -136,13 +305,13 @@ int main(int _argc, const char** _argv) {
if (perf == true) { if (perf == true) {
APPL_INFO("Performance Result: "); APPL_INFO("Performance Result: ");
APPL_INFO(" blockSize=" << blockSize << " sample"); APPL_INFO(" blockSize=" << blockSize << " sample");
APPL_INFO(" min=" << minProcessing.count() << " ns"); APPL_INFO(" min=" << perfo.getMinProcessing().count() << " ns");
APPL_INFO(" max=" << maxProcessing.count() << " ns"); APPL_INFO(" max=" << perfo.getMaxProcessing().count() << " ns");
APPL_INFO(" avg=" << totalTimeProcessing.count()/totalIteration << " ns"); APPL_INFO(" avg=" << perfo.getTotalTimeProcessing().count()/perfo.getTotalIteration() << " ns");
APPL_INFO(" min=" << (float((minProcessing.count()*sampleRate)/blockSize)/1000000000.0)*100.0 << " %"); APPL_INFO(" min=" << (float((perfo.getMinProcessing().count()*sampleRate)/blockSize)/1000000000.0)*100.0 << " %");
APPL_INFO(" max=" << (float((maxProcessing.count()*sampleRate)/blockSize)/1000000000.0)*100.0 << " %"); APPL_INFO(" max=" << (float((perfo.getMaxProcessing().count()*sampleRate)/blockSize)/1000000000.0)*100.0 << " %");
APPL_INFO(" avg=" << (float(((totalTimeProcessing.count()/totalIteration)*sampleRate)/blockSize)/1000000000.0)*100.0 << " %"); APPL_INFO(" avg=" << (float(((perfo.getTotalTimeProcessing().count()/perfo.getTotalIteration())*sampleRate)/blockSize)/1000000000.0)*100.0 << " %");
} }
etk::FSNodeWriteAllDataType<int16_t>("output.raw", convert(output)); etk::FSNodeWriteAllDataType<int16_t>("output.raw", convert(output));