#include "Envelope.h" namespace serum { void Envelope::reset() { stage = Stage::Idle; value = 0.0f; startValue = endValue = 0.0f; elapsed = duration = 0.0; } void Envelope::noteOn() { stage = Stage::Attack; elapsed = 0.0; duration = attackSamples; startValue = value; // retrigger from current level endValue = 1.0f; } void Envelope::noteOff() { if (stage == Stage::Idle) return; stage = Stage::Release; elapsed = 0.0; duration = releaseSamples; startValue = value; } void Envelope::setParams (float attackSec, float decaySec, float sustainLevel, float releaseSec, float curve) { sustain = juce::jlimit (0.0f, 1.0f, sustainLevel); curve = juce::jlimit (0.0f, 1.0f, curve); attackSamples = std::max (1.0, (double) attackSec * sr); decaySamples = std::max (1.0, (double) decaySec * sr); releaseSamples = std::max (1.0, (double) releaseSec * sr); // curve 0 -> fast attack / long release curve; curve 1 -> slow attack / fast decay attackShape = 0.3 + curve * 2.7; // 0.3 .. 3.0 decayShape = 3.0 - curve * 2.7; // 3.0 .. 0.3 shape.attack = attackSec; shape.decay = decaySec; shape.sustain = sustain; shape.release = releaseSec; shape.curve = curve; } float Envelope::process() noexcept { switch (stage) { case Stage::Idle: value = 0.0f; return 0.0f; case Stage::Attack: elapsed += 1.0; if (duration <= 1.0 || elapsed >= duration) { value = endValue; stage = Stage::Decay; elapsed = 0.0; duration = decaySamples; startValue = value; endValue = sustain; } else { const double p = elapsed / duration; value = startValue + (endValue - startValue) * (float) std::pow (p, attackShape); } return value; case Stage::Decay: elapsed += 1.0; if (duration <= 1.0 || elapsed >= duration) { value = sustain; stage = Stage::Sustain; } else { const double p = elapsed / duration; value = endValue + (startValue - endValue) * (float) std::pow (1.0 - p, decayShape); } return value; case Stage::Sustain: value = sustain; return value; case Stage::Release: elapsed += 1.0; if (duration <= 1.0 || elapsed >= duration) { value = 0.0f; stage = Stage::Idle; } else { const double p = elapsed / duration; value = startValue * (float) std::pow (1.0 - p, decayShape); } return value; } return 0.0f; } } // namespace serum