11namespace tracktion {
inline namespace engine
28 sampleRate = newSampleRate;
41 float coefficient = 1.0f;
42 float sampleRate = 44100.0f;
44 void update() noexcept
85 sampleRate = newSampleRate;
88 attackCoeff = getDelta (attackTimeMs);
89 releaseCoeff = getDelta (releaseTimeMs);
90 holdSamples = (
int) msToSamples (holdTimeMs, sampleRate);
105 attackTimeMs = attackMs;
106 attackCoeff = getDelta (attackTimeMs);
113 holdSamples = (
int) msToSamples (holdMs, sampleRate);
119 releaseTimeMs = releaseMs;
120 releaseCoeff = getDelta (releaseTimeMs);
126 detectMode = newDetectionMode;
132 if (! setIfDifferent (timeConstantMode, newTC))
135 switch (timeConstantMode)
137 case digitalTC: timeConstant = -2.0f;
break;
138 case slowDigitalTC: timeConstant = -1.0f;
break;
139 case analogTC: timeConstant = -0.43533393574791066201247090699309f;
break;
142 attackCoeff = getDelta (attackTimeMs);
143 releaseCoeff = getDelta (releaseTimeMs);
154 input = std::abs (input);
169 if (input > envelope)
171 envelope = attackCoeff * (envelope - input) + input;
172 holdSamplesLeft = holdSamples;
174 else if (holdSamplesLeft > 0)
180 envelope = releaseCoeff * (envelope - input) + input;
191 float attackCoeff = 0.0f;
192 float releaseCoeff = 0.0f;
193 float envelope = 0.0f;
194 float attackTimeMs = 0.0f;
195 float holdTimeMs = 0.0f;
196 float releaseTimeMs = 0.0f;
197 float sampleRate = 44100.0f;
198 float timeConstant = -2.0f;
199 int holdSamples = 0, holdSamplesLeft = 0;
204 inline float getDelta (
float timeMs)
206 return std::exp (timeConstant / (timeMs * sampleRate * 0.001f));
209 inline double msToSamples (
double numMiliseconds,
double sr)
211 return numMiliseconds * 0.001 * sr;
219EnvelopeFollowerModifier::EnvelopeFollowerModifier (Edit& e,
const juce::ValueTree& v)
222 auto um = &edit.getUndoManager();
224 gainDb.referTo (
state, IDs::gainDb, um, 0.0f);
225 attack.referTo (
state, IDs::attack, um, 100.0f);
226 hold.referTo (
state, IDs::hold, um, 0.0f);
227 release.referTo (
state, IDs::release, um, 500.0f);
228 depth.referTo (
state, IDs::depth, um, 1.0f);
229 offset.referTo (
state, IDs::offset, um, 0.0f);
230 lowPassEnabled.referTo (
state, IDs::lowPassEnabled, um,
false);
231 highPassEnabled.referTo (
state, IDs::highPassEnabled, um,
false);
232 lowPassFrequency.referTo (
state, IDs::lowPassFrequency, um, 2000.0f);
233 highPassFrequency.referTo (
state, IDs::highPassFrequency, um, 500.0f);
239 auto* p =
new DiscreteLabelledParameter (paramID, name, *
this, valueRange, labels.size(), labels);
240 addAutomatableParameter (p);
241 p->attachToCurrentValue (val);
250 valueRange.setSkewForCentre (centreVal);
251 auto* p =
new SuffixedParameter (paramID, name, *
this, valueRange, suffix);
252 addAutomatableParameter (p);
253 p->attachToCurrentValue (val);
260 gainDbParam = addParam (
"gainDb",
TRANS(
"Gain"), { -20.0f, 20.0f, 0.001f }, 0.0f, gainDb,
"dB");
261 attackParam = addParam (
"attack",
TRANS(
"Attack"), { 1.0f, 5000.0f }, 50.0f, attack,
"ms");
262 holdParam = addParam (
"hold",
TRANS(
"Hold"), { 0.0f, 5000.0f }, 50.0f, hold,
"ms");
263 releaseParam = addParam (
"release",
TRANS(
"Release"), { 1.0f, 5000.0f }, 50.0f, release,
"ms");
264 depthParam = addParam (
"depth",
TRANS(
"Depth"), { -1.0f, 1.0f }, 0.0f, depth, {});
265 offsetParam = addParam (
"offset",
TRANS(
"Offset"), { 0.0f, 1.0f }, 0.5f, offset, {});
266 lowPassEnabledParam = addDiscreteParam (
"lowPassEnabled",
TRANS(
"Low-pass Enabled"), { 0.0f, 1.0f }, lowPassEnabled, modifier::getEnabledNames());
267 highPassEnabledParam = addDiscreteParam (
"highPassEnabled",
TRANS(
"High-pass Enabled"), { 0.0f, 1.0f }, highPassEnabled, modifier::getEnabledNames());
268 lowPassFrequencyParam = addParam (
"lowPassFrequency",
TRANS(
"Low-pass Frequency"), freqRange, 700.0f, lowPassFrequency,
"Hz");
269 highPassFrequencyParam = addParam (
"highPassFrequency",
TRANS(
"High-pass Frequency"), freqRange, 700.0f, highPassFrequency,
"Hz");
271 changedTimer.setCallback ([
this]
273 changedTimer.stopTimer();
282EnvelopeFollowerModifier::~EnvelopeFollowerModifier()
285 notifyListenersOfDeletion();
287 for (
auto p : getAutomatableParameters())
288 p->detachFromCurrentValue();
290 deleteAutomatableParameters();
296 return (getEnvelopeValue() * depthParam->getCurrentValue()) + offsetParam->getCurrentValue();
306 return {
TRANS(
"Audio input left"),
307 TRANS(
"Audio input right") };
312 prepareToPlay (newSampleRate);
339 envelopeFollowerModifierID (evm.
itemID)
343bool EnvelopeFollowerModifier::Assignment::isForModifierSource (
const ModifierSource& source)
const
346 return mod->itemID == envelopeFollowerModifierID;
351EnvelopeFollowerModifier::Ptr EnvelopeFollowerModifier::Assignment::getEnvelopeFollowerModifier()
const
353 if (
auto mod = findModifierTypeForID<EnvelopeFollowerModifier> (edit, envelopeFollowerModifierID))
360void EnvelopeFollowerModifier::prepareToPlay (
double newSampleRate)
362 envelopeFollower->setSampleRate ((
float) newSampleRate);
367 envelopeFollower->setAttackTime (attackParam->getCurrentValue());
368 envelopeFollower->setHoldTime (holdParam->getCurrentValue());
369 envelopeFollower->setReleaseTime (releaseParam->getCurrentValue());
377 float envelope = 0.0f;
379 AudioScratchBuffer scratch (1, numSamples);
380 float* scratchData = scratch.buffer.getWritePointer (0);
383 for (
int i = 0; i < numSamples; ++i)
387 for (
int c = 0; c < numChannels; ++c)
388 sample =
std::max (sample, std::abs (samples[c][i]));
390 scratchData[i] =
sample * gainVal;
394 if (setIfDifferent (currentLowPassFrequency, lowPassFrequencyParam->getCurrentValue()))
397 if (setIfDifferent (currentHighPassFrequency, highPassFrequencyParam->getCurrentValue()))
407 for (
int i = 0; i < numSamples; ++i)
408 envelope = envelopeFollower->processSingleSample (scratchData[i]);
414void EnvelopeFollowerModifier::reset()
416 envelopeFollower->reset();
419void EnvelopeFollowerModifier::valueTreeChanged()
int getNumChannels() const noexcept
int getNumSamples() const noexcept
const Type *const * getArrayOfReadPointers() const noexcept
Type *const * getArrayOfWritePointers() noexcept
static Type decibelsToGain(Type decibels, Type minusInfinityDb=Type(defaultMinusInfinitydB))
static IIRCoefficients makeLowPass(double sampleRate, double frequency) noexcept
static IIRCoefficients makeHighPass(double sampleRate, double frequency) noexcept
void setCoefficients(const IIRCoefficients &newCoefficients) noexcept
void processSamples(float *samples, int numSamples) noexcept
void startTimerHz(int timerFrequencyHz) noexcept
bool isTimerRunning() const noexcept
void addListener(Listener *listener)
void removeListener(Listener *listener)
void updateParameterStreams(TimePosition)
Updates all the parameter streams to their positions at this time.
const EditItemID itemID
Every EditItem has an ID which is unique within the edit.
Envelope follower with adjustable attack/release parameters as well as several detection and time con...
EnvelopeFollower()=default
Creates a default EnvelopeFollower.
void setDetectMode(DetectionMode newDetectionMode)
Sets the detection mode to use.
void setAttackTime(float attackMs)
Sets the attack time.
DetectionMode
The available detection modes.
void setReleaseTime(float releaseMs)
Sets the release time.
TimeConstantMode
The available time constant modes modes.
void setSampleRate(float newSampleRate) noexcept
Sets the sample rate to use.
void setTimeConstantMode(TimeConstantMode newTC)
Sets the time constant to be used.
void reset() noexcept
Resets the detection and current envelope.
float processSingleSample(float input)
Returns the envelope for a new sample.
void setHoldTime(float holdMs)
Sets the hold time.
void initialise() override
Call this once after construction to connect it to the audio graph.
float getCurrentValue() override
Must return the current value of the modifier.
void applyToBuffer(const PluginRenderContext &) override
Sub classes should implement this to process the Modifier.
void deinitialise() override
Sub classes should implement this to deinitialise the Modifier.
AutomatableParameter::ModifierAssignment * createAssignment(const juce::ValueTree &) override
Must return a new ModifierAssignment for a given state.
juce::StringArray getAudioInputNames() override
Can return an array of names represeting audio inputs.
Calculates the RMS of a continuous signal.
void setSampleRate(float newSampleRate) noexcept
Sets the sample rate to use for detection.
RunningRMS()=default
Creates an empty RunningRMS.
float processSingleSample(float in) noexcept
Returns the current RMS for a new input sample.
virtual void changed()
This should be called to send a change notification to any SelectableListeners that are registered wi...
#define TRANS(stringLiteral)
Type jlimit(Type lowerLimit, Type upperLimit, Type valueToConstrain) noexcept
constexpr NumericType square(NumericType n) noexcept
bool getBoolParamValue(const AutomatableParameter &ap)
Returns a bool version of an AutomatableParameter.
Connects a modifier source to an AutomatableParameter.
juce::ValueTree state
Modifier internal state.
void setEditTime(TimePosition newEditTime)
Subclasses can call this to update the edit time of the current value.
double getSampleRate() const
Returns the sample rate the Modifier has been initialised with.
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.
TimeRange editTime
The edit time range this context represents.