[DEV] rework naming of the lib ==> audio::algo::chunkware

This commit is contained in:
Edouard DUPIN 2015-04-03 21:06:39 +02:00
parent 4f3794ca80
commit 4cd6d4e0bf
25 changed files with 1109 additions and 1257 deletions

View File

@ -0,0 +1,140 @@
/*
* Simple Compressor (source)
*
* File : SimpleComp.cpp
* Library : SimpleSource
* Version : 1.12
* Implements : SimpleComp, SimpleCompRms
*
* © 2006, ChunkWare Music Software, OPEN-SOURCE
*
* 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 "Compressor.h"
//-------------------------------------------------------------
// simple compressor
//-------------------------------------------------------------
audio::algo::chunkware::Compresssor::Compresssor() :
AttRelEnvelope(10.0, 100.0),
threshdB_(0.0),
ratio_(1.0),
envdB_(DC_OFFSET) {
}
//-------------------------------------------------------------
void audio::algo::chunkware::Compresssor::setThresh(double dB) {
threshdB_ = dB;
}
//-------------------------------------------------------------
void audio::algo::chunkware::Compresssor::setRatio(double ratio) {
assert(ratio > 0.0);
ratio_ = ratio;
}
//-------------------------------------------------------------
void audio::algo::chunkware::Compresssor::initRuntime() {
envdB_ = DC_OFFSET;
}
void audio::algo::chunkware::Compresssor::process(double &in1, double &in2) {
// create sidechain
double rect1 = fabs(in1); // rectify input
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::Compresssor::process(double &in1, double &in2, double keyLinked) {
keyLinked = fabs(keyLinked); // rectify (just in case)
// convert key to dB
keyLinked += DC_OFFSET; // add DC offset to avoid log(0)
double keydB = lin2dB(keyLinked); // convert linear -> dB
// threshold
double overdB = keydB - threshdB_; // delta over threshold
if (overdB < 0.0)
overdB = 0.0;
// attack/release
overdB += DC_OFFSET; // add DC offset to avoid denormal
AttRelEnvelope::run(overdB, envdB_); // run attack/release envelope
overdB = envdB_ - DC_OFFSET; // subtract DC offset
/* 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,
* thereby avoiding denormals. However, to prevent the offset from causing
* constant gain reduction, we must subtract it from the envelope, yielding
* a minimum value of 0dB.
*/
// transfer function
double gr = overdB * (ratio_ - 1.0); // gain reduction (dB)
gr = dB2lin(gr); // convert dB -> linear
// output gain
in1 *= gr; // apply gain reduction to input
in2 *= gr;
}
//-------------------------------------------------------------
// simple compressor with RMS detection
//-------------------------------------------------------------
audio::algo::chunkware::CompresssorRms::CompresssorRms() :
ave_(5.0),
aveOfSqrs_(DC_OFFSET) {
}
//-------------------------------------------------------------
void audio::algo::chunkware::CompresssorRms::setSampleRate(double sampleRate) {
audio::algo::chunkware::Compresssor::setSampleRate(sampleRate);
ave_.setSampleRate(sampleRate);
}
//-------------------------------------------------------------
void audio::algo::chunkware::CompresssorRms::setWindow(double ms) {
ave_.setTc(ms);
}
//-------------------------------------------------------------
void audio::algo::chunkware::CompresssorRms::initRuntime() {
audio::algo::chunkware::Compresssor::initRuntime();
aveOfSqrs_ = DC_OFFSET;
}
void audio::algo::chunkware::CompresssorRms::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
ave_.run(sum, aveOfSqrs_); // average of squares
double rms = sqrt(aveOfSqrs_); // 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.
*/
// rest of process
Compresssor::process(in1, in2, rms);
}

View File

