#pragma once #include namespace serum { // =========================================================================== // ADSR envelope with curve tension. Durations are in seconds; the sustain // level is 0..1. Retriggering (noteOn while active) starts from the current // value for click-free legato behaviour. // =========================================================================== class Envelope { public: void prepare (double sampleRate) { sr = sampleRate; reset(); } void reset(); void noteOn(); void noteOff(); void setParams (float attackSec, float decaySec, float sustain, float releaseSec, float curve); float process() noexcept; // advance one sample and return the value float getValue() const noexcept { return value; } bool isActive() const noexcept { return stage != Stage::Idle; } // Snapshot for GUI rendering. struct Shape { float attack = 0, decay = 0, sustain = 0, release = 0, curve = 0.5f; }; Shape getShape() const noexcept { return shape; } private: enum class Stage { Idle, Attack, Decay, Sustain, Release }; Stage stage = Stage::Idle; double sr = 44100.0; float value = 0.0f; float startValue = 0.0f, endValue = 0.0f; double elapsed = 0.0, duration = 0.0; double attackShape = 1.0, decayShape = 1.0; float sustain = 0.7f; double attackSamples = 0.0, decaySamples = 0.0, releaseSamples = 0.0; Shape shape; }; } // namespace serum