Loading...
Searching...
No Matches
juce_ADSR.h
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
The code included in this file is provided under the terms of the ISC license
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
To use, copy, modify, and/or distribute this software for any purpose with or
without fee is hereby granted provided that the above copyright notice and
this permission notice appear in all copies.
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
class JUCE_API ADSR
{
public:
//==============================================================================
ADSR()
{
recalculateRates();
}
//==============================================================================
struct JUCE_API Parameters
{
Parameters() = default;
Parameters (float attackTimeSeconds,
float decayTimeSeconds,
float sustainLevel,
float releaseTimeSeconds)
: attack (attackTimeSeconds),
decay (decayTimeSeconds),
sustain (sustainLevel),
release (releaseTimeSeconds)
{
}
float attack = 0.1f, decay = 0.1f, sustain = 1.0f, release = 0.1f;
};
void setParameters (const Parameters& newParameters)
{
// need to call setSampleRate() first!
jassert (sampleRate > 0.0);
parameters = newParameters;
recalculateRates();
}
const Parameters& getParameters() const noexcept { return parameters; }
bool isActive() const noexcept { return state != State::idle; }
//==============================================================================
void setSampleRate (double newSampleRate) noexcept
{
jassert (newSampleRate > 0.0);
sampleRate = newSampleRate;
}
//==============================================================================
void reset() noexcept
{
envelopeVal = 0.0f;
state = State::idle;
}
void noteOn() noexcept
{
if (attackRate > 0.0f)
{
state = State::attack;
}
else if (decayRate > 0.0f)
{
envelopeVal = 1.0f;
state = State::decay;
}
else
{
envelopeVal = parameters.sustain;
state = State::sustain;
}
}
void noteOff() noexcept
{
if (state != State::idle)
{
if (parameters.release > 0.0f)
{
releaseRate = (float) (envelopeVal / (parameters.release * sampleRate));
state = State::release;
}
else
{
reset();
}
}
}
//==============================================================================
float getNextSample() noexcept
{
switch (state)
{
case State::idle:
{
return 0.0f;
}
case State::attack:
{
envelopeVal += attackRate;
if (envelopeVal >= 1.0f)
{
envelopeVal = 1.0f;
goToNextState();
}
break;
}
case State::decay:
{
envelopeVal -= decayRate;
if (envelopeVal <= parameters.sustain)
{
envelopeVal = parameters.sustain;
goToNextState();
}
break;
}
case State::sustain:
{
envelopeVal = parameters.sustain;
break;
}
case State::release:
{
envelopeVal -= releaseRate;
if (envelopeVal <= 0.0f)
goToNextState();
break;
}
}
return envelopeVal;
}
template <typename FloatType>
void applyEnvelopeToBuffer (AudioBuffer<FloatType>& buffer, int startSample, int numSamples)
{
jassert (startSample + numSamples <= buffer.getNumSamples());
if (state == State::idle)
{
buffer.clear (startSample, numSamples);
return;
}
if (state == State::sustain)
{
buffer.applyGain (startSample, numSamples, parameters.sustain);
return;
}
auto numChannels = buffer.getNumChannels();
while (--numSamples >= 0)
{
auto env = getNextSample();
for (int i = 0; i < numChannels; ++i)
buffer.getWritePointer (i)[startSample] *= env;
++startSample;
}
}
private:
//==============================================================================
void recalculateRates() noexcept
{
auto getRate = [] (float distance, float timeInSeconds, double sr)
{
return timeInSeconds > 0.0f ? (float) (distance / (timeInSeconds * sr)) : -1.0f;
};
attackRate = getRate (1.0f, parameters.attack, sampleRate);
decayRate = getRate (1.0f - parameters.sustain, parameters.decay, sampleRate);
releaseRate = getRate (parameters.sustain, parameters.release, sampleRate);
if ((state == State::attack && attackRate <= 0.0f)
|| (state == State::decay && (decayRate <= 0.0f || envelopeVal <= parameters.sustain))
|| (state == State::release && releaseRate <= 0.0f))
{
goToNextState();
}
}
void goToNextState() noexcept
{
if (state == State::attack)
{
state = (decayRate > 0.0f ? State::decay : State::sustain);
return;
}
if (state == State::decay)
{
state = State::sustain;
return;
}
if (state == State::release)
reset();
}
//==============================================================================
enum class State { idle, attack, decay, sustain, release };
State state = State::idle;
Parameters parameters;
double sampleRate = 44100.0;
float envelopeVal = 0.0f, attackRate = 0.0f, decayRate = 0.0f, releaseRate = 0.0f;
};
} // namespace juce
juce::ADSR::setSampleRate
void setSampleRate(double newSampleRate) noexcept
Definition juce_ADSR.h:103
juce::ADSR::noteOff
void noteOff() noexcept
Definition juce_ADSR.h:137
juce::ADSR::isActive
bool isActive() const noexcept
Definition juce_ADSR.h:96
juce::ADSR::reset
void reset() noexcept
Definition juce_ADSR.h:111
juce::ADSR::getNextSample
float getNextSample() noexcept
Definition juce_ADSR.h:158
juce::ADSR::setParameters
void setParameters(const Parameters &newParameters)
Definition juce_ADSR.h:80
juce::ADSR::noteOn
void noteOn() noexcept
Definition juce_ADSR.h:118
juce::ADSR::getParameters
const Parameters & getParameters() const noexcept
Definition juce_ADSR.h:93
juce::ADSR::applyEnvelopeToBuffer
void applyEnvelopeToBuffer(AudioBuffer< FloatType > &buffer, int startSample, int numSamples)
Definition juce_ADSR.h:219
juce::AudioBuffer
Definition juce_AudioSampleBuffer.h:34
juce::AudioBuffer::getWritePointer
Type * getWritePointer(int channelNumber) noexcept
Definition juce_AudioSampleBuffer.h:291
juce::AudioBuffer::getNumChannels
int getNumChannels() const noexcept
Definition juce_AudioSampleBuffer.h:236
juce::AudioBuffer::getNumSamples
int getNumSamples() const noexcept
Definition juce_AudioSampleBuffer.h:242
juce::AudioBuffer::clear
void clear() noexcept
Definition juce_AudioSampleBuffer.h:556
juce::AudioBuffer::applyGain
void applyGain(int channel, int startSample, int numSamples, Type gain) noexcept
Definition juce_AudioSampleBuffer.h:684
juce::ADSR::Parameters
Definition juce_ADSR.h:56