@ -0,0 +1,94 @@
/*
* Simple Compressor (header)
*
* File : SimpleComp.h
* Library : SimpleSource
* Version : 1.12
* Class : SimpleComp, SimpleCompRms
*
* © 2006, ChunkWare Music Software, OPEN-SOURCE
*
* 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 __SIMPLE_COMP_H__
#define __SIMPLE_COMP_H__
#include "header.h"
#include "Envelope.h"
#include "Gain.h"
namespace audio {
namespace algo {
namespace chunkware {
//-------------------------------------------------------------
// compressor
//-------------------------------------------------------------
class Compresssor : public AttRelEnvelope {
public:
Compresssor();
virtual ~Compresssor() {}
// parameters
virtual void setThresh(double dB);
virtual void setRatio(double dB);
virtual double getThresh() const {
return threshdB_;
}
virtual double getRatio() const {
return ratio_;
}
// runtime
// call before runtime (in resume())
virtual void initRuntime();
// compressor runtime process
void process(double &in1, double &in2);
// with stereo-linked key in
void process(double &in1, double &in2, double keyLinked);
private:
// transfer function
double threshdB_;//!< threshold (dB)
double ratio_; //!< ratio (compression: < 1 ; expansion: > 1)
// runtime variables
double envdB_; //!< over-threshold envelope (dB)
};
//-------------------------------------------------------------
// compressor with RMS detection
//-------------------------------------------------------------
class CompresssorRms : public Compresssor {
public:
CompresssorRms();
virtual ~CompresssorRms() {}
// sample rate
virtual void setSampleRate(double sampleRate);
// RMS window
virtual void setWindow(double ms);
virtual double getWindow() const { return ave_.getTc(); }
// runtime process
virtual void initRuntime(); // call before runtime (in resume())
void process(double &in1, double &in2); // compressor runtime process
protected:
EnvelopeDetector ave_; //!< averager
double aveOfSqrs_; //!< average of squares
};
}
}
}
#endif

View File

@ -0,0 +1,81 @@
/*
* Simple Envelope Detectors (source)
*
* File : SimpleEnvelope.cpp
* Library : SimpleSource
* Version : 1.12
* Implements : EnvelopeDetector, AttRelEnvelope
*
* © 2006, ChunkWare Music Software, OPEN-SOURCE
*
* 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 "Envelope.h"
audio::algo::chunkware::EnvelopeDetector::EnvelopeDetector(double ms, double sampleRate) {
assert(sampleRate > 0.0);
assert(ms > 0.0);
sampleRate_ = sampleRate;
ms_ = ms;
setCoef();
}
void audio::algo::chunkware::EnvelopeDetector::setTc(double ms) {
assert(ms > 0.0);
ms_ = ms;
setCoef();
}
void audio::algo::chunkware::EnvelopeDetector::setSampleRate(double sampleRate) {
assert(sampleRate > 0.0);
sampleRate_ = sampleRate;
setCoef();
}
void audio::algo::chunkware::EnvelopeDetector::setCoef() {
coef_ = exp(-1000.0 / (ms_ * sampleRate_));
}
audio::algo::chunkware::AttRelEnvelope::AttRelEnvelope(double att_ms, double rel_ms, double sampleRate) :
att_(att_ms, sampleRate),
rel_(rel_ms, sampleRate) {
}
//-------------------------------------------------------------
void audio::algo::chunkware::AttRelEnvelope::setAttack(double ms) {
att_.setTc(ms);
}
//-------------------------------------------------------------
void audio::algo::chunkware::AttRelEnvelope::setRelease(double ms) {
rel_.setTc(ms);
}
//-------------------------------------------------------------
void audio::algo::chunkware::AttRelEnvelope::setSampleRate(double sampleRate) {
att_.setSampleRate(sampleRate);
rel_.setSampleRate(sampleRate);
}

View File

@ -0,0 +1,121 @@
/*
* Simple Envelope Detectors (header)
*
* File : SimpleEnvelope.h
* Library : SimpleSource
* Version : 1.12
* Class : EnvelopeDetector, AttRelEnvelope
*
* © 2006, ChunkWare Music Software, OPEN-SOURCE
*
* 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 __SIMPLE_ENVELOPE_H__
#define __SIMPLE_ENVELOPE_H__
#include "header.h"
namespace audio {
namespace algo {
namespace chunkware {
//-------------------------------------------------------------
// DC offset (to prevent denormal)
//-------------------------------------------------------------
// USE:
// 1. init envelope state to DC_OFFSET before processing
// 2. add to input before envelope runtime function
static const double DC_OFFSET = 1.0E-25;
//-------------------------------------------------------------
// envelope detector
//-------------------------------------------------------------
class EnvelopeDetector {
public:
EnvelopeDetector(double ms = 1.0,
double sampleRate = 44100.0);
virtual ~EnvelopeDetector() {}
// time constant
virtual void setTc(double ms);
virtual double getTc() const {
return ms_;
}
// sample rate
virtual void setSampleRate(double sampleRate);
virtual double getSampleRate() const {
return sampleRate_;
}
// runtime function
void run(double in, double &state) {
state = in + coef_ * (state - in);
}
protected:
double sampleRate_; //!< sample rate
double ms_; //!< time constant in ms
double coef_; //!< runtime coefficient
virtual void setCoef(); //!< coef calculation
};
//-------------------------------------------------------------
// attack/release envelope
//-------------------------------------------------------------
class AttRelEnvelope {
public:
AttRelEnvelope(double att_ms = 10.0,
double rel_ms = 100.0,
double sampleRate = 44100.0);
virtual ~AttRelEnvelope() {}
// attack time constant
virtual void setAttack(double ms);
virtual double getAttack() const {
return att_.getTc();
}
// release time constant
virtual void setRelease(double ms);
virtual double getRelease() const {
return rel_.getTc();
}
// sample rate dependencies
virtual void setSampleRate(double sampleRate);
virtual double getSampleRate() const {
return att_.getSampleRate();
}
// runtime function
void run(double in, double &state) {
/* assumes that:
* positive delta = attack
* negative delta = release
* good for linear & log values
*/
if (in > state) {
// attack
att_.run(in, state);
} else {
// release
rel_.run(in, state);
}
}
private:
EnvelopeDetector att_;
EnvelopeDetector rel_;
};
}
}
}
#endif

113
simpleSource/SimpleGain.h → audio/algo/chunkware/Gain.h Executable file → Normal file
View File

@ -1,56 +1,57 @@
/*
* Gain Functions (header)
*
* File : SimpleGain.h
* Library : SimpleSource
* Version : 1.12
* Class :
*
* © 2006, ChunkWare Music Software, OPEN-SOURCE
*
* 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 __SIMPLE_GAIN_H__
#define __SIMPLE_GAIN_H__
#include "SimpleHeader.h" // common header
namespace chunkware_simple
{
//-------------------------------------------------------------
// gain functions
//-------------------------------------------------------------
// linear -> dB conversion
static INLINE double lin2dB( double lin ) {
static const double LOG_2_DB = 8.6858896380650365530225783783321; // 20 / ln( 10 )
return log( lin ) * LOG_2_DB;
}
// dB -> linear conversion
static INLINE double dB2lin( double dB ) {
static const double DB_2_LOG = 0.11512925464970228420089957273422; // ln( 10 ) / 20
return exp( dB * DB_2_LOG );
}
} // end namespace chunkware_simple
#endif // end __SIMPLE_GAIN_H__
/*
* Gain Functions (header)
*
* File : SimpleGain.h
* Library : SimpleSource
* Version : 1.12
* Class :
*
* © 2006, ChunkWare Music Software, OPEN-SOURCE
*
* 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 __SIMPLE_GAIN_H__
#define __SIMPLE_GAIN_H__
#include "header.h"
namespace audio {
namespace algo {
namespace chunkware {
//-------------------------------------------------------------
// gain functions
//-------------------------------------------------------------
// linear -> dB conversion
static inline double lin2dB(double lin) {
static const double LOG_2_DB = 8.6858896380650365530225783783321; // 20 / ln(10)
return log(lin) * LOG_2_DB;
}
// dB -> linear conversion
static inline double dB2lin(double dB) {
static const double DB_2_LOG = 0.11512925464970228420089957273422; // ln(10) / 20
return exp(dB * DB_2_LOG);
}
}
}
}
#endif

View File

@ -0,0 +1,119 @@
/*
* Simple Gate (source)
*
* File : SimpleGate.cpp
* Library : SimpleSource
* Version : 1.12
* Implements : SimpleGate, SimpleGateRms
*
* © 2006, ChunkWare Music Software, OPEN-SOURCE
*
* 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 "Gate.h"
audio::algo::chunkware::Gate::Gate() :
AttRelEnvelope(1.0, 100.0),
threshdB_(0.0),
thresh_(1.0),
env_(DC_OFFSET) {
}
void audio::algo::chunkware::Gate::setThresh(double dB) {
threshdB_ = dB;
thresh_ = dB2lin(dB);
}
void audio::algo::chunkware::Gate::initRuntime() {
env_ = DC_OFFSET;
}
void audio::algo::chunkware::Gate::process(double &in1, double &in2) {
// create sidechain
double rect1 = fabs(in1); // rectify input
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) {
keyLinked = fabs(keyLinked); // rectify (just in case)
// threshold
// key over threshold (0.0 or 1.0)
double over = double(keyLinked > thresh_);
// attack/release
over += DC_OFFSET; // add DC offset to avoid denormal
AttRelEnvelope::run(over, env_); // run attack/release
over = env_ - DC_OFFSET; // subtract DC offset
/* 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,
* thereby avoiding denormals. However, to prevent the offset from causing
* constant gain reduction, we must subtract it from the envelope, yielding
* a minimum value of 0dB.
*/
// output gain
in1 *= over; // apply gain reduction to input
in2 *= over;
}
audio::algo::chunkware::GateRms::GateRms() :
ave_(5.0),
aveOfSqrs_(DC_OFFSET) {
}
void audio::algo::chunkware::GateRms::setSampleRate(double sampleRate) {
audio::algo::chunkware::Gate::setSampleRate(sampleRate);
ave_.setSampleRate(sampleRate);
}
void audio::algo::chunkware::GateRms::setWindow(double ms) {
ave_.setTc(ms);
}
void audio::algo::chunkware::GateRms::initRuntime() {
audio::algo::chunkware::Gate::initRuntime();
aveOfSqrs_ = 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
ave_.run(sum, aveOfSqrs_); // average of squares
double rms = sqrt(aveOfSqrs_); // 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.
*/
Gate::process(in1, in2, rms); // rest of process
}

