Smooth envelope transitions (fixes #373)
This commit is contained in:
parent
8c951d3a7f
commit
d19c41bd90
3 changed files with 25 additions and 6 deletions
|
|
@ -65,6 +65,7 @@ void ADSREnvelope::getBlock(absl::Span<Float> output) noexcept
|
||||||
Float currentValue = this->currentValue;
|
Float currentValue = this->currentValue;
|
||||||
bool shouldRelease = this->shouldRelease;
|
bool shouldRelease = this->shouldRelease;
|
||||||
int releaseDelay = this->releaseDelay;
|
int releaseDelay = this->releaseDelay;
|
||||||
|
Float transitionDelta = this->transitionDelta;
|
||||||
|
|
||||||
while (!output.empty()) {
|
while (!output.empty()) {
|
||||||
size_t count = 0;
|
size_t count = 0;
|
||||||
|
|
@ -106,8 +107,9 @@ void ADSREnvelope::getBlock(absl::Span<Float> output) noexcept
|
||||||
while (count < size && (currentValue *= decayRate) > sustain)
|
while (count < size && (currentValue *= decayRate) > sustain)
|
||||||
output[count++] = currentValue;
|
output[count++] = currentValue;
|
||||||
if (currentValue <= sustainThreshold) {
|
if (currentValue <= sustainThreshold) {
|
||||||
currentValue = sustain;
|
|
||||||
currentState = State::Sustain;
|
currentState = State::Sustain;
|
||||||
|
currentValue = std::max(sustain, currentValue);
|
||||||
|
transitionDelta = (sustain - currentValue) / (sampleRate * config::egTransitionTime);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case State::Sustain:
|
case State::Sustain:
|
||||||
|
|
@ -115,16 +117,25 @@ void ADSREnvelope::getBlock(absl::Span<Float> output) noexcept
|
||||||
shouldRelease = true;
|
shouldRelease = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
count = size;
|
for (size_t i = 0; i < size; ++i) {
|
||||||
currentValue = sustain;
|
currentValue = std::max(sustain, currentValue + transitionDelta);
|
||||||
sfz::fill(output.first(count), currentValue);
|
output[count++] = currentValue;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case State::Release:
|
case State::Release:
|
||||||
while (count < size && (currentValue *= releaseRate) > config::egReleaseThreshold)
|
while (count < size && (currentValue *= releaseRate) > config::egReleaseThreshold)
|
||||||
output[count++] = currentValue;
|
output[count++] = currentValue;
|
||||||
if (currentValue <= config::egReleaseThreshold) {
|
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;
|
currentState = State::Done;
|
||||||
|
currentValue = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
@ -144,6 +155,7 @@ void ADSREnvelope::getBlock(absl::Span<Float> output) noexcept
|
||||||
this->currentValue = currentValue;
|
this->currentValue = currentValue;
|
||||||
this->shouldRelease = shouldRelease;
|
this->shouldRelease = shouldRelease;
|
||||||
this->releaseDelay = releaseDelay;
|
this->releaseDelay = releaseDelay;
|
||||||
|
this->transitionDelta = transitionDelta;
|
||||||
|
|
||||||
ASSERT(!hasNanInf(output));
|
ASSERT(!hasNanInf(output));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ public:
|
||||||
* @return true
|
* @return true
|
||||||
* @return false
|
* @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
|
* @brief Get the remaining delay samples
|
||||||
*
|
*
|
||||||
|
|
@ -83,6 +83,7 @@ private:
|
||||||
Decay,
|
Decay,
|
||||||
Sustain,
|
Sustain,
|
||||||
Release,
|
Release,
|
||||||
|
Fadeout,
|
||||||
Done
|
Done
|
||||||
};
|
};
|
||||||
State currentState { State::Done };
|
State currentState { State::Done };
|
||||||
|
|
@ -99,6 +100,7 @@ private:
|
||||||
int releaseDelay { 0 };
|
int releaseDelay { 0 };
|
||||||
bool shouldRelease { false };
|
bool shouldRelease { false };
|
||||||
bool freeRunning { false };
|
bool freeRunning { false };
|
||||||
|
Float transitionDelta {};
|
||||||
LEAK_DETECTOR(ADSREnvelope);
|
LEAK_DETECTOR(ADSREnvelope);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -108,6 +108,11 @@ namespace config {
|
||||||
finished.
|
finished.
|
||||||
*/
|
*/
|
||||||
constexpr float egReleaseThreshold = 1e-4;
|
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
|
Default metadata for MIDIName documents
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue