diff --git a/app/static/js/services/soundfontPlayer.js b/app/static/js/services/soundfontPlayer.js index 3b16690..57d6763 100644 --- a/app/static/js/services/soundfontPlayer.js +++ b/app/static/js/services/soundfontPlayer.js @@ -175,12 +175,12 @@ if (_initialized && _synthInstance) { // Ensure sustain is OFF before noteOff (SpessaSynth uses >=8192 threshold) try { _synthInstance.controllerChange(channel, 64, 0); } catch (e) {} - // Standard noteOff with multiple velocity variants + // Standard MIDI noteOff for the specific pitch — enters SoundFont release envelope try { _synthInstance.noteOff(channel, pitch); } catch (e) {} - try { _synthInstance.noteOff(channel, pitch, 0); } catch (e) {} - // Backup: All Notes Off + reset controllers - try { _synthInstance.controllerChange(channel, 123, 0); } catch (e) {} - try { _synthInstance.controllerChange(channel, 121, 0); } catch (e) {} + // Force immediate voice kill: CC 120 (All Sound Off) sets isActive=false instantly, + // bypassing the release envelope. CC 123 (All Notes Off) merely enters the release + // phase which respects long release tails (2-5s for sustained instruments). + try { _synthInstance.controllerChange(channel, 120, 0); } catch (e) {} } }, @@ -321,7 +321,7 @@ stopAll: function () { if (_initialized && _synthInstance) { - try { for (let ch = 0; ch < 16; ch++) _synthInstance.allNotesOff(ch); } catch (e) {} + try { for (let ch = 0; ch < 16; ch++) _synthInstance.controllerChange(ch, 120, 0); } catch (e) {} } // Cancel all scheduled future notes while (_scheduledNotes.length > 0) {