View File

@ -0,0 +1,94 @@
/*
* Simple Gate (header)
*
* File : SimpleGate.h
* Library : SimpleSource
* Version : 1.12
* Class : SimpleGate, SimpleGateRms
*
* © 2006, ChunkWare Music Software, OPEN-SOURCE
*
* 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 __SIMPLE_GATE_H__
#define __SIMPLE_GATE_H__
#include "header.h"
#include "Envelope.h"
#include "Gain.h"
namespace audio {
namespace algo {
namespace chunkware {
//-------------------------------------------------------------
// simple gate
//-------------------------------------------------------------
class Gate : public AttRelEnvelope {
public:
Gate();
virtual ~Gate() {}
// parameters
virtual void setThresh(double dB);
virtual double getThresh() const {
return threshdB_;
}
// 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:
// transfer function
double threshdB_; //!< threshold (dB)
double thresh_; //!< threshold (linear)
// runtime variables
double env_; //!< over-threshold envelope (linear)
};
//-------------------------------------------------------------
// simple gate with RMS detection
//-------------------------------------------------------------
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 ave_.getTc();
}
// runtime process
// call before runtime (in resume())
virtual void initRuntime();
// gate runtime process
void process(double &in1, double &in2);
private:
EnvelopeDetector ave_; //!< averager
double aveOfSqrs_; //!< average of squares
};
}
}
}
#endif

View File

@ -0,0 +1,172 @@
/*
* Simple Limiter (source)
*
* File : SimpleLimit.cpp
* Library : SimpleSource
* Version : 1.12
* Implements : SimpleLimit
*
* © 2006, ChunkWare Music Software, OPEN-SOURCE
*
* 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 "Limiter.h"
audio::algo::chunkware::Limiter::Limiter() :
threshdB_(0.0),
thresh_(1.0),
peakHold_(0),
peakTimer_(0),
maxPeak_(1.0),
att_(1.0),
rel_(10.0),
env_(1.0),
mask_(BUFFER_SIZE-1),
cur_(0) {
setAttack(1.0);
outBuffer_[ 0 ].resize(BUFFER_SIZE, 0.0);
outBuffer_[ 1 ].resize(BUFFER_SIZE, 0.0);
}
void audio::algo::chunkware::Limiter::setThresh(double dB) {
threshdB_ = dB;
thresh_ = dB2lin(dB);
}
void audio::algo::chunkware::Limiter::setAttack(double ms) {
unsigned int samp = int(0.001 * ms * att_.getSampleRate());
assert(samp < BUFFER_SIZE);
peakHold_ = samp;
att_.setTc(ms);
}
void audio::algo::chunkware::Limiter::setRelease(double ms) {
rel_.setTc(ms);
}
void audio::algo::chunkware::Limiter::setSampleRate(double sampleRate) {
att_.setSampleRate(sampleRate);
rel_.setSampleRate(sampleRate);
}
void audio::algo::chunkware::Limiter::initRuntime() {
peakTimer_ = 0;
maxPeak_ = thresh_;
env_ = thresh_;
cur_ = 0;
outBuffer_[ 0 ].assign(BUFFER_SIZE, 0.0);
outBuffer_[ 1 ].assign(BUFFER_SIZE, 0.0);
}
void audio::algo::chunkware::Limiter::FastEnvelope::setCoef() {
// rises to 99% of in value over duration of time constant
coef_ = pow(0.01, (1000.0 / (ms_ * sampleRate_)));
}
void audio::algo::chunkware::Limiter::process(double &in1, double &in2) {
// create sidechain
double rect1 = fabs(in1); // rectify input
double rect2 = fabs(in2);
double keyLink = std::max(rect1, rect2); // link channels with greater of 2
// threshold
// we always want to feed the sidechain AT LEATS the threshold value
if (keyLink < thresh_)
keyLink = thresh_;
// test:
// a) whether peak timer has "expired"
// b) whether new peak is greater than previous max peak
if ((++peakTimer_ >= peakHold_) || (keyLink > maxPeak_)) {
// if either condition is met:
peakTimer_ = 0; // reset peak timer
maxPeak_ = keyLink; // assign new peak to max peak
}
/* REGARDING THE MAX PEAK: This method assumes that the only important
* sample in a look-ahead buffer would be the highest peak. As such,
* instead of storing all samples in a look-ahead buffer, it only stores
* the max peak, and compares all incoming samples to that one.
* The max peak has a hold time equal to what the look-ahead buffer
* would have been, which is tracked by a timer (counter). When this
* timer expires, the sample would have exited from the buffer. Therefore,
* a new sample must be assigned to the max peak. We assume that the next
* highest sample in our theoretical buffer is the current input sample.
* In reality, we know this is probably NOT the case, and that there has
* been another sample, slightly lower than the one before it, that has
* passed the input. If we do not account for this possibility, our gain
* reduction could be insufficient, resulting in an "over" at the output.
* To remedy this, we simply apply a suitably long release stage in the
* envelope follower.
*/
// attack/release
if (maxPeak_ > env_) {
// run attack phase
att_.run(maxPeak_, env_);
} else {
// run release phase
rel_.run(maxPeak_, env_);
}
/* REGARDING THE ATTACK: This limiter achieves "look-ahead" detection
* by allowing the envelope follower to attack the max peak, which is
* held for the duration of the attack phase -- unless a new, higher
* peak is detected. The output signal is buffered so that the gain
* reduction is applied in advance of the "offending" sample.
*/
/* NOTE: a DC offset is not necessary for the envelope follower,
* as neither the max peak nor envelope should fall below the
* threshold (which is assumed to be around 1.0 linear).
*/
// gain reduction
double gR = thresh_ / env_;
// unload current buffer index
// (cur_ - delay) & mask_ gets sample from [delay] samples ago
// mask_ variable wraps index
unsigned int delayIndex = (cur_ - peakHold_) & mask_;
double delay1 = outBuffer_[ 0 ][ delayIndex ];
double delay2 = outBuffer_[ 1 ][ delayIndex ];
// load current buffer index and advance current index
// mask_ wraps cur_ index
outBuffer_[ 0 ][ cur_ ] = in1;
outBuffer_[ 1 ][ cur_ ] = in2;
++cur_ &= mask_;
// output gain
in1 = delay1 * gR; // apply gain reduction to input
in2 = delay2 * gR;
/* REGARDING THE GAIN REDUCTION: Due to the logarithmic nature
* of the attack phase, the sidechain will never achieve "full"
* attack. (Actually, it is only guaranteed to achieve 99% of
* the input value over the given time constant.) As such, the
* limiter cannot achieve "brick-wall" limiting. There are 2
* workarounds:
*
* 1) Set the threshold slightly lower than the desired threshold.
* i.e. 0.0dB -> -0.1dB or even -0.5dB
*
* 2) Clip the output at the threshold, as such:
*
* if (in1 > thresh_) in1 = thresh_;
* else if (in1 < -thresh_) in1 = -thresh_;
*
* if (in2 > thresh_) in2 = thresh_;
* else if (in2 < -thresh_) in2 = -thresh_;
*
* (... or replace with your favorite branchless clipper ...)
*/
}

