From d4e738c9f1f4d81ef5fce27ef6d30ff6f23ebf47 Mon Sep 17 00:00:00 2001 From: Armin Date: Thu, 13 Aug 2026 13:37:39 +0200 Subject: [PATCH] Fix filter env: modulate relative to sustain so cutoff knob stays audible at any env amount --- Source/DSP/Voice.h | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Source/DSP/Voice.h b/Source/DSP/Voice.h index 78a8b9d..8b0db89 100644 --- a/Source/DSP/Voice.h +++ b/Source/DSP/Voice.h @@ -128,8 +128,14 @@ public: left *= noteVelocity * envSample; right *= noteVelocity * envSample; - // Filter cutoff with env + keytrack - float modCutoff = filterCutoff * std::pow(2.0f, fEnvSample * filterEnvAmount * 4.0f); + // Filter cutoff with env + keytrack. + // Modulate RELATIVE to the envelope's sustain level so the held + // (sustain) cutoff always equals the base cutoff knob regardless of + // env amount — the envelope only opens above (attack) and closes + // below (release) that centre. This keeps the cutoff knob audible + // at any env amount instead of collapsing when env amt is lowered. + float modCutoff = filterCutoff * std::pow(2.0f, + (fEnvSample - filterEnvSustain) * filterEnvAmount * 4.0f); float keyTrackFactor = std::pow(2.0f, (static_cast(currentMidiNote) - 60.0f) / 12.0f * keyTrack); modCutoff *= keyTrackFactor; @@ -191,6 +197,7 @@ public: filterResonance = res; filterType = ft; filterEnvAmount = fEnvAmt; + filterEnvSustain = fSus; keyTrack = kTrack; pan = p; drive = std::max(drv, 1.001f); @@ -245,6 +252,7 @@ private: float filterResonance = 0.7f; FilterType filterType = FilterType::LowPass12; float filterEnvAmount = 0.0f; + float filterEnvSustain = 0.5f; float keyTrack = 0.5f; float pan = 0.0f; float drive = 1.5f;