[DEV] basic set of input function with _
This commit is contained in:
parent
4d3296a9e1
commit
f9203782e2
@ -26,25 +26,25 @@
|
|||||||
|
|
||||||
#include <audio/algo/chunkware/AttRelEnvelope.h>
|
#include <audio/algo/chunkware/AttRelEnvelope.h>
|
||||||
|
|
||||||
audio::algo::chunkware::AttRelEnvelope::AttRelEnvelope(double m_attackms, double m_releasems, double sampleRate) :
|
audio::algo::chunkware::AttRelEnvelope::AttRelEnvelope(double _attackms, double _releasems, double _sampleRate) :
|
||||||
m_attack(m_attackms, sampleRate),
|
m_attack(_attackms, _sampleRate),
|
||||||
m_release(m_releasems, sampleRate) {
|
m_release(_releasems, _sampleRate) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------
|
//-------------------------------------------------------------
|
||||||
void audio::algo::chunkware::AttRelEnvelope::setAttack(double ms) {
|
void audio::algo::chunkware::AttRelEnvelope::setAttack(double _ms) {
|
||||||
m_attack.setTc(ms);
|
m_attack.setTc(_ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------
|
//-------------------------------------------------------------
|
||||||
void audio::algo::chunkware::AttRelEnvelope::setRelease(double ms) {
|
void audio::algo::chunkware::AttRelEnvelope::setRelease(double _ms) {
|
||||||
m_release.setTc(ms);
|
m_release.setTc(_ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------
|
//-------------------------------------------------------------
|
||||||
void audio::algo::chunkware::AttRelEnvelope::setSampleRate(double sampleRate) {
|
void audio::algo::chunkware::AttRelEnvelope::setSampleRate(double _sampleRate) {
|
||||||
m_attack.setSampleRate(sampleRate);
|
m_attack.setSampleRate(_sampleRate);
|
||||||
m_release.setSampleRate(sampleRate);
|
m_release.setSampleRate(_sampleRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,48 +32,45 @@
|
|||||||
namespace audio {
|
namespace audio {
|
||||||
namespace algo {
|
namespace algo {
|
||||||
namespace chunkware {
|
namespace chunkware {
|
||||||
//-------------------------------------------------------------
|
|
||||||
// attack/release envelope
|
|
||||||
//-------------------------------------------------------------
|
|
||||||
class AttRelEnvelope {
|
class AttRelEnvelope {
|
||||||
public:
|
public:
|
||||||
AttRelEnvelope(double m_attackms = 10.0,
|
AttRelEnvelope(double _attackms = 10.0,
|
||||||
double m_releasems = 100.0,
|
double _releasems = 100.0,
|
||||||
double sampleRate = 44100.0);
|
double _sampleRate = 44100.0);
|
||||||
virtual ~AttRelEnvelope() {}
|
virtual ~AttRelEnvelope() {}
|
||||||
// attack time constant
|
// attack time constant
|
||||||
virtual void setAttack(double ms);
|
virtual void setAttack(double _ms);
|
||||||
virtual double getAttack() const {
|
virtual double getAttack() const {
|
||||||
return m_attack.getTc();
|
return m_attack.getTc();
|
||||||
}
|
}
|
||||||
// release time constant
|
// release time constant
|
||||||
virtual void setRelease(double ms);
|
virtual void setRelease(double _ms);
|
||||||
virtual double getRelease() const {
|
virtual double getRelease() const {
|
||||||
return m_release.getTc();
|
return m_release.getTc();
|
||||||
}
|
}
|
||||||
// sample rate dependencies
|
// sample rate dependencies
|
||||||
virtual void setSampleRate(double sampleRate);
|
virtual void setSampleRate(double _sampleRate);
|
||||||
virtual double getSampleRate() const {
|
virtual double getSampleRate() const {
|
||||||
return m_attack.getSampleRate();
|
return m_attack.getSampleRate();
|
||||||
}
|
}
|
||||||
// runtime function
|
// runtime function
|
||||||
void run(double in, double &state) {
|
void run(double _in, double& _state) {
|
||||||
/* assumes that:
|
/* assumes that:
|
||||||
* positive delta = attack
|
* positive delta = attack
|
||||||
* negative delta = release
|
* negative delta = release
|
||||||
* good for linear & log values
|
* good for linear & log values
|
||||||
*/
|
*/
|
||||||
if (in > state) {
|
if (_in > _state) {
|
||||||
// attack
|
// attack
|
||||||
m_attack.run(in, state);
|
m_attack.run(_in, _state);
|
||||||
} else {
|
} else {
|
||||||
// release
|
// release
|
||||||
m_release.run(in, state);
|
m_release.run(_in, _state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
EnvelopeDetector m_attack;
|
audio::algo::chunkware::EnvelopeDetector m_attack;
|
||||||
EnvelopeDetector m_release;
|
audio::algo::chunkware::EnvelopeDetector m_release;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,42 +34,42 @@ audio::algo::chunkware::Compresssor::Compresssor() :
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void audio::algo::chunkware::Compresssor::setThresh(double dB) {
|
void audio::algo::chunkware::Compresssor::setThresh(double _dB) {
|
||||||
m_threshdB = dB;
|
m_threshdB = _dB;
|
||||||
}
|
}
|
||||||
|
|
||||||
void audio::algo::chunkware::Compresssor::setRatio(double ratio) {
|
void audio::algo::chunkware::Compresssor::setRatio(double _ratio) {
|
||||||
AA_CHUNK_ASSERT(ratio > 0.0, "input function error");
|
AA_CHUNK_ASSERT(_ratio > 0.0, "input function error");
|
||||||
m_ratio = ratio;
|
m_ratio = _ratio;
|
||||||
}
|
}
|
||||||
|
|
||||||
void audio::algo::chunkware::Compresssor::initRuntime() {
|
void audio::algo::chunkware::Compresssor::initRuntime() {
|
||||||
m_overThresholdEnvelopeDB = DC_OFFSET;
|
m_overThresholdEnvelopeDB = DC_OFFSET;
|
||||||
}
|
}
|
||||||
|
|
||||||
void audio::algo::chunkware::Compresssor::process(double &in1, double &in2) {
|
void audio::algo::chunkware::Compresssor::process(double& _in1, double& _in2) {
|
||||||
// create sidechain
|
// create sidechain
|
||||||
double rect1 = fabs(in1); // rectify input
|
double rect1 = fabs(_in1); // rectify input
|
||||||
double rect2 = fabs(in2);
|
double rect2 = fabs(_in2);
|
||||||
/* if desired, one could use another EnvelopeDetector to smooth
|
/* if desired, one could use another EnvelopeDetector to smooth
|
||||||
* the rectified signal.
|
* the rectified signal.
|
||||||
*/
|
*/
|
||||||
double link = std::max(rect1, rect2); // link channels with greater of 2
|
double link = std::max(rect1, rect2); // link channels with greater of 2
|
||||||
process(in1, in2, link); // rest of process
|
process(_in1, _in2, link); // rest of process
|
||||||
}
|
}
|
||||||
|
|
||||||
void audio::algo::chunkware::Compresssor::process(double &in1, double &in2, double keyLinked) {
|
void audio::algo::chunkware::Compresssor::process(double& _in1, double& _in2, double _keyLinked) {
|
||||||
keyLinked = fabs(keyLinked); // rectify (just in case)
|
_keyLinked = fabs(_keyLinked); // rectify (just in case)
|
||||||
// convert key to dB
|
// convert key to dB
|
||||||
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_threshdB; // delta over threshold
|
||||||
if (overdB < 0.0)
|
if (overdB < 0.0)
|
||||||
overdB = 0.0;
|
overdB = 0.0;
|
||||||
// attack/release
|
// attack/release
|
||||||
overdB += DC_OFFSET; // add DC offset to avoid denormal
|
overdB += DC_OFFSET; // add DC offset to avoid denormal
|
||||||
AttRelEnvelope::run(overdB, m_overThresholdEnvelopeDB); // run attack/release envelope
|
audio::algo::chunkware::AttRelEnvelope::run(overdB, m_overThresholdEnvelopeDB); // run attack/release envelope
|
||||||
overdB = m_overThresholdEnvelopeDB - DC_OFFSET; // subtract DC offset
|
overdB = m_overThresholdEnvelopeDB - 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,
|
||||||
@ -81,7 +81,7 @@ void audio::algo::chunkware::Compresssor::process(double &in1, double &in2, doub
|
|||||||
double gr = overdB * (m_ratio - 1.0); // gain reduction (dB)
|
double gr = overdB * (m_ratio - 1.0); // gain reduction (dB)
|
||||||
gr = dB2lin(gr); // convert dB -> linear
|
gr = dB2lin(gr); // convert dB -> linear
|
||||||
// output gain
|
// output gain
|
||||||
in1 *= gr; // apply gain reduction to input
|
_in1 *= gr; // apply gain reduction to input
|
||||||
in2 *= gr;
|
_in2 *= gr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,13 +34,13 @@
|
|||||||
namespace audio {
|
namespace audio {
|
||||||
namespace algo {
|
namespace algo {
|
||||||
namespace chunkware {
|
namespace chunkware {
|
||||||
class Compresssor : public AttRelEnvelope {
|
class Compresssor : public audio::algo::chunkware::AttRelEnvelope {
|
||||||
public:
|
public:
|
||||||
Compresssor();
|
Compresssor();
|
||||||
virtual ~Compresssor() {}
|
virtual ~Compresssor() {}
|
||||||
// parameters
|
// parameters
|
||||||
virtual void setThresh(double dB);
|
virtual void setThresh(double _dB);
|
||||||
virtual void setRatio(double dB);
|
virtual void setRatio(double _dB);
|
||||||
virtual double getThresh() const {
|
virtual double getThresh() const {
|
||||||
return m_threshdB;
|
return m_threshdB;
|
||||||
}
|
}
|
||||||
@ -51,9 +51,9 @@ namespace audio {
|
|||||||
// call before runtime (in resume())
|
// call before runtime (in resume())
|
||||||
virtual void initRuntime();
|
virtual void initRuntime();
|
||||||
// compressor runtime process
|
// compressor runtime process
|
||||||
void process(double &in1, double &in2);
|
void process(double& _in1, double& _in2);
|
||||||
// with stereo-linked key in
|
// with stereo-linked key in
|
||||||
void process(double &in1, double &in2, double keyLinked);
|
void process(double& _in1, double& _in2, double _keyLinked);
|
||||||
private:
|
private:
|
||||||
// transfer function
|
// transfer function
|
||||||
double m_threshdB;//!< threshold (dB)
|
double m_threshdB;//!< threshold (dB)
|
||||||
|
@ -33,13 +33,13 @@ audio::algo::chunkware::CompresssorRms::CompresssorRms() :
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void audio::algo::chunkware::CompresssorRms::setSampleRate(double sampleRate) {
|
void audio::algo::chunkware::CompresssorRms::setSampleRate(double _sampleRate) {
|
||||||
audio::algo::chunkware::Compresssor::setSampleRate(sampleRate);
|
audio::algo::chunkware::Compresssor::setSampleRate(_sampleRate);
|
||||||
m_averager.setSampleRate(sampleRate);
|
m_averager.setSampleRate(_sampleRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
void audio::algo::chunkware::CompresssorRms::setWindow(double ms) {
|
void audio::algo::chunkware::CompresssorRms::setWindow(double _ms) {
|
||||||
m_averager.setTc(ms);
|
m_averager.setTc(_ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
void audio::algo::chunkware::CompresssorRms::initRuntime() {
|
void audio::algo::chunkware::CompresssorRms::initRuntime() {
|
||||||
@ -47,10 +47,10 @@ void audio::algo::chunkware::CompresssorRms::initRuntime() {
|
|||||||
m_averageSuares = DC_OFFSET;
|
m_averageSuares = DC_OFFSET;
|
||||||
}
|
}
|
||||||
|
|
||||||
void audio::algo::chunkware::CompresssorRms::process(double &in1, double &in2) {
|
void audio::algo::chunkware::CompresssorRms::process(double& _in1, double& _in2) {
|
||||||
// create sidechain
|
// create sidechain
|
||||||
double inSq1 = in1 * in1; // square input
|
double inSq1 = _in1 * _in1; // square input
|
||||||
double inSq2 = in2 * in2;
|
double inSq2 = _in2 * _in2;
|
||||||
double sum = inSq1 + inSq2; // power summing
|
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_averageSuares); // average of squares
|
||||||
@ -62,5 +62,5 @@ void audio::algo::chunkware::CompresssorRms::process(double &in1, double &in2) {
|
|||||||
* giving comparable results.
|
* giving comparable results.
|
||||||
*/
|
*/
|
||||||
// rest of process
|
// rest of process
|
||||||
Compresssor::process(in1, in2, rms);
|
audio::algo::chunkware::Compresssor::process(_in1, _in2, rms);
|
||||||
}
|
}
|
||||||
|
@ -32,20 +32,22 @@
|
|||||||
namespace audio {
|
namespace audio {
|
||||||
namespace algo {
|
namespace algo {
|
||||||
namespace chunkware {
|
namespace chunkware {
|
||||||
class CompresssorRms : public Compresssor {
|
class CompresssorRms : public audio::algo::chunkware::Compresssor {
|
||||||
public:
|
public:
|
||||||
CompresssorRms();
|
CompresssorRms();
|
||||||
virtual ~CompresssorRms() {}
|
virtual ~CompresssorRms() {}
|
||||||
// sample rate
|
// sample rate
|
||||||
virtual void setSampleRate(double sampleRate);
|
virtual void setSampleRate(double _sampleRate);
|
||||||
// RMS window
|
// RMS window
|
||||||
virtual void setWindow(double ms);
|
virtual void setWindow(double _ms);
|
||||||
virtual double getWindow() const { return m_averager.getTc(); }
|
virtual double getWindow() const {
|
||||||
|
return m_averager.getTc();
|
||||||
|
}
|
||||||
// runtime process
|
// runtime process
|
||||||
virtual void initRuntime(); // call before runtime (in resume())
|
virtual void initRuntime(); // call before runtime (in resume())
|
||||||
void process(double &in1, double &in2); // compressor runtime process
|
void process(double& _in1, double& _in2); // compressor runtime process
|
||||||
protected:
|
protected:
|
||||||
EnvelopeDetector m_averager; //!< averager
|
audio::algo::chunkware::EnvelopeDetector m_averager; //!< averager
|
||||||
double m_averageSuares; //!< average of squares
|
double m_averageSuares; //!< average of squares
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -27,23 +27,23 @@
|
|||||||
#include <audio/algo/chunkware/debug.h>
|
#include <audio/algo/chunkware/debug.h>
|
||||||
#include <audio/algo/chunkware/EnvelopeDetector.h>
|
#include <audio/algo/chunkware/EnvelopeDetector.h>
|
||||||
|
|
||||||
audio::algo::chunkware::EnvelopeDetector::EnvelopeDetector(double ms, double sampleRate) {
|
audio::algo::chunkware::EnvelopeDetector::EnvelopeDetector(double _ms, double _sampleRate) {
|
||||||
AA_CHUNK_ASSERT(sampleRate > 0.0, "input function error");
|
AA_CHUNK_ASSERT(_sampleRate > 0.0, "input function error");
|
||||||
AA_CHUNK_ASSERT(ms > 0.0, "input function error");
|
AA_CHUNK_ASSERT(_ms > 0.0, "input function error");
|
||||||
m_sampleRate = sampleRate;
|
m_sampleRate = _sampleRate;
|
||||||
m_timeMs = ms;
|
m_timeMs = _ms;
|
||||||
setCoef();
|
setCoef();
|
||||||
}
|
}
|
||||||
|
|
||||||
void audio::algo::chunkware::EnvelopeDetector::setTc(double ms) {
|
void audio::algo::chunkware::EnvelopeDetector::setTc(double _ms) {
|
||||||
AA_CHUNK_ASSERT(ms > 0.0, "input function error");
|
AA_CHUNK_ASSERT(_ms > 0.0, "input function error");
|
||||||
m_timeMs = ms;
|
m_timeMs = _ms;
|
||||||
setCoef();
|
setCoef();
|
||||||
}
|
}
|
||||||
|
|
||||||
void audio::algo::chunkware::EnvelopeDetector::setSampleRate(double sampleRate) {
|
void audio::algo::chunkware::EnvelopeDetector::setSampleRate(double _sampleRate) {
|
||||||
AA_CHUNK_ASSERT(sampleRate > 0.0, "input function error");
|
AA_CHUNK_ASSERT(_sampleRate > 0.0, "input function error");
|
||||||
m_sampleRate = sampleRate;
|
m_sampleRate = _sampleRate;
|
||||||
setCoef();
|
setCoef();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,34 +32,28 @@
|
|||||||
namespace audio {
|
namespace audio {
|
||||||
namespace algo {
|
namespace algo {
|
||||||
namespace chunkware {
|
namespace chunkware {
|
||||||
//-------------------------------------------------------------
|
|
||||||
// DC offset (to prevent denormal)
|
|
||||||
//-------------------------------------------------------------
|
|
||||||
// USE:
|
// USE:
|
||||||
// 1. init envelope state to DC_OFFSET before processing
|
// 1. init envelope state to DC_OFFSET before processing
|
||||||
// 2. add to input before envelope runtime function
|
// 2. add to input before envelope runtime function
|
||||||
static const double DC_OFFSET = 1.0E-25;
|
static const double DC_OFFSET = 1.0E-25;
|
||||||
//-------------------------------------------------------------
|
|
||||||
// envelope detector
|
|
||||||
//-------------------------------------------------------------
|
|
||||||
class EnvelopeDetector {
|
class EnvelopeDetector {
|
||||||
public:
|
public:
|
||||||
EnvelopeDetector(double ms = 1.0,
|
EnvelopeDetector(double _ms = 1.0,
|
||||||
double sampleRate = 44100.0);
|
double _sampleRate = 44100.0);
|
||||||
virtual ~EnvelopeDetector() {}
|
virtual ~EnvelopeDetector() {}
|
||||||
// time constant
|
// time constant
|
||||||
virtual void setTc(double ms);
|
virtual void setTc(double _ms);
|
||||||
virtual double getTc() const {
|
virtual double getTc() const {
|
||||||
return m_timeMs;
|
return m_timeMs;
|
||||||
}
|
}
|
||||||
// sample rate
|
// sample rate
|
||||||
virtual void setSampleRate(double sampleRate);
|
virtual void setSampleRate(double _sampleRate);
|
||||||
virtual double getSampleRate() const {
|
virtual double getSampleRate() const {
|
||||||
return m_sampleRate;
|
return m_sampleRate;
|
||||||
}
|
}
|
||||||
// runtime function
|
// runtime function
|
||||||
void run(double in, double &state) {
|
void run(double _in, double& _state) {
|
||||||
state = in + m_coefficient * (state - in);
|
_state = _in + m_coefficient * (_state - _in);
|
||||||
}
|
}
|
||||||
protected:
|
protected:
|
||||||
double m_sampleRate; //!< sample rate
|
double m_sampleRate; //!< sample rate
|
||||||
|
@ -33,18 +33,15 @@
|
|||||||
namespace audio {
|
namespace audio {
|
||||||
namespace algo {
|
namespace algo {
|
||||||
namespace chunkware {
|
namespace chunkware {
|
||||||
//-------------------------------------------------------------
|
|
||||||
// gain functions
|
|
||||||
//-------------------------------------------------------------
|
|
||||||
// linear -> dB conversion
|
// linear -> dB conversion
|
||||||
static inline double lin2dB(double lin) {
|
static inline double lin2dB(double _lin) {
|
||||||
static const double LOG_2_DB = 8.6858896380650365530225783783321; // 20 / ln(10)
|
static const double LOG_2_DB = 8.6858896380650365530225783783321; // 20 / ln(10)
|
||||||
return log(lin) * LOG_2_DB;
|
return log(_lin) * LOG_2_DB;
|
||||||
}
|
}
|
||||||
// dB -> linear conversion
|
// dB -> linear conversion
|
||||||
static inline double dB2lin(double dB) {
|
static inline double dB2lin(double _dB) {
|
||||||
static const double DB_2_LOG = 0.11512925464970228420089957273422; // ln(10) / 20
|
static const double DB_2_LOG = 0.11512925464970228420089957273422; // ln(10) / 20
|
||||||
return exp(dB * DB_2_LOG);
|
return exp(_dB * DB_2_LOG);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,9 +34,9 @@ audio::algo::chunkware::Gate::Gate() :
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void audio::algo::chunkware::Gate::setThresh(double dB) {
|
void audio::algo::chunkware::Gate::setThresh(double _dB) {
|
||||||
m_threshdB = dB;
|
m_threshdB = _dB;
|
||||||
m_threshold = dB2lin(dB);
|
m_threshold = dB2lin(_dB);
|
||||||
}
|
}
|
||||||
|
|
||||||
void audio::algo::chunkware::Gate::initRuntime() {
|
void audio::algo::chunkware::Gate::initRuntime() {
|
||||||
@ -44,25 +44,25 @@ void audio::algo::chunkware::Gate::initRuntime() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void audio::algo::chunkware::Gate::process(double &in1, double &in2) {
|
void audio::algo::chunkware::Gate::process(double& _in1, double& _in2) {
|
||||||
// create sidechain
|
// create sidechain
|
||||||
double rect1 = fabs(in1); // rectify input
|
double rect1 = fabs(_in1); // rectify input
|
||||||
double rect2 = fabs(in2);
|
double rect2 = fabs(_in2);
|
||||||
/* if desired, one could use another EnvelopeDetector to smooth
|
/* if desired, one could use another EnvelopeDetector to smooth
|
||||||
* the rectified signal.
|
* the rectified signal.
|
||||||
*/
|
*/
|
||||||
double link = std::max(rect1, rect2); // link channels with greater of 2
|
double link = std::max(rect1, rect2); // link channels with greater of 2
|
||||||
process(in1, in2, link); // rest of process
|
process(_in1, _in2, link); // rest of process
|
||||||
}
|
}
|
||||||
|
|
||||||
void audio::algo::chunkware::Gate::process(double &in1, double &in2, double keyLinked) {
|
void audio::algo::chunkware::Gate::process(double& _in1, double& _in2, double _keyLinked) {
|
||||||
keyLinked = fabs(keyLinked); // rectify (just in case)
|
_keyLinked = fabs(_keyLinked); // rectify (just in case)
|
||||||
// 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
|
||||||
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,
|
||||||
@ -71,6 +71,6 @@ void audio::algo::chunkware::Gate::process(double &in1, double &in2, double keyL
|
|||||||
* a minimum value of 0dB.
|
* a minimum value of 0dB.
|
||||||
*/
|
*/
|
||||||
// output gain
|
// output gain
|
||||||
in1 *= over; // apply gain reduction to input
|
_in1 *= over; // apply gain reduction to input
|
||||||
in2 *= over;
|
_in2 *= over;
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ namespace audio {
|
|||||||
Gate();
|
Gate();
|
||||||
virtual ~Gate() {}
|
virtual ~Gate() {}
|
||||||
// parameters
|
// parameters
|
||||||
virtual void setThresh(double dB);
|
virtual void setThresh(double _dB);
|
||||||
virtual double getThresh() const {
|
virtual double getThresh() const {
|
||||||
return m_threshdB;
|
return m_threshdB;
|
||||||
}
|
}
|
||||||
@ -47,9 +47,9 @@ namespace audio {
|
|||||||
// call before runtime (in resume())
|
// call before runtime (in resume())
|
||||||
virtual void initRuntime();
|
virtual void initRuntime();
|
||||||
// gate runtime process
|
// gate runtime process
|
||||||
void process(double &in1, double &in2);
|
void process(double& _in1, double& _in2);
|
||||||
// with stereo-linked key in
|
// with stereo-linked key in
|
||||||
void process(double &in1, double &in2, double keyLinked);
|
void process(double& _in1, double& _in2, double _keyLinked);
|
||||||
private:
|
private:
|
||||||
// transfer function
|
// transfer function
|
||||||
double m_threshdB; //!< threshold (dB)
|
double m_threshdB; //!< threshold (dB)
|
||||||
|
64
audio/algo/chunkware/GateRms.cpp
Normal file
64
audio/algo/chunkware/GateRms.cpp
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
/**
|
||||||
|
* @author Bojan MARKOVIC
|
||||||
|
* @author Edouard DUPIN
|
||||||
|
* @copyright 2006, ChunkWare Music Software, OPEN-SOURCE
|
||||||
|
* @license BSD-1 (see license file)
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* * The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <audio/algo/chunkware/GateRms.h>
|
||||||
|
|
||||||
|
audio::algo::chunkware::GateRms::GateRms() :
|
||||||
|
m_averager(5.0),
|
||||||
|
m_averageSuares(DC_OFFSET) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void audio::algo::chunkware::GateRms::setSampleRate(double _sampleRate) {
|
||||||
|
audio::algo::chunkware::Gate::setSampleRate(_sampleRate);
|
||||||
|
m_averager.setSampleRate(_sampleRate);
|
||||||
|
}
|
||||||
|
|
||||||
|
void audio::algo::chunkware::GateRms::setWindow(double _ms) {
|
||||||
|
m_averager.setTc(_ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
void audio::algo::chunkware::GateRms::initRuntime() {
|
||||||
|
audio::algo::chunkware::Gate::initRuntime();
|
||||||
|
m_averageSuares = DC_OFFSET;
|
||||||
|
}
|
||||||
|
|
||||||
|
void audio::algo::chunkware::GateRms::process(double& _in1, double& _in2) {
|
||||||
|
// create sidechain
|
||||||
|
double inSq1 = _in1 * _in1; // square input
|
||||||
|
double inSq2 = _in2 * _in2;
|
||||||
|
double sum = inSq1 + inSq2; // power summing
|
||||||
|
sum += DC_OFFSET; // DC offset, to prevent denormal
|
||||||
|
m_averager.run(sum, m_averageSuares); // average of squares
|
||||||
|
double rms = sqrt(m_averageSuares); // rms (sort of ...)
|
||||||
|
/* REGARDING THE RMS AVERAGER: Ok, so this isn't a REAL RMS
|
||||||
|
* calculation. A true RMS is an FIR moving average. This
|
||||||
|
* approximation is a 1-pole IIR. Nonetheless, in practice,
|
||||||
|
* and in the interest of simplicity, this method will suffice,
|
||||||
|
* giving comparable results.
|
||||||
|
*/
|
||||||
|
audio::algo::chunkware::Gate::process(_in1, _in2, rms); // rest of process
|
||||||
|
}
|
58
audio/algo/chunkware/GateRms.h
Normal file
58
audio/algo/chunkware/GateRms.h
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
/**
|
||||||
|
* @author Bojan MARKOVIC
|
||||||
|
* @author Edouard DUPIN
|
||||||
|
* @copyright 2006, ChunkWare Music Software, OPEN-SOURCE
|
||||||
|
* @license BSD-1 (see license file)
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* * The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __AUDIO_ALGO_CHUNKWARE_GATE_RMS_H__
|
||||||
|
#define __AUDIO_ALGO_CHUNKWARE_GATE_RMS_H__
|
||||||
|
|
||||||
|
#include <audio/algo/chunkware/Gate.h>
|
||||||
|
|
||||||
|
namespace audio {
|
||||||
|
namespace algo {
|
||||||
|
namespace chunkware {
|
||||||
|
class GateRms : public Gate {
|
||||||
|
public:
|
||||||
|
GateRms();
|
||||||
|
virtual ~GateRms() {}
|
||||||
|
// sample rate
|
||||||
|
virtual void setSampleRate(double _sampleRate);
|
||||||
|
// RMS window
|
||||||
|
virtual void setWindow(double _ms);
|
||||||
|
virtual double getWindow() const {
|
||||||
|
return m_averager.getTc();
|
||||||
|
}
|
||||||
|
// runtime process
|
||||||
|
// call before runtime (in resume())
|
||||||
|
virtual void initRuntime();
|
||||||
|
// gate runtime process
|
||||||
|
void process(double& _in1, double& _in2);
|
||||||
|
private:
|
||||||
|
audio::algo::chunkware::EnvelopeDetector m_averager; //!< averager
|
||||||
|
double m_averageSuares; //!< average of squares
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -43,25 +43,25 @@ audio::algo::chunkware::Limiter::Limiter() :
|
|||||||
m_outputBuffer[ 1 ].resize(BUFFER_SIZE, 0.0);
|
m_outputBuffer[ 1 ].resize(BUFFER_SIZE, 0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void audio::algo::chunkware::Limiter::setThresh(double dB) {
|
void audio::algo::chunkware::Limiter::setThresh(double _dB) {
|
||||||
m_threshdB = dB;
|
m_threshdB = _dB;
|
||||||
m_threshold = dB2lin(dB);
|
m_threshold = dB2lin(_dB);
|
||||||
}
|
}
|
||||||
|
|
||||||
void audio::algo::chunkware::Limiter::setAttack(double ms) {
|
void audio::algo::chunkware::Limiter::setAttack(double _ms) {
|
||||||
unsigned int samp = int(0.001 * ms * m_attack.getSampleRate());
|
unsigned int samp = int(0.001 * _ms * m_attack.getSampleRate());
|
||||||
AA_CHUNK_ASSERT(samp < BUFFER_SIZE, "input function error");
|
AA_CHUNK_ASSERT(samp < BUFFER_SIZE, "input function error");
|
||||||
m_peakHold = samp;
|
m_peakHold = samp;
|
||||||
m_attack.setTc(ms);
|
m_attack.setTc(_ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
void audio::algo::chunkware::Limiter::setRelease(double ms) {
|
void audio::algo::chunkware::Limiter::setRelease(double _ms) {
|
||||||
m_release.setTc(ms);
|
m_release.setTc(_ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
void audio::algo::chunkware::Limiter::setSampleRate(double sampleRate) {
|
void audio::algo::chunkware::Limiter::setSampleRate(double _sampleRate) {
|
||||||
m_attack.setSampleRate(sampleRate);
|
m_attack.setSampleRate(_sampleRate);
|
||||||
m_release.setSampleRate(sampleRate);
|
m_release.setSampleRate(_sampleRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
void audio::algo::chunkware::Limiter::initRuntime() {
|
void audio::algo::chunkware::Limiter::initRuntime() {
|
||||||
@ -79,10 +79,10 @@ void audio::algo::chunkware::Limiter::FastEnvelope::setCoef() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void audio::algo::chunkware::Limiter::process(double &in1, double &in2) {
|
void audio::algo::chunkware::Limiter::process(double& _in1, double& _in2) {
|
||||||
// create sidechain
|
// create sidechain
|
||||||
double rect1 = fabs(in1); // rectify input
|
double rect1 = fabs(_in1); // rectify input
|
||||||
double rect2 = fabs(in2);
|
double rect2 = fabs(_in2);
|
||||||
double keyLink = std::max(rect1, rect2); // link channels with greater of 2
|
double keyLink = std::max(rect1, rect2); // link channels with greater of 2
|
||||||
// threshold
|
// threshold
|
||||||
// we always want to feed the sidechain AT LEATS the threshold value
|
// we always want to feed the sidechain AT LEATS the threshold value
|
||||||
@ -136,16 +136,16 @@ void audio::algo::chunkware::Limiter::process(double &in1, double &in2) {
|
|||||||
// (m_cursor - delay) & m_bufferMask gets sample from [delay] samples ago
|
// (m_cursor - delay) & m_bufferMask gets sample from [delay] samples ago
|
||||||
// m_bufferMask variable wraps index
|
// m_bufferMask variable wraps index
|
||||||
unsigned int delayIndex = (m_cursor - m_peakHold) & m_bufferMask;
|
unsigned int delayIndex = (m_cursor - m_peakHold) & m_bufferMask;
|
||||||
double delay1 = m_outputBuffer[ 0 ][ delayIndex ];
|
double delay1 = m_outputBuffer[0][delayIndex];
|
||||||
double delay2 = m_outputBuffer[ 1 ][ delayIndex ];
|
double delay2 = m_outputBuffer[1][delayIndex];
|
||||||
// load current buffer index and advance current index
|
// load current buffer index and advance current index
|
||||||
// m_bufferMask wraps m_cursor index
|
// m_bufferMask wraps m_cursor index
|
||||||
m_outputBuffer[ 0 ][ m_cursor ] = in1;
|
m_outputBuffer[0][m_cursor] = _in1;
|
||||||
m_outputBuffer[ 1 ][ m_cursor ] = in2;
|
m_outputBuffer[1][m_cursor] = _in2;
|
||||||
++m_cursor &= m_bufferMask;
|
++m_cursor &= m_bufferMask;
|
||||||
// output gain
|
// output gain
|
||||||
in1 = delay1 * gR; // apply gain reduction to input
|
_in1 = delay1 * gR; // apply gain reduction to input
|
||||||
in2 = delay2 * gR;
|
_in2 = delay2 * gR;
|
||||||
/* REGARDING THE GAIN REDUCTION: Due to the logarithmic nature
|
/* REGARDING THE GAIN REDUCTION: Due to the logarithmic nature
|
||||||
* of the attack phase, the sidechain will never achieve "full"
|
* of the attack phase, the sidechain will never achieve "full"
|
||||||
* attack. (Actually, it is only guaranteed to achieve 99% of
|
* attack. (Actually, it is only guaranteed to achieve 99% of
|
||||||
|
@ -35,17 +35,14 @@
|
|||||||
namespace audio {
|
namespace audio {
|
||||||
namespace algo {
|
namespace algo {
|
||||||
namespace chunkware {
|
namespace chunkware {
|
||||||
//-------------------------------------------------------------
|
|
||||||
// simple limiter
|
|
||||||
//-------------------------------------------------------------
|
|
||||||
class Limiter {
|
class Limiter {
|
||||||
public:
|
public:
|
||||||
Limiter();
|
Limiter();
|
||||||
virtual ~Limiter() {}
|
virtual ~Limiter() {}
|
||||||
// parameters
|
// parameters
|
||||||
virtual void setThresh(double dB);
|
virtual void setThresh(double _dB);
|
||||||
virtual void setAttack(double ms);
|
virtual void setAttack(double _ms);
|
||||||
virtual void setRelease(double ms);
|
virtual void setRelease(double _ms);
|
||||||
virtual double getThresh() const {
|
virtual double getThresh() const {
|
||||||
return m_threshdB;
|
return m_threshdB;
|
||||||
}
|
}
|
||||||
@ -60,7 +57,7 @@ namespace audio {
|
|||||||
return m_peakHold;
|
return m_peakHold;
|
||||||
}
|
}
|
||||||
// sample rate dependencies
|
// sample rate dependencies
|
||||||
virtual void setSampleRate(double sampleRate);
|
virtual void setSampleRate(double _sampleRate);
|
||||||
virtual double getSampleRate() {
|
virtual double getSampleRate() {
|
||||||
return m_attack.getSampleRate();
|
return m_attack.getSampleRate();
|
||||||
}
|
}
|
||||||
@ -68,13 +65,13 @@ namespace audio {
|
|||||||
// call before runtime (in resume())
|
// call before runtime (in resume())
|
||||||
virtual void initRuntime();
|
virtual void initRuntime();
|
||||||
// limiter runtime process
|
// limiter runtime process
|
||||||
void process(double &in1, double &in2);
|
void process(double& _in1, double& _in2);
|
||||||
protected:
|
protected:
|
||||||
// class for faster attack/release
|
// class for faster attack/release
|
||||||
class FastEnvelope : public EnvelopeDetector {
|
class FastEnvelope : public audio::algo::chunkware::EnvelopeDetector {
|
||||||
public:
|
public:
|
||||||
FastEnvelope(double ms = 1.0, double sampleRate = 44100.0) :
|
FastEnvelope(double _ms = 1.0, double _sampleRate = 44100.0) :
|
||||||
EnvelopeDetector(ms, sampleRate) {
|
EnvelopeDetector(_ms, _sampleRate) {
|
||||||
|
|
||||||
}
|
}
|
||||||
virtual ~FastEnvelope() {}
|
virtual ~FastEnvelope() {}
|
||||||
@ -91,8 +88,8 @@ namespace audio {
|
|||||||
unsigned int m_peakTimer; //!< peak hold timer
|
unsigned int m_peakTimer; //!< peak hold timer
|
||||||
double m_maxPeak; //!< max peak
|
double m_maxPeak; //!< max peak
|
||||||
// attack/release envelope
|
// attack/release envelope
|
||||||
FastEnvelope m_attack; //!< attack
|
audio::algo::chunkware::Limiter::FastEnvelope m_attack; //!< attack
|
||||||
FastEnvelope m_release; //!< release
|
audio::algo::chunkware::Limiter::FastEnvelope m_release; //!< release
|
||||||
double m_overThresholdEnvelope; //!< over-threshold envelope (linear)
|
double m_overThresholdEnvelope; //!< over-threshold envelope (linear)
|
||||||
// buffer
|
// buffer
|
||||||
// BUFFER_SIZE default can handle up to ~10ms at 96kHz
|
// BUFFER_SIZE default can handle up to ~10ms at 96kHz
|
||||||
|
Loading…
Reference in New Issue
Block a user