View File

@ -0,0 +1,112 @@
/*
* Simple Limiter (header)
*
* File : SimpleLimit.h
* Library : SimpleSource
* Version : 1.12
* Class : SimpleLimit
*
* © 2006, ChunkWare Music Software, OPEN-SOURCE
*
* 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 __SIMPLE_LIMIT_H__
#define __SIMPLE_LIMIT_H__
#include "header.h"
#include "Envelope.h"
#include "Gain.h"
#include <vector>
namespace audio {
namespace algo {
namespace chunkware {
//-------------------------------------------------------------
// simple limiter
//-------------------------------------------------------------
class Limiter {
public:
Limiter();
virtual ~Limiter() {}
// parameters
virtual void setThresh(double dB);
virtual void setAttack(double ms);
virtual void setRelease(double ms);
virtual double getThresh() const {
return threshdB_;
}
virtual double getAttack() const {
return att_.getTc();
}
virtual double getRelease() const {
return rel_.getTc();
}
// latency
virtual const unsigned int getLatency() const {
return peakHold_;
}
// sample rate dependencies
virtual void setSampleRate(double sampleRate);
virtual double getSampleRate() {
return att_.getSampleRate();
}
// runtime
// call before runtime (in resume())
virtual void initRuntime();
// limiter runtime process
void process(double &in1, double &in2);
protected:
// class for faster attack/release
class FastEnvelope : public EnvelopeDetector {
public:
FastEnvelope(double ms = 1.0, double sampleRate = 44100.0)
: EnvelopeDetector(ms, sampleRate)
{}
virtual ~FastEnvelope() {}
protected:
// override setCoef() - coefficient calculation
virtual void setCoef();
};
private:
// transfer function
double threshdB_; // threshold (dB)
double thresh_; // threshold (linear)
// max peak
unsigned int peakHold_; // peak hold (samples)
unsigned int peakTimer_; // peak hold timer
double maxPeak_; // max peak
// attack/release envelope
FastEnvelope att_; // attack
FastEnvelope rel_; // release
double env_; // over-threshold envelope (linear)
// buffer
// BUFFER_SIZE default can handle up to ~10ms at 96kHz
// change this if you require more
static const int BUFFER_SIZE = 1024; //!< buffer size (always a power of 2!)
unsigned int mask_; //!< buffer mask
unsigned int cur_; //!< cursor
std::vector< double > outBuffer_[ 2 ]; //!< output buffer
};
}
}
}
#endif

View 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::aec::getLogId() {
static int32_t g_val = etk::log::registerInstance("audio-algo-aec");
return g_val;
}

View File

@ -0,0 +1,45 @@
/** @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 audio {
namespace algo {
namespace aec {
int32_t getLogId();
}
}
}
#define AA_AEC_BASE(info,data) TK_LOG_BASE(audio::algo::aec::getLogId(),info,data)
#define AA_AEC_CRITICAL(data) AA_AEC_BASE(1, data)
#define AA_AEC_ERROR(data) AA_AEC_BASE(2, data)
#define AA_AEC_WARNING(data) AA_AEC_BASE(3, data)
#ifdef DEBUG
#define AA_AEC_INFO(data) AA_AEC_BASE(4, data)
#define AA_AEC_DEBUG(data) AA_AEC_BASE(5, data)
#define AA_AEC_VERBOSE(data) AA_AEC_BASE(6, data)
#define AA_AEC_TODO(data) AA_AEC_BASE(4, "TODO : " << data)
#else
#define AA_AEC_INFO(data) do { } while(false)
#define AA_AEC_DEBUG(data) do { } while(false)
#define AA_AEC_VERBOSE(data) do { } while(false)
#define AA_AEC_TODO(data) do { } while(false)
#endif
#define AA_AEC_ASSERT(cond,data) \
do { \
if (!(cond)) { \
APPL_CRITICAL(data); \
assert(!#cond); \
} \
} while (0)
#endif

View File

@ -30,16 +30,16 @@
#ifndef __SIMPLE_HEADER_H__
#define __SIMPLE_HEADER_H__
#if _MSC_VER > 1000 // MS Visual Studio
#define INLINE __forceinline // forces inline
#define NOMINMAX // for standard library min(), max()
#define _USE_MATH_DEFINES // for math constants
#else // other IDE's
#define INLINE inline
#if _MSC_VER > 1000
// MS Visual Studio
// for standard library min(), max()
#define NOMINMAX
// for math constants
#define _USE_MATH_DEFINES
#endif
#include <algorithm> // for min(), max()
#include <cassert> // for assert()
#include <algorithm>
#include <cassert>
#include <cmath>
#endif // end __SIMPLE_HEADER_H__
#endif

19
license.txt Normal file
View File

@ -0,0 +1,19 @@
Copyright audio-algo-chunkware Edouard DUPIN
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.

View File

@ -0,0 +1,32 @@
#!/usr/bin/python
import lutinModule as module
import lutinTools as tools
import lutinDebug as debug
def get_desc():
return "audio_algo_aec : AEC basic algo"
def create(target):
myModule = module.Module(__file__, 'audio_algo_chunkware', 'LIBRARY')
myModule.add_src_file([
'audio/algo/chunkware/debug.cpp',
'audio/algo/chunkware/Compressor.cpp',
'audio/algo/chunkware/debug.cpp',
'audio/algo/chunkware/Envelope.cpp',
'audio/algo/chunkware/Gate.cpp',
'audio/algo/chunkware/Limiter.cpp'
])
myModule.add_module_depend(['etk'])
myModule.add_export_path(tools.get_current_path(__file__))
# return module
return myModule

View File

@ -1,94 +0,0 @@
/*
* Simple Compressor (source)
*
* File : SimpleComp.cpp
* Library : SimpleSource
* Version : 1.12
* Implements : SimpleComp, SimpleCompRms
*
* © 2006, ChunkWare Music Software, OPEN-SOURCE
*
* 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 "SimpleComp.h"
namespace chunkware_simple
{
//-------------------------------------------------------------
// simple compressor
//-------------------------------------------------------------
SimpleComp::SimpleComp()
: AttRelEnvelope( 10.0, 100.0 )
, threshdB_( 0.0 )
, ratio_( 1.0 )
, envdB_( DC_OFFSET )
{
}
//-------------------------------------------------------------
void SimpleComp::setThresh( double dB )
{
threshdB_ = dB;
}
//-------------------------------------------------------------
void SimpleComp::setRatio( double ratio )
{
assert( ratio > 0.0 );
ratio_ = ratio;
}
//-------------------------------------------------------------
void SimpleComp::initRuntime( void )
{
envdB_ = DC_OFFSET;
}
//-------------------------------------------------------------
// simple compressor with RMS detection
//-------------------------------------------------------------
SimpleCompRms::SimpleCompRms()
: ave_( 5.0 )
, aveOfSqrs_( DC_OFFSET )
{
}
//-------------------------------------------------------------
void SimpleCompRms::setSampleRate( double sampleRate )
{
SimpleComp::setSampleRate( sampleRate );
ave_.setSampleRate( sampleRate );
}
//-------------------------------------------------------------
void SimpleCompRms::setWindow( double ms )
{
ave_.setTc( ms );
}
//-------------------------------------------------------------
void SimpleCompRms::initRuntime( void )
{
SimpleComp::initRuntime();
aveOfSqrs_ = DC_OFFSET;
}
} // end namespace chunkware_simple

View File

@ -1,104 +0,0 @@
/*
* Simple Compressor (header)
*
* File : SimpleComp.h
* Library : SimpleSource
* Version : 1.12
* Class : SimpleComp, SimpleCompRms
*
* © 2006, ChunkWare Music Software, OPEN-SOURCE
*
* 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 __SIMPLE_COMP_H__
#define __SIMPLE_COMP_H__
#include "SimpleHeader.h" // common header
#include "SimpleEnvelope.h" // for base class
#include "SimpleGain.h" // for gain functions
namespace chunkware_simple
{
//-------------------------------------------------------------
// simple compressor
//-------------------------------------------------------------
class SimpleComp : public AttRelEnvelope
{
public:
SimpleComp();
virtual ~SimpleComp() {}
// parameters
virtual void setThresh( double dB );
virtual void setRatio( double dB );
virtual double getThresh( void ) const { return threshdB_; }
virtual double getRatio( void ) const { return ratio_; }
// runtime
virtual void initRuntime( void ); // call before runtime (in resume())
void process( double &in1, double &in2 ); // compressor runtime process
void process( double &in1, double &in2, double keyLinked ); // with stereo-linked key in
private:
// transfer function
double threshdB_; // threshold (dB)
double ratio_; // ratio (compression: < 1 ; expansion: > 1)
// runtime variables
double envdB_; // over-threshold envelope (dB)
}; // end SimpleComp class
//-------------------------------------------------------------
// simple compressor with RMS detection
//-------------------------------------------------------------
class SimpleCompRms : public SimpleComp
{
public:
SimpleCompRms();
virtual ~SimpleCompRms() {}
// sample rate
virtual void setSampleRate( double sampleRate );
// RMS window
virtual void setWindow( double ms );
virtual double getWindow( void ) const { return ave_.getTc(); }
// runtime process
virtual void initRuntime( void ); // call before runtime (in resume())
void process( double &in1, double &in2 ); // compressor runtime process
private:
EnvelopeDetector ave_; // averager
double aveOfSqrs_; // average of squares
}; // end SimpleCompRms class
} // end namespace chunkware_simple
// include inlined process function
#include "SimpleCompProcess.inl"
#endif // end __SIMPLE_COMP_H__

View File

@ -1,116 +0,0 @@
/*
* Simple Compressor (runtime function)
*
* File : SimpleCompProcess.inl
* Library : SimpleSource
* Version : 1.12
* Implements : void SimpleComp::process( double &in1, double &in2 )
* void SimpleComp::process( double &in1, double &in2, double keyLinked )
* void SimpleCompRms::process( double &in1, double &in2 )
*
* © 2006, ChunkWare Music Software, OPEN-SOURCE
*
* 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 __SIMPLE_COMP_PROCESS_INL__
#define __SIMPLE_COMP_PROCESS_INL__
namespace chunkware_simple
{
//-------------------------------------------------------------
INLINE void SimpleComp::process( double &in1, double &in2 )
{
// create sidechain
double rect1 = fabs( in1 ); // rectify input
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
}
//-------------------------------------------------------------
INLINE void SimpleComp::process( double &in1, double &in2, double keyLinked )
{
keyLinked = fabs( keyLinked ); // rectify (just in case)
// convert key to dB
keyLinked += DC_OFFSET; // add DC offset to avoid log( 0 )
double keydB = lin2dB( keyLinked ); // convert linear -> dB
// threshold
double overdB = keydB - threshdB_; // delta over threshold
if ( overdB < 0.0 )
overdB = 0.0;
// attack/release
overdB += DC_OFFSET; // add DC offset to avoid denormal
AttRelEnvelope::run( overdB, envdB_ ); // run attack/release envelope
overdB = envdB_ - DC_OFFSET; // subtract DC offset
/* 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,
* thereby avoiding denormals. However, to prevent the offset from causing
* constant gain reduction, we must subtract it from the envelope, yielding
* a minimum value of 0dB.
*/
// transfer function
double gr = overdB * ( ratio_ - 1.0 ); // gain reduction (dB)
gr = dB2lin( gr ); // convert dB -> linear
// output gain
in1 *= gr; // apply gain reduction to input
in2 *= gr;
}
//-------------------------------------------------------------
INLINE void SimpleCompRms::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
ave_.run( sum, aveOfSqrs_ ); // average of squares
double rms = sqrt( aveOfSqrs_ ); // 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.
*/
SimpleComp::process( in1, in2, rms ); // rest of process
}
} // end namespace chunkware_simple
#endif // end __SIMPLE_COMP_PROCESS_INL__

