-
Notifications
You must be signed in to change notification settings - Fork 6
/
PeakLevelDetector.cpp
153 lines (126 loc) · 2.91 KB
/
PeakLevelDetector.cpp
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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#include "PeakLevelDetector.h"
PeakLevelDetector::PeakLevelDetector(float sampleRate)
{
setDetector(sampleRate);
}
PeakLevelDetector::~PeakLevelDetector() {}
float PeakLevelDetector::tick(float inputSample)
{
inputAbs = fabs(inputSample);
if (inputAbs > peakOutput)
{
b0 = b0Attack;
}
else
{
b0 = b0Release;
}
// Simplified filter equation (out = b0 * input + a1 * lastOut)
peakOutput += b0 * (inputAbs - peakOutput);
return peakOutput;
}
void PeakLevelDetector::setDetector(float sampleRate)
{
fs = sampleRate;
peakOutput = 0.f;
// set coefficients for leaky integrator
b0Attack = 1.f;
a1 = expf(-1 / (releaseTime * fs));
b0Release = 1.f - a1;
}
// Times are in seconds (e.g. 100ms = 0.1f, 1.2s = 1.2f)
GainDynamics::GainDynamics(float sampleRate, float newAttackTime, float newReleaseTime)
{
attackTime = newAttackTime;
releaseTime = newReleaseTime;
setDetector(sampleRate);
}
GainDynamics::~GainDynamics() {}
float GainDynamics::tick(float inputGain)
{
if (inputGain < outputGain)
{ // Isn't this suppose to be (input > lastOutput)?
b0 = b0Attack;
}
else
{
b0 = b0Release;
}
// Simplified filter equation (out = b0 * input + a1 * lastOut)
outputGain += b0 * (inputGain - outputGain);
return outputGain;
}
void GainDynamics::setDetector(float sampleRate)
{
fs = sampleRate;
outputGain = 0.f;
setAttack(attackTime);
setRelease(releaseTime);
}
void GainDynamics::setAttack(float newAttackTime)
{
attackTime = newAttackTime;
b0Attack = 1. - expf(-1. / (attackTime * fs));
}
void GainDynamics::setRelease(float newReleaseTime)
{
releaseTime = newReleaseTime;
b0Release = 1. - expf(-1. / (releaseTime * fs));
}
AudioProcessor::AudioProcessor()
{
thresholdDb = DEFAULT_THRESHOLD;
ratio = DEFAULT_RATIO;
attackTime = DEFAULT_ATTACK;
releaseTime = DEFAULT_RELEASE;
}
void AudioProcessor::prepareToPlay(double sampleRate)
{
// Use this method as the place to do any pre-playback
// initialisation that you need..
fs = sampleRate;
gain = 1.f;
if (LevelDetector == nullptr)
{
LevelDetector = std::make_unique<PeakLevelDetector>(sampleRate);
}
else
{
LevelDetector->setDetector(sampleRate);
}
if (gainDymanics == nullptr)
{
gainDymanics = std::make_unique<GainDynamics>(sampleRate, attackTime, releaseTime);
}
else
{
gainDymanics->setDetector(sampleRate);
}
}
void AudioProcessor::processBlock(SampleVector &buffer)
{
// This is the place where you'd normally do the guts of your plugin's
// audio processing...
for (int i = 0; i < buffer.size(); i++)
{
// Peak detector
peakOut = LevelDetector->tick(buffer[i]);
// Convert to db
peakSumDb = dB(peakOut);
// Calculate gain
if (peakSumDb < thresholdDb)
{
gainDb = 0.f;
}
else
{
gainDb = -(peakSumDb - thresholdDb) * (1.f - 1.f / ratio);
}
// Gain dynamics (attack and release)
gainDb = gainDymanics->tick(gainDb);
// Convert to Linear
gain = dB2mag(gainDb);
// Apply gain
buffer[i] *= gain;
}
}