From d95c8de558dbe9b64f3bc132b73413c5960d1932 Mon Sep 17 00:00:00 2001 From: "prompt.ac/@jeffrey" Date: Wed, 10 Jun 2026 08:28:28 -0700 Subject: [PATCH] notepat native: fix shift-linger cutting off on key release MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The linger path called voice.update({volume:0}) before kill(voice,tail) — update sets volume instantly (no ramp), muting the voice before the fade could run, so releasing a key during shift-linger stopped the sound at once instead of ringing out. Drop the instant-mute; kill(voice,tail) alone ramps the engine's fade 1→0 over the tail (~4s sustained / 1.2s staccato) for the long decay. --- fedac/native/pieces/notepat.mjs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/fedac/native/pieces/notepat.mjs b/fedac/native/pieces/notepat.mjs index e424c77bf5..097cb4d172 100644 --- a/fedac/native/pieces/notepat.mjs +++ b/fedac/native/pieces/notepat.mjs @@ -2209,14 +2209,12 @@ function stopSoundKey(key, sound, system, fade) { : (entry.compositeVoices || [entry.synth || entry]); for (const voice of list) { if (!voice) continue; - // Prefer a smooth volume ramp when the voice exposes update(); fall - // back to a scheduled kill with a long fade. - if (typeof voice.update === "function") { - voice.update?.({ volume: 0 }); - sound?.kill?.(voice, tail); - } else { - sound?.kill?.(voice, tail); - } + // kill(voice, tail) ramps the engine voice's fade 1→0 over `tail` + // seconds (output is scaled by volume*fade), giving the linger + // ring-out. Do NOT call update({volume:0}) first — update sets the + // volume INSTANTLY (no ramp), muting the voice before the fade can + // run, which is what made shift-linger cut off on key-release. + sound?.kill?.(voice, tail); } lingerVoices.push({ until: frame + Math.ceil(tail * 60) + 30 }); if (entry.midiNote !== undefined) { -- 2.51.2