Smooth envelope transitions (fixes #373)

This commit is contained in:
Jean Pierre Cimalando 2021-03-22 19:10:13 +01:00
parent 8c951d3a7f
commit d19c41bd90
3 changed files with 25 additions and 6 deletions

View file

@ -65,6 +65,7 @@ void ADSREnvelope::getBlock(absl::Span<Float> output) noexcept
Float currentValue = this->currentValue;
bool shouldRelease = this->shouldRelease;
int releaseDelay = this->releaseDelay;
Float transitionDelta = this->transitionDelta;
while (!output.empty()) {
size_t count = 0;
@ -106,8 +107,9 @@ void ADSREnvelope::getBlock(absl::Span<Float> output) noexcept
while (count < size && (currentValue *= decayRate) > sustain)
output[count++] = currentValue;
if (currentValue <= sustainThreshold) {
currentValue = sustain;
currentState = State::Sustain;
currentValue = std::max(sustain, currentValue);
transitionDelta = (sustain - currentValue) / (sampleRate * config::egTransitionTime);
}
break;
case State::Sustain:
@ -115,16 +117,25 @@ void ADSREnvelope::getBlock(absl::Span<Float> output) noexcept
shouldRelease = true;
break;
}
count = size;
currentValue = sustain;
sfz::fill(output.first(count), currentValue);
for (size_t i = 0; i < size; ++i) {
currentValue = std::max(sustain, currentValue + transitionDelta);
output[count++] = currentValue;
}
break;
case State::Release:
while (count < size && (currentValue *= releaseRate) > config::egReleaseThreshold)
output[count++] = currentValue;
if (currentValue <= config::egReleaseThreshold) {
currentValue = 0;
currentState = State::Fadeout;
transitionDelta = -currentValue / (sampleRate * config::egTransitionTime);
}
break;
case State::Fadeout:
while (count < size && (currentValue += transitionDelta) > 0)
output[count++] = currentValue;
if (currentValue <= 0) {
currentState = State::Done;
currentValue = 0;
}
break;
default:
@ -144,6 +155,7 @@ void ADSREnvelope::getBlock(absl::Span<Float> output) noexcept
this->currentValue = currentValue;
this->shouldRelease = shouldRelease;
this->releaseDelay = releaseDelay;
this->transitionDelta = transitionDelta;
ASSERT(!hasNanInf(output));
}

View file

@ -62,7 +62,7 @@ public:
* @return true
* @return false
*/
bool isReleased() const noexcept { return currentState == State::Release || shouldRelease; }
bool isReleased() const noexcept { return currentState >= State::Release || shouldRelease; }
/**
* @brief Get the remaining delay samples
*
@ -83,6 +83,7 @@ private:
Decay,
Sustain,
Release,
Fadeout,
Done
};
State currentState { State::Done };
@ -99,6 +100,7 @@ private:
int releaseDelay { 0 };
bool shouldRelease { false };
bool freeRunning { false };
Float transitionDelta {};
LEAK_DETECTOR(ADSREnvelope);
};

View file

@ -108,6 +108,11 @@ namespace config {
finished.
*/
constexpr float egReleaseThreshold = 1e-4;
/**
Duration of a linear transition user to smooth cases of otherwise
immediate level transitions. (eg. decay->sustain or release->off)
*/
constexpr float egTransitionTime = 50e-3;
/**
Default metadata for MIDIName documents
*/