View File

@ -1,97 +0,0 @@
/*
* Simple Envelope Detectors (source)
*
* File : SimpleEnvelope.cpp
* Library : SimpleSource
* Version : 1.12
* Implements : EnvelopeDetector, AttRelEnvelope
*
* © 2006, ChunkWare Music Software, OPEN-SOURCE
*
* 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 "SimpleEnvelope.h"
namespace chunkware_simple
{
//-------------------------------------------------------------
// envelope detector
//-------------------------------------------------------------
EnvelopeDetector::EnvelopeDetector( double ms, double sampleRate )
{
assert( sampleRate > 0.0 );
assert( ms > 0.0 );
sampleRate_ = sampleRate;
ms_ = ms;
setCoef();
}
//-------------------------------------------------------------
void EnvelopeDetector::setTc( double ms )
{
assert( ms > 0.0 );
ms_ = ms;
setCoef();
}
//-------------------------------------------------------------
void EnvelopeDetector::setSampleRate( double sampleRate )
{
assert( sampleRate > 0.0 );
sampleRate_ = sampleRate;
setCoef();
}
//-------------------------------------------------------------
void EnvelopeDetector::setCoef( void )
{
coef_ = exp( -1000.0 / ( ms_ * sampleRate_ ) );
}
//-------------------------------------------------------------
// attack/release envelope
//-------------------------------------------------------------
AttRelEnvelope::AttRelEnvelope( double att_ms, double rel_ms, double sampleRate )
: att_( att_ms, sampleRate )
, rel_( rel_ms, sampleRate )
{
}
//-------------------------------------------------------------
void AttRelEnvelope::setAttack( double ms )
{
att_.setTc( ms );
}
//-------------------------------------------------------------
void AttRelEnvelope::setRelease( double ms )
{
rel_.setTc( ms );
}
//-------------------------------------------------------------
void AttRelEnvelope::setSampleRate( double sampleRate )
{
att_.setSampleRate( sampleRate );
rel_.setSampleRate( sampleRate );
}
} // end namespace chunkware_simple

View File

@ -1,130 +0,0 @@
/*
* Simple Envelope Detectors (header)
*
* File : SimpleEnvelope.h
* Library : SimpleSource
* Version : 1.12
* Class : EnvelopeDetector, AttRelEnvelope
*
* © 2006, ChunkWare Music Software, OPEN-SOURCE
*
* 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 __SIMPLE_ENVELOPE_H__
#define __SIMPLE_ENVELOPE_H__
#include "SimpleHeader.h" // common header
namespace chunkware_simple
{
//-------------------------------------------------------------
// DC offset (to prevent denormal)
//-------------------------------------------------------------
// USE:
// 1. init envelope state to DC_OFFSET before processing
// 2. add to input before envelope runtime function
static const double DC_OFFSET = 1.0E-25;
//-------------------------------------------------------------
// envelope detector
//-------------------------------------------------------------
class EnvelopeDetector
{
public:
EnvelopeDetector(
double ms = 1.0
, double sampleRate = 44100.0
);
virtual ~EnvelopeDetector() {}
// time constant
virtual void setTc( double ms );
virtual double getTc( void ) const { return ms_; }
// sample rate
virtual void setSampleRate( double sampleRate );
virtual double getSampleRate( void ) const { return sampleRate_; }
// runtime function
INLINE void run( double in, double &state ) {
state = in + coef_ * ( state - in );
}
protected:
double sampleRate_; // sample rate
double ms_; // time constant in ms
double coef_; // runtime coefficient
virtual void setCoef( void ); // coef calculation
}; // end SimpleComp class
//-------------------------------------------------------------
// attack/release envelope
//-------------------------------------------------------------
class AttRelEnvelope
{
public:
AttRelEnvelope(
double att_ms = 10.0
, double rel_ms = 100.0
, double sampleRate = 44100.0
);
virtual ~AttRelEnvelope() {}
// attack time constant
virtual void setAttack( double ms );
virtual double getAttack( void ) const { return att_.getTc(); }
// release time constant
virtual void setRelease( double ms );
virtual double getRelease( void ) const { return rel_.getTc(); }
// sample rate dependencies
virtual void setSampleRate( double sampleRate );
virtual double getSampleRate( void ) const { return att_.getSampleRate(); }
// runtime function
INLINE void run( double in, double &state ) {
/* assumes that:
* positive delta = attack
* negative delta = release
* good for linear & log values
*/
if ( in > state )
att_.run( in, state ); // attack
else
rel_.run( in, state ); // release
}
private:
EnvelopeDetector att_;
EnvelopeDetector rel_;
}; // end AttRelEnvelope class
} // end namespace chunkware_simple
#endif // end __SIMPLE_ENVELOPE_H__

