11namespace tracktion {
inline namespace engine
14CompressorPlugin::CompressorPlugin (PluginCreationInfo info) : Plugin (info)
16 thresholdGain = addParam (
"threshold",
TRANS(
"Threshold"), { 0.01f, 1.0f },
17 [] (
float value) {
return gainToDbString (value); },
18 [] (
const juce::String& s) {
return dbStringToGain (s); });
20 ratio = addParam (
"ratio",
TRANS(
"Ratio"), { 0.0f, 0.95f },
21 [] (
float value) {
return (value > 0.001f ?
juce::String (1.0f / value, 2)
22 :
juce::String (
"INF")) +
" : 1"; },
23 [] (
const juce::String& s) {
return s.getFloatValue(); });
25 attackMs = addParam (
"attack",
TRANS(
"Attack"), { 0.3f, 200.0f },
26 [] (
float value) {
return juce::String (value, 1) +
" ms"; },
29 releaseMs = addParam (
"release",
TRANS(
"Release"), { 10.0f, 300.0f },
30 [] (
float value) {
return juce::String (value, 1) +
" ms"; },
33 outputDb = addParam (
"output gain",
TRANS(
"Output gain"), { -10.0f, 24.0f },
35 [] (
const juce::String& s) {
return dbStringToDb (s); });
37 sidechainDb = addParam (
"input gain",
TRANS(
"Sidechain gain"), { -24.0f, 24.0f },
39 [] (
const juce::String& s) {
return dbStringToDb (s); });
41 auto um = getUndoManager();
43 thresholdValue.referTo (state, IDs::threshold, um, dbToGain (-6.0f));
44 thresholdGain->attachToCurrentValue (thresholdValue);
46 ratioValue.referTo (state, IDs::ratio, um, 0.5f);
47 ratio->attachToCurrentValue (ratioValue);
49 attackValue.referTo (state, IDs::attack, um, 100.0f);
50 attackMs->attachToCurrentValue (attackValue);
52 releaseValue.referTo (state, IDs::release, um, 100.0f);
53 releaseMs->attachToCurrentValue (releaseValue);
55 outputValue.referTo (state, IDs::outputDb, um);
56 outputDb->attachToCurrentValue (outputValue);
58 useSidechainTrigger.referTo (state, IDs::sidechainTrigger, um);
60 sidechainValue.referTo (state, IDs::inputDb, um);
61 sidechainDb->attachToCurrentValue (sidechainValue);
64CompressorPlugin::~CompressorPlugin()
66 notifyListenersOfDeletion();
68 thresholdGain->detachFromCurrentValue();
69 ratio->detachFromCurrentValue();
70 attackMs->detachFromCurrentValue();
71 releaseMs->detachFromCurrentValue();
72 outputDb->detachFromCurrentValue();
73 sidechainDb->detachFromCurrentValue();
76const char* CompressorPlugin::xmlTypeName =
"compressor";
81 Plugin::getChannelNames (ins, outs);
84 ins->
add (
TRANS(
"Sidechain Trigger"));
93void CompressorPlugin::deinitialise()
97static const float preFilterAmount = 0.9f;
104 SCOPED_REALTIME_CHECK
106 const double logThreshold =
std::log10 (0.01);
107 const double attackFactor =
std::pow (10.0, logThreshold / (attackMs->getCurrentValue() * sampleRate / 1000.0));
108 const double releaseFactor =
std::pow (10.0, logThreshold / (releaseMs->getCurrentValue() * sampleRate / 1000.0));
109 const float outputGain = dbToGain (outputDb->getCurrentValue());
110 const float thresh = thresholdGain->getCurrentValue();
111 const float rat = ratio->getCurrentValue();
112 const bool useSidechain = useSidechainTrigger.get();
113 const float sidechainGain = dbToGain (sidechainDb->getCurrentValue());
124 float samp1 = *b1 + 1.0f;
126 float samp2 = *b2 + 1.0f;
129 float sampAvg = 0.0f;
131 if (useSidechain && b3 !=
nullptr)
133 sampAvg = lastSamp * preFilterAmount
134 + std::abs (*b3++ * sidechainGain) * ((1.0f - preFilterAmount));
138 sampAvg = lastSamp * preFilterAmount
139 + std::abs (samp1 + samp2) * ((1.0f - preFilterAmount) * 0.5f);
146 if (sampAvg > thresh)
147 currentLevel = (currentLevel - sampAvg) * attackFactor + sampAvg;
149 currentLevel = (currentLevel - sampAvg) * releaseFactor + sampAvg;
151 float r = outputGain;
153 if (currentLevel > thresh)
155 r *= (
float)((thresh + (currentLevel - thresh) * rat)
167 const float samp = *b1;
168 const float sampAvg = lastSamp * preFilterAmount
169 + std::abs (samp) * (1.0f - preFilterAmount);
174 if (sampAvg > thresh)
175 currentLevel = (currentLevel - sampAvg) * attackFactor + sampAvg;
177 currentLevel = (currentLevel - sampAvg) * releaseFactor + sampAvg;
179 float r = outputGain;
181 if (currentLevel > thresh)
182 r *= (
float)((thresh + (currentLevel - thresh) * rat) / currentLevel);
191float CompressorPlugin::getThreshold()
const
193 return thresholdGain->getCurrentValue();
196void CompressorPlugin::setThreshold (
float t)
198 thresholdGain->setParameter (
juce::jlimit (getMinThreshold(),
199 getMaxThreshold(), t),
203float CompressorPlugin::getRatio()
const
205 return ratio->getCurrentValue();
208void CompressorPlugin::setRatio (
float r)
214void CompressorPlugin::restorePluginStateFromValueTree (
const juce::ValueTree& v)
216 copyPropertiesToCachedValues (v, thresholdValue, ratioValue, attackValue, releaseValue,
217 outputValue, sidechainValue, useSidechainTrigger);
219 for (
auto p : getAutomatableParameters())
220 p->updateFromAttachedValue();
225 if (v == state &&
id == IDs::sidechainTrigger)
228 Plugin::valueTreePropertyChanged (v,
id);
Type * getWritePointer(int channelNumber) noexcept
int getNumChannels() const noexcept
static String toString(Type decibels, int decimalPlaces=2, Type minusInfinityDb=Type(defaultMinusInfinitydB), bool shouldIncludeSuffix=true, StringRef customMinusInfinityString={})
void add(String stringToAdd)
float getFloatValue() const noexcept
#define TRANS(stringLiteral)
#define JUCE_UNDENORMALISE(x)
Type jlimit(Type lowerLimit, Type upperLimit, Type valueToConstrain) noexcept
Passed into Plugins when they are being initialised, to give them useful contextual information that ...
The context passed to plugin render methods to provide it with buffers to fill.
int bufferNumSamples
The number of samples to write into the audio buffer.
juce::AudioBuffer< float > * destBuffer
The target audio buffer which needs to be filled.
int bufferStartSample
The index of the start point in the audio buffer from which data must be written.