Files
serumalt/Source/Envelope.cpp
T
biggy e4cea300db chore: land janitor round 1 and graft integration
Round 1 findings and fixes, all previously uncommitted:
- FXProcessor per-slot DSP history repair (HEAD does not compile without it)
- SynthVoice::getModulationValue, editor control-lock guard
- ExactCompare.h naming the deliberate exact float comparisons
- KnobLookAndFeel replacing the never-installed SerumLookAndFeel
- 55 first-party compiler warnings to 0
- AGENT.md renamed to AGENTS.md across Source/
- graft repository context graph and its hooks
- JANITOR_TASKS.md and UI_UX_AUDIT.md records
2026-10-06 08:50:45 +02:00

117 lines
2.9 KiB
C++

#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 = (double) attackShapeFor (curve);
decayShape = (double) decayShapeFor (curve);
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