60 float decayTimeSeconds,
62 float releaseTimeSeconds)
63 : attack (attackTimeSeconds),
64 decay (decayTimeSeconds),
65 sustain (sustainLevel),
66 release (releaseTimeSeconds)
70 float attack = 0.1f, decay = 0.1f, sustain = 1.0f, release = 0.1f;
85 parameters = newParameters;
96 bool isActive() const noexcept {
return state != State::idle; }
106 sampleRate = newSampleRate;
120 if (attackRate > 0.0f)
122 state = State::attack;
124 else if (decayRate > 0.0f)
127 state = State::decay;
131 envelopeVal = parameters.sustain;
132 state = State::sustain;
139 if (state != State::idle)
141 if (parameters.release > 0.0f)
143 releaseRate = (
float) (envelopeVal / (parameters.release * sampleRate));
144 state = State::release;
169 envelopeVal += attackRate;
171 if (envelopeVal >= 1.0f)
182 envelopeVal -= decayRate;
184 if (envelopeVal <= parameters.sustain)
186 envelopeVal = parameters.sustain;
195 envelopeVal = parameters.sustain;
201 envelopeVal -= releaseRate;
203 if (envelopeVal <= 0.0f)
218 template <
typename FloatType>
223 if (state == State::idle)
225 buffer.
clear (startSample, numSamples);
229 if (state == State::sustain)
231 buffer.
applyGain (startSample, numSamples, parameters.sustain);
237 while (--numSamples >= 0)
239 auto env = getNextSample();
241 for (
int i = 0; i < numChannels; ++i)
250 void recalculateRates() noexcept
252 auto getRate = [] (
float distance,
float timeInSeconds,
double sr)
254 return timeInSeconds > 0.0f ? (
float) (distance / (timeInSeconds * sr)) : -1.0f;
257 attackRate = getRate (1.0f, parameters.attack, sampleRate);
258 decayRate = getRate (1.0f - parameters.sustain, parameters.decay, sampleRate);
259 releaseRate = getRate (parameters.sustain, parameters.release, sampleRate);
261 if ((state == State::attack && attackRate <= 0.0f)
262 || (state == State::decay && (decayRate <= 0.0f || envelopeVal <= parameters.sustain))
263 || (state == State::release && releaseRate <= 0.0f))
269 void goToNextState() noexcept
271 if (state == State::attack)
273 state = (decayRate > 0.0f ? State::decay : State::sustain);
277 if (state == State::decay)
279 state = State::sustain;
283 if (state == State::release)
288 enum class State { idle, attack, decay, sustain, release };
290 State state = State::idle;
291 Parameters parameters;
293 double sampleRate = 44100.0;
294 float envelopeVal = 0.0f, attackRate = 0.0f, decayRate = 0.0f, releaseRate = 0.0f;
A very simple ADSR envelope class.
void setSampleRate(double newSampleRate) noexcept
Sets the sample rate that will be used for the envelope.
void noteOff() noexcept
Starts the release phase of the envelope.
bool isActive() const noexcept
Returns true if the envelope is in its attack, decay, sustain or release stage.
void reset() noexcept
Resets the envelope to an idle state.
float getNextSample() noexcept
Returns the next sample value for an ADSR object.
void setParameters(const Parameters &newParameters)
Sets the parameters that will be used by an ADSR object.
void noteOn() noexcept
Starts the attack phase of the envelope.
const Parameters & getParameters() const noexcept
Returns the parameters currently being used by an ADSR object.
void applyEnvelopeToBuffer(AudioBuffer< FloatType > &buffer, int startSample, int numSamples)
This method will conveniently apply the next numSamples number of envelope values to an AudioBuffer.
A multi-channel buffer containing floating point audio samples.
Type * getWritePointer(int channelNumber) noexcept
Returns a writeable pointer to one of the buffer's channels.
int getNumChannels() const noexcept
Returns the number of channels of audio data that this buffer contains.
int getNumSamples() const noexcept
Returns the number of samples allocated in each of the buffer's channels.
void clear() noexcept
Clears all the samples in all channels and marks the buffer as cleared.
void applyGain(int channel, int startSample, int numSamples, Type gain) noexcept
Applies a gain multiple to a region of one channel.
Holds the parameters being used by an ADSR object.