117 lines
3.0 KiB
C++
117 lines
3.0 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 = 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
|