-
Notifications
You must be signed in to change notification settings - Fork 0
/
Compressor.cpp
94 lines (81 loc) · 3.11 KB
/
Compressor.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
// Compressor.cpp
#include "Compressor.h"
#include <algorithm>
#include <cmath>
Compressor::Compressor(float threshold, float ratio, float attackTime, float releaseTime, float kneeWidth, float makeupGain, float sampleRate)
: threshold_(dBToLinear(threshold)), ratio_(ratio), attackTime_(attackTime), releaseTime_(releaseTime), kneeWidth_(dBToLinear(kneeWidth)), makeupGain_(dBToLinear(makeupGain)), envelope_(0.0f),
gain_(1.0f), sampleRate_(sampleRate)
{
// Calculate attack and release coefficients based on sample rate
updateCoefficients();
}
float Compressor::process(float inputSample)
{
// Calculate the envelope of the input sample
float inputMagnitude = std::fabs(inputSample); // get the absolute value of the input
if (inputMagnitude > envelope_) // if the absolute value of the input is greater than the envelope
{
envelope_ += attackCoefficient_ * (inputMagnitude - envelope_); // attack phase
}
else
{
envelope_ += releaseCoefficient_ * (inputMagnitude - envelope_); // release phase
}
// Calculate desired gain
float desiredGain;
if (envelope_ <= threshold_ - kneeWidth_ / 2) // if the envelope is below the threshold
{
desiredGain = 1.0f; // no compression
}
else if (envelope_ > threshold_ + kneeWidth_ / 2) // if the envelope is above the threshold
{
desiredGain = powf(envelope_ / threshold_, -ratio_); // apply compression
}
else
{
// We're in the 'knee'. interpolate smoothly between uncompressed and compressed.
float x = (envelope_ - threshold_ + kneeWidth_ / 2) / kneeWidth_; // calculate the x value
desiredGain = powf(1.0f + (ratio_ - 1.0f) * x * x, -1.0f); // interpolate between uncompressed and compressed
}
// Smooth gain
gain_ = desiredGain + (attackCoefficient_ * (desiredGain - gain_));
// Apply makeup gain
return inputSample * gain_ * makeupGain_; // apply makeup gain
}
void Compressor::setThreshold(float threshold) // set the threshold
{
threshold_ = dBToLinear(threshold);
}
void Compressor::setRatio(float ratio) // set the ratio
{
ratio_ = ratio;
}
void Compressor::setAttackTime(float attackTime) // set the attack time
{
attackTime_ = attackTime;
updateCoefficients();
}
void Compressor::setReleaseTime(float releaseTime) // set the release time
{
releaseTime_ = releaseTime;
updateCoefficients();
}
void Compressor::setKneeWidth(float kneeWidth) // set the knee width
{
kneeWidth_ = dBToLinear(kneeWidth); // convert dB to linear scale
}
void Compressor::setMakeupGain(float makeupGain) // set the makeup gain
{
makeupGain_ = dBToLinear(makeupGain);
}
// Convert dB to linear scale
float Compressor::dBToLinear(float dB)
{
return powf(10.0f, dB / 20.0f); // convert dB to linear scale
}
// Update attack and release coefficients
void Compressor::updateCoefficients()
{
attackCoefficient_ = 1.0f - std::exp(-1.0f / (attackTime_ * sampleRate_)); // calculate the attack coefficient
releaseCoefficient_ = 1.0f - std::exp(-1.0f / (releaseTime_ * sampleRate_)); // calculate the release coefficient
}