chromaflock/Source/DSP/Envelope.h
2026-07-13 20:57:38 +02:00

87 lines
2.4 KiB
C++

#pragma once
#include <cmath>
#include <algorithm>
enum class ADSRStage { Idle = 0, Attack, Decay, Sustain, Release };
class ADSREnvelope {
public:
void prepare(double sr) {
sampleRate = sr;
stage = ADSRStage::Idle;
level = 0.0f;
}
void setAttack(float a) { attackTime = std::max(a, 0.001f); }
void setDecay(float d) { decayTime = std::max(d, 0.001f); }
void setSustain(float s) { sustainLevel = std::clamp(s, 0.0f, 1.0f); }
void setRelease(float r) { releaseTime = std::max(r, 0.001f); }
void noteOn() {
stage = ADSRStage::Attack;
level = 0.0f;
}
void noteOff() {
if (stage != ADSRStage::Idle)
stage = ADSRStage::Release;
}
bool isActive() const { return stage != ADSRStage::Idle; }
float getNextSample() {
switch (stage) {
case ADSRStage::Idle:
level = 0.0f;
break;
case ADSRStage::Attack: {
float attackInc = 1.0f / (attackTime * static_cast<float>(sampleRate));
level += attackInc;
if (level >= 1.0f) {
level = 1.0f;
stage = ADSRStage::Decay;
}
break;
}
case ADSRStage::Decay: {
float decayInc = (1.0f - sustainLevel) / (decayTime * static_cast<float>(sampleRate));
level -= decayInc;
if (level <= sustainLevel) {
level = sustainLevel;
stage = ADSRStage::Sustain;
}
break;
}
case ADSRStage::Sustain:
level = sustainLevel;
break;
case ADSRStage::Release: {
float releaseInc = level / (releaseTime * static_cast<float>(sampleRate));
level -= releaseInc;
if (level <= 0.0f) {
level = 0.0f;
stage = ADSRStage::Idle;
}
break;
}
}
return level;
}
float getCurrentLevel() const { return level; }
ADSRStage getCurrentStage() const { return stage; }
private:
double sampleRate = 44100.0;
float attackTime = 0.01f;
float decayTime = 0.3f;
float sustainLevel = 0.7f;
float releaseTime = 0.5f;
float level = 0.0f;
ADSRStage stage = ADSRStage::Idle;
};