Audacity 3.2.0
GainReductionComputer.cpp
Go to the documentation of this file.
1/*
2 This file is part of the SimpleCompressor project.
3 https://github.com/DanielRudrich/SimpleCompressor
4 Copyright (c) 2019 Daniel Rudrich
5
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, version 3.
9
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
20#include "MathApprox.h"
21
22namespace DanielRudrich {
23namespace
24{
25float getSlope(float ratio) { return 1 / ratio - 1; }
26float getRatio(float slope) { return 1 / (slope + 1); }
27} // namespace
28
29float GainReductionComputer::getCharacteristicSample(float inputLevelInDecibels,
30 float kneeInDecibels,
31 float thresholdInDecibels,
32 float ratio,
33 float makeUpGainInDecibels)
34{
35 const auto slope = getSlope(ratio);
36 float overShoot = inputLevelInDecibels - thresholdInDecibels;
37 overShoot = applyCharacteristicToOverShoot(overShoot, kneeInDecibels, slope);
38 return overShoot + inputLevelInDecibels + makeUpGainInDecibels;
39}
40
42{
43 sampleRate = 0.0f;
44
45 threshold = -10.0f;
46 knee = 0.0f;
47 kneeHalf = 0.0f;
48 attackTime = 0.01f;
49 releaseTime = 0.15f;
50 setRatio (2); // 2 : 1
51 makeUpGain = 0.0f;
52 reset();
53}
54
55void GainReductionComputer::prepare (const double newSampleRate)
56{
57 sampleRate = newSampleRate;
58
61}
62
63void GainReductionComputer::setAttackTime (const float attackTimeInSeconds)
64{
65 attackTime = attackTimeInSeconds;
67}
68
69void GainReductionComputer::setReleaseTime (const float releaseTimeInSeconds)
70{
71 releaseTime = releaseTimeInSeconds;
73}
74
75const float GainReductionComputer::timeToGain (const float timeInSeconds)
76{
77 return std::exp (-1.0f / (static_cast<float> (sampleRate) * timeInSeconds));
78}
79
80void GainReductionComputer::setKnee (const float kneeInDecibels)
81{
82 knee = kneeInDecibels;
83 kneeHalf = knee / 2.0f;
84}
85
86void GainReductionComputer::setThreshold (const float thresholdInDecibels)
87{
88 threshold = thresholdInDecibels;
89}
90
91void GainReductionComputer::setMakeUpGain (const float makeUpGainInDecibels)
92{
93 makeUpGain = makeUpGainInDecibels;
94}
95
96void GainReductionComputer::setRatio (const float ratio)
97{
98 slope = getSlope(ratio);
99}
100
101
102inline const float GainReductionComputer::applyCharacteristicToOverShoot (const float overShootInDecibels)
103{
104 return applyCharacteristicToOverShoot(overShootInDecibels, knee, slope);
105}
106
108 float overShootInDecibels, float knee, float slope)
109{
110 const auto kneeHalf = knee / 2;
111 if (overShootInDecibels <= -kneeHalf)
112 return 0.0f;
113 else if (overShootInDecibels > -kneeHalf && overShootInDecibels <= kneeHalf)
114 return 0.5f * slope * (overShootInDecibels + kneeHalf) * (overShootInDecibels + kneeHalf) / knee;
115 else
116 return slope * overShootInDecibels;
117}
118
119void GainReductionComputer::computeGainInDecibelsFromSidechainSignal (const float* sideChainSignal, float* destination, const int numSamples)
120{
121 maxInputLevel = -std::numeric_limits<float>::infinity();
122 maxGainReduction = 0.0f;
123
124 for (int i = 0; i < numSamples; ++i)
125 {
126 // convert sample to decibels
127 const float levelInDecibels =
128 log2ToDb * FastLog2(std::abs(sideChainSignal[i]));
129
130 if (levelInDecibels > maxInputLevel)
131 maxInputLevel = levelInDecibels;
132
133 // calculate overshoot and apply knee and ratio
134 const float overShoot = levelInDecibels - threshold;
135 const float gainReduction = applyCharacteristicToOverShoot (overShoot);
136
137 // apply ballistics
138 const float diff = gainReduction - state;
139 if (diff < 0.0f) // wanted gain reduction is below state -> attack phase
140 state += alphaAttack * diff;
141 else // release phase
142 state += alphaRelease * diff;
143
144 // write back gain reduction
145 destination[i] = state;
146
149 }
150}
151
152void GainReductionComputer::computeLinearGainFromSidechainSignal (const float* sideChainSignal, float* destination, const int numSamples)
153{
154 computeGainInDecibelsFromSidechainSignal (sideChainSignal, destination, numSamples);
155 for (int i = 0; i < numSamples; ++i)
156 destination[i] = std::pow (10.0f, 0.05f * (destination[i] + makeUpGain));
157}
158
159
160void GainReductionComputer::getCharacteristic (float* inputLevelsInDecibels, float* dest, const int numSamples)
161{
162 for (int i = 0; i < numSamples; ++i)
163 dest[i] = getCharacteristicSample (inputLevelsInDecibels[i]);
164}
165
166float GainReductionComputer::getCharacteristicSample (const float inputLevelInDecibels)
167{
168 return getCharacteristicSample(inputLevelInDecibels, knee, threshold,
170}
171} // namespace DanielRudrich
constexpr float FastLog2(float x)
Approximates the base-2 logarithm of a float to two decimal places, adapted from https://stackoverflo...
Definition: MathApprox.h:32
static constexpr float log2ToDb
Definition: MathApprox.h:46
void prepare(const double sampleRate)
void setMakeUpGain(const float makeUpGainInDecibels)
void getCharacteristic(float *inputLevelsInDecibels, float *destination, const int numSamples)
static float getCharacteristicSample(float inputLevelInDecibels, float kneeInDecibels, float thresholdInDecibels, float ratio, float makeUpGainInDecibels)
void computeGainInDecibelsFromSidechainSignal(const float *sideChainSignal, float *destination, const int numSamples)
static float applyCharacteristicToOverShoot(float overShootInDecibels, float knee, float slope)
void setThreshold(const float thresholdInDecibels)
void setReleaseTime(const float releaseTimeInSeconds)
void setAttackTime(const float attackTimeInSeconds)
void setKnee(const float kneeInDecibels)
const float timeToGain(const float timeInSeconds)
void computeLinearGainFromSidechainSignal(const float *sideChainSignal, float *destination, const int numSamples)