1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
|
/*
This file is part of the SimpleCompressor project.
https://github.com/DanielRudrich/SimpleCompressor
Copyright (c) 2019 Daniel Rudrich
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, version 3.
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/>.
*/
#pragma once
#include <vector>
#include <limits>
#include <cmath>
#include <atomic>
namespace DanielRudrich {
/**
This class acts as the side-chain path of a dynamic range compressor. It processes a given side-chain signal and computes the gain reduction samples depending on the parameters threshold, knee, attack-time, release-time, ratio, and make-up gain.
*/
class GainReductionComputer
{
public:
GainReductionComputer();
~GainReductionComputer() {}
static float getCharacteristicSample(float inputLevelInDecibels,
float kneeInDecibels,
float thresholdInDecibels, float ratio,
float makeUpGainInDecibels);
// ======================================================================
/**
Sets the attack time of the compressor in seconds.
*/
void setAttackTime (const float attackTimeInSeconds);
/**
Sets the release time of the compressorin seconds
*/
void setReleaseTime (const float releaseTimeInSeconds);
/**
Sets the knee-width in decibels.
*/
void setKnee (const float kneeInDecibels);
const float getKnee() { return knee; }
/**
Sets the threshold above which the compressor will start to compress the signal.
*/
void setThreshold (const float thresholdInDecibels);
const float getThreshold() { return threshold; }
/**
Sets the make-up-gain of the compressor in decibels.
*/
void setMakeUpGain (const float makeUpGainInDecibels);
const float getMakeUpGain() { return makeUpGain; }
/**
Sets the ratio of input-output signal above threshold. Set to 1 for no compression, up to infinity for a brickwall limiter.
*/
void setRatio (const float ratio);
// ======================================================================
/**
Computes the static output levels for an array of input levels in decibels. Useful for visualization of the compressor's characteristic. Will contain make-up gain.
*/
void getCharacteristic (float* inputLevelsInDecibels, float* destination, const int numSamples);
/**
Computes the static output levels for a given input level in decibels. Useful for visualization of the compressor's characteristic. Will contain make-up gain.
*/
float getCharacteristicSample (const float inputLevelInDecibels);
// ======================================================================
/**
Prepares the compressor with sampleRate and expected blockSize. Make sure you call this before you do any processing!
*/
void prepare (const double sampleRate);
/**
Resets the internal state of the compressor.
*/
void reset() { state = 0.0f; }
/**
Computes the gain reduction for a given side-chain signal. The values will be in decibels and will NOT contain the make-up gain.
*/
void computeGainInDecibelsFromSidechainSignal (const float* sideChainSignal, float* destination, const int numSamples);
/**
Computes the linear gain including make-up gain for a given side-chain signal. The gain written to the destination can be directly applied to the signals which should be compressed.
*/
void computeLinearGainFromSidechainSignal (const float* sideChainSignal, float* destination, const int numSamples);
const float getMaxInputLevelInDecibels() { return maxInputLevel; }
const float getMaxGainReductionInDecibels() { return maxGainReduction; }
private:
static float applyCharacteristicToOverShoot(float overShootInDecibels,
float knee, float slope);
inline const float timeToGain (const float timeInSeconds);
inline const float applyCharacteristicToOverShoot (const float overShootInDecibels);
double sampleRate;
// parameters
float knee, kneeHalf;
float threshold;
float attackTime;
float releaseTime;
float slope;
float makeUpGain;
std::atomic<float> maxInputLevel {-std::numeric_limits<float>::infinity()};
std::atomic<float> maxGainReduction {0};
//state variable
float state;
float alphaAttack;
float alphaRelease;
};
} // namespace DanielRudrich
|