Loopp/src/dsp/dsp_sidechain_gain.cxx

106 lines
2.6 KiB
C++

/*
* Author: Harry van Haaren 2013
* harryhaaren@gmail.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "dsp_sidechain_gain.hxx"
// for pow()
#include <cmath>
SidechainGain::SidechainGain(int rate) :
/// initial control values
controlThreshold(0.2),
controlReduction(1),
controlReleaseTime(0.5),
/// filter state init
w(10.0f / (rate * 0.02)),
a(0.07f),
b(1.0f / (1.0f - a)),
g1(0.0f),
g2(0.0f),
peakFrameCounter(0),
peakCountDuration( rate / 4 ),
currentTarget(0)
{
}
void SidechainGain::process(unsigned int n_samples, float** inputs, float** outputs)
{
/// audio inputs
float* inL = inputs[0];
float* inR = inputs[1];
float* side = inputs[2];
float* outL = outputs[0];
float* outR = outputs[1];
/// control inputs
float threshold = controlThreshold;
float reduction = controlReduction;
float releaseTime = controlReleaseTime;
/// analyse sidechain input for peak
float sum = 0.f;
for( unsigned int i = 0; i < n_samples; i++ )
{
if ( *side > 0.000001 )
sum += *side++;
else
sum += -*side++;
}
currentTarget = 0.f;
/// check for peak level (offset to avoid "always on" peak)
if ( sum / n_samples > threshold + 0.05 )
{
peakFrameCounter = peakCountDuration * releaseTime;
currentTarget = 1.f - reduction;
}
else if ( peakFrameCounter < 0 )
{
currentTarget = 1.f;
}
else
{
currentTarget = 1.f - reduction;
}
if ( currentTarget < 0.f )
currentTarget = 0.f;
peakFrameCounter -= n_samples;
for( unsigned int i = 0; i < n_samples; i++ )
{
/// smoothing algo is a lowpass, to de-zip the fades
/// x^^4 approximates linear volume increase for human ears
g1 += w * ( pow ( currentTarget, 4.f ) - g1 - a * g2 - 1e-20f);
g2 += w * (b * g1 - g2 + 1e-20f);
float gain = g2;
*outL++ = *inL++ * gain;
*outR++ = *inR++ * gain;
}
/// update output value
controlSidechainAmp = currentTarget;
}