View File

@ -1,86 +0,0 @@
/*
* Simple Gate (source)
*
* File : SimpleGate.cpp
* Library : SimpleSource
* Version : 1.12
* Implements : SimpleGate, SimpleGateRms
*
* © 2006, ChunkWare Music Software, OPEN-SOURCE
*
* 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 "SimpleGate.h"
namespace chunkware_simple
{
//-------------------------------------------------------------
SimpleGate::SimpleGate()
: AttRelEnvelope( 1.0, 100.0 )
, threshdB_( 0.0 )
, thresh_( 1.0 )
, env_( DC_OFFSET )
{
}
//-------------------------------------------------------------
void SimpleGate::setThresh( double dB )
{
threshdB_ = dB;
thresh_ = dB2lin( dB );
}
//-------------------------------------------------------------
void SimpleGate::initRuntime( void )
{
env_ = DC_OFFSET;
}
//-------------------------------------------------------------
// simple gate with RMS detection
//-------------------------------------------------------------
SimpleGateRms::SimpleGateRms()
: ave_( 5.0 )
, aveOfSqrs_( DC_OFFSET )
{
}
//-------------------------------------------------------------
void SimpleGateRms::setSampleRate( double sampleRate )
{
SimpleGate::setSampleRate( sampleRate );
ave_.setSampleRate( sampleRate );
}
//-------------------------------------------------------------
void SimpleGateRms::setWindow( double ms )
{
ave_.setTc( ms );
}
//-------------------------------------------------------------
void SimpleGateRms::initRuntime( void )
{
SimpleGate::initRuntime();
aveOfSqrs_ = DC_OFFSET;
}
} // end namespace chunkware_simple

View File

@ -1,101 +0,0 @@
/*
* Simple Gate (header)
*
* File : SimpleGate.h
* Library : SimpleSource
* Version : 1.12
* Class : SimpleGate, SimpleGateRms
*
* © 2006, ChunkWare Music Software, OPEN-SOURCE
*
* 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 __SIMPLE_GATE_H__
#define __SIMPLE_GATE_H__
#include "SimpleHeader.h" // common header
#include "SimpleEnvelope.h" // for base class
#include "SimpleGain.h" // for gain functions
namespace chunkware_simple
{
//-------------------------------------------------------------
// simple gate
//-------------------------------------------------------------
class SimpleGate : public AttRelEnvelope
{
public:
SimpleGate();
virtual ~SimpleGate() {}
// parameters
virtual void setThresh( double dB );
virtual double getThresh( void ) const { return threshdB_; }
// runtime
virtual void initRuntime( void ); // call before runtime (in resume())
void process( double &in1, double &in2 ); // gate runtime process
void process( double &in1, double &in2, double keyLinked ); // with stereo-linked key in
private:
// transfer function
double threshdB_; // threshold (dB)
double thresh_; // threshold (linear)
// runtime variables
double env_; // over-threshold envelope (linear)
}; // end SimpleGate class
//-------------------------------------------------------------
// simple gate with RMS detection
//-------------------------------------------------------------
class SimpleGateRms : public SimpleGate
{
public:
SimpleGateRms();
virtual ~SimpleGateRms() {}
// sample rate
virtual void setSampleRate( double sampleRate );
// RMS window
virtual void setWindow( double ms );
virtual double getWindow( void ) const { return ave_.getTc(); }
// runtime process
virtual void initRuntime( void ); // call before runtime (in resume())
void process( double &in1, double &in2 ); // gate runtime process
private:
EnvelopeDetector ave_; // averager
double aveOfSqrs_; // average of squares
}; // end SimpleGateRms class
} // end namespace chunkware_simple
// include inlined process function
#include "SimpleGateProcess.inl"
#endif // end __SIMPLE_GATE_H__

View File

@ -1,106 +0,0 @@
/*
* Simple Gate (runtime function)
*
* File : SimpleGateProcess.inl
* Library : SimpleSource
* Version : 1.12
* Implements : void SimpleGate::process( double &in1, double &in2 )
* void SimpleGate::process( double &in1, double &in2, double keyLinked )
* void SimpleGateRms::process( double &in1, double &in2 )
*
* © 2006, ChunkWare Music Software, OPEN-SOURCE
*
* 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 __SIMPLE_GATE_PROCESS_INL__
#define __SIMPLE_GATE_PROCESS_INL__
namespace chunkware_simple
{
//-------------------------------------------------------------
INLINE void SimpleGate::process( double &in1, double &in2 )
{
// create sidechain
double rect1 = fabs( in1 ); // rectify input
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
}
//-------------------------------------------------------------
INLINE void SimpleGate::process( double &in1, double &in2, double keyLinked )
{
keyLinked = fabs( keyLinked ); // rectify (just in case)
// threshold
// key over threshold ( 0.0 or 1.0 )
double over = double( keyLinked > thresh_ );
// attack/release
over += DC_OFFSET; // add DC offset to avoid denormal
AttRelEnvelope::run( over, env_ ); // run attack/release
over = env_ - DC_OFFSET; // subtract DC offset
/* 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,
* thereby avoiding denormals. However, to prevent the offset from causing
* constant gain reduction, we must subtract it from the envelope, yielding
* a minimum value of 0dB.
*/
// output gain
in1 *= over; // apply gain reduction to input
in2 *= over;
}
//-------------------------------------------------------------
INLINE void SimpleGateRms::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
ave_.run( sum, aveOfSqrs_ ); // average of squares
double rms = sqrt( aveOfSqrs_ ); // 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.
*/
SimpleGate::process( in1, in2, rms ); // rest of process
}
} // end namespace chunkware_simple
#endif // end __SIMPLE_GATE_PROCESS_INL__

View File

@ -1,102 +0,0 @@
/*
* Simple Limiter (source)
*
* File : SimpleLimit.cpp
* Library : SimpleSource
* Version : 1.12
* Implements : SimpleLimit
*
* © 2006, ChunkWare Music Software, OPEN-SOURCE
*
* 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 "SimpleLimit.h"
namespace chunkware_simple
{
//-------------------------------------------------------------
SimpleLimit::SimpleLimit()
: threshdB_( 0.0 )
, thresh_( 1.0 )
, peakHold_( 0 )
, peakTimer_( 0 )
, maxPeak_( 1.0 )
, att_( 1.0 )
, rel_( 10.0 )
, env_( 1.0 )
, mask_( BUFFER_SIZE - 1 )
, cur_( 0 )
{
setAttack( 1.0 );
outBuffer_[ 0 ].resize( BUFFER_SIZE, 0.0 );
outBuffer_[ 1 ].resize( BUFFER_SIZE, 0.0 );
}
//-------------------------------------------------------------
void SimpleLimit::setThresh( double dB )
{
threshdB_ = dB;
thresh_ = dB2lin( dB );
}
//-------------------------------------------------------------
void SimpleLimit::setAttack( double ms )
{
unsigned int samp = int( 0.001 * ms * att_.getSampleRate() );
assert( samp < BUFFER_SIZE );
peakHold_ = samp;
att_.setTc( ms );
}
//-------------------------------------------------------------
void SimpleLimit::setRelease( double ms )
{
rel_.setTc( ms );
}
//-------------------------------------------------------------
void SimpleLimit::setSampleRate( double sampleRate )
{
att_.setSampleRate( sampleRate );
rel_.setSampleRate( sampleRate );
}
//-------------------------------------------------------------
void SimpleLimit::initRuntime( void )
{
peakTimer_ = 0;
maxPeak_ = thresh_;
env_ = thresh_;
cur_ = 0;
outBuffer_[ 0 ].assign( BUFFER_SIZE, 0.0 );
outBuffer_[ 1 ].assign( BUFFER_SIZE, 0.0 );
}
//-------------------------------------------------------------
void SimpleLimit::FastEnvelope::setCoef( void )
{
// rises to 99% of in value over duration of time constant
coef_ = pow( 0.01, (1000.0 / (ms_ * sampleRate_) ) );
}
} // end namespace chunkware_simple

View File

@ -1,117 +0,0 @@
/*
* Simple Limiter (header)
*
* File : SimpleLimit.h
* Library : SimpleSource
* Version : 1.12
* Class : SimpleLimit
*
* © 2006, ChunkWare Music Software, OPEN-SOURCE
*
* 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 __SIMPLE_LIMIT_H__
#define __SIMPLE_LIMIT_H__
#include "SimpleHeader.h" // common header
#include "SimpleEnvelope.h" // for base class of FastEnvelope
#include "SimpleGain.h" // for gain functions
#include <vector>
namespace chunkware_simple
{
//-------------------------------------------------------------
// simple limiter
//-------------------------------------------------------------
class SimpleLimit
{
public:
SimpleLimit();
virtual ~SimpleLimit() {}
// parameters
virtual void setThresh( double dB );
virtual void setAttack( double ms );
virtual void setRelease( double ms );
virtual double getThresh( void ) const { return threshdB_; }
virtual double getAttack( void ) const { return att_.getTc(); }
virtual double getRelease( void ) const { return rel_.getTc(); }
// latency
virtual const unsigned int getLatency( void ) const { return peakHold_; }
// sample rate dependencies
virtual void setSampleRate( double sampleRate );
virtual double getSampleRate( void ) { return att_.getSampleRate(); }
// runtime
virtual void initRuntime( void ); // call before runtime (in resume())
void process( double &in1, double &in2 ); // limiter runtime process
protected:
// class for faster attack/release
class FastEnvelope : public EnvelopeDetector
{
public:
FastEnvelope( double ms = 1.0, double sampleRate = 44100.0 )
: EnvelopeDetector( ms, sampleRate )
{}
virtual ~FastEnvelope() {}
protected:
// override setCoef() - coefficient calculation
virtual void setCoef( void );
};
private:
// transfer function
double threshdB_; // threshold (dB)
double thresh_; // threshold (linear)
// max peak
unsigned int peakHold_; // peak hold (samples)
unsigned int peakTimer_; // peak hold timer
double maxPeak_; // max peak
// attack/release envelope
FastEnvelope att_; // attack
FastEnvelope rel_; // release
double env_; // over-threshold envelope (linear)
// buffer
// BUFFER_SIZE default can handle up to ~10ms at 96kHz
// change this if you require more
static const int BUFFER_SIZE = 1024; // buffer size (always a power of 2!)
unsigned int mask_; // buffer mask
unsigned int cur_; // cursor
std::vector< double > outBuffer_[ 2 ]; // output buffer
}; // end SimpleLimit class
} // end namespace chunkware_simple
// include inlined process function
#include "SimpleLimitProcess.inl"
#endif // end __SIMPLE_LIMIT_H__

View File

@ -1,139 +0,0 @@
/*
* Simple Limiter (runtime function)
*
* File : SimpleLimitProcess.inl
* Library : SimpleSource
* Version : 1.12
* Implements : void SimpleLimit::process( double &in1, double &in2 )
*
* © 2006, ChunkWare Music Software, OPEN-SOURCE
*
* 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 __SIMPLE_LIMIT_PROCESS_INL__
#define __SIMPLE_LIMIT_PROCESS_INL__
namespace chunkware_simple
{
//-------------------------------------------------------------
INLINE void SimpleLimit::process( double &in1, double &in2 )
{
// create sidechain
double rect1 = fabs( in1 ); // rectify input
double rect2 = fabs( in2 );
double keyLink = std::max( rect1, rect2 ); // link channels with greater of 2
// threshold
// we always want to feed the sidechain AT LEATS the threshold value
if ( keyLink < thresh_ )
keyLink = thresh_;
// test:
// a) whether peak timer has "expired"
// b) whether new peak is greater than previous max peak
if ( (++peakTimer_ >= peakHold_) || (keyLink > maxPeak_) ) {
// if either condition is met:
peakTimer_ = 0; // reset peak timer
maxPeak_ = keyLink; // assign new peak to max peak
}
/* REGARDING THE MAX PEAK: This method assumes that the only important
* sample in a look-ahead buffer would be the highest peak. As such,
* instead of storing all samples in a look-ahead buffer, it only stores
* the max peak, and compares all incoming samples to that one.
* The max peak has a hold time equal to what the look-ahead buffer
* would have been, which is tracked by a timer (counter). When this
* timer expires, the sample would have exited from the buffer. Therefore,
* a new sample must be assigned to the max peak. We assume that the next
* highest sample in our theoretical buffer is the current input sample.
* In reality, we know this is probably NOT the case, and that there has
* been another sample, slightly lower than the one before it, that has
* passed the input. If we do not account for this possibility, our gain
* reduction could be insufficient, resulting in an "over" at the output.
* To remedy this, we simply apply a suitably long release stage in the
* envelope follower.
*/
// attack/release
if ( maxPeak_ > env_ )
att_.run( maxPeak_, env_ ); // run attack phase
else
rel_.run( maxPeak_, env_ ); // run release phase
/* REGARDING THE ATTACK: This limiter achieves "look-ahead" detection
* by allowing the envelope follower to attack the max peak, which is
* held for the duration of the attack phase -- unless a new, higher
* peak is detected. The output signal is buffered so that the gain
* reduction is applied in advance of the "offending" sample.
*/
/* NOTE: a DC offset is not necessary for the envelope follower,
* as neither the max peak nor envelope should fall below the
* threshold (which is assumed to be around 1.0 linear).
*/
// gain reduction
double gR = thresh_ / env_;
// unload current buffer index
// ( cur_ - delay ) & mask_ gets sample from [delay] samples ago
// mask_ variable wraps index
unsigned int delayIndex = ( cur_ - peakHold_ ) & mask_;
double delay1 = outBuffer_[ 0 ][ delayIndex ];
double delay2 = outBuffer_[ 1 ][ delayIndex ];
// load current buffer index and advance current index
// mask_ wraps cur_ index
outBuffer_[ 0 ][ cur_ ] = in1;
outBuffer_[ 1 ][ cur_ ] = in2;
++cur_ &= mask_;
// output gain
in1 = delay1 * gR; // apply gain reduction to input
in2 = delay2 * gR;
/* REGARDING THE GAIN REDUCTION: Due to the logarithmic nature
* of the attack phase, the sidechain will never achieve "full"
* attack. (Actually, it is only guaranteed to achieve 99% of
* the input value over the given time constant.) As such, the
* limiter cannot achieve "brick-wall" limiting. There are 2
* workarounds:
*
* 1) Set the threshold slightly lower than the desired threshold.
* i.e. 0.0dB -> -0.1dB or even -0.5dB
*
* 2) Clip the output at the threshold, as such:
*
* if ( in1 > thresh_ ) in1 = thresh_;
* else if ( in1 < -thresh_ ) in1 = -thresh_;
*
* if ( in2 > thresh_ ) in2 = thresh_;
* else if ( in2 < -thresh_ ) in2 = -thresh_;
*
* (... or replace with your favorite branchless clipper ...)
*/
}
} // end namespace chunkware_simple
#endif // end __SIMPLE_LIMIT_PROCESS_INL__