From 8aeac14e4be06094385d3178ed117832c297ff83 Mon Sep 17 00:00:00 2001 From: 3dtours Date: Mon, 27 Jul 2026 11:30:35 +0700 Subject: [PATCH] fix: only send All Notes Off (CC123) when sustain pedal is not active - Track sustain state per channel via _sustainStates[] - sustainActive(channel) returns boolean - MIDI NoteOn: only send CC123 if !sustainActive(ch) - Preserves sustained notes when playing new notes --- app/static/js/app.jsx | 13 ++++++++----- app/static/js/services/soundfontPlayer.js | 9 +++++++++ 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/app/static/js/app.jsx b/app/static/js/app.jsx index 677a667..e0188e6 100644 --- a/app/static/js/app.jsx +++ b/app/static/js/app.jsx @@ -6757,11 +6757,14 @@ const App = () => { setLastMidiNote({ pitch, velocity, length: 0, time: Date.now() }); activeMidiPitchesRef.current.add(pitch); setActiveMidiPitches(new Set(activeMidiPitchesRef.current)); - // Stop previous notes on this channel before playing new note - { if (window.SonicSF) { - const ch = msg.data[0] & 0x0F; - try { window.SonicSF.controllerChange(ch, 123, 0); } catch (e) {} - const arSub = subTabsRef && subTabsRef.current && activeTabRef && subTabsRef.current.find(s => s.id === activeTabRef.current && s.type === 'PIANO_ROLL' && s.isArmed); + // Stop previous notes on this channel before playing new note + // Only send All Notes Off when sustain pedal is not active + { if (window.SonicSF) { + const ch = msg.data[0] & 0x0F; + if (!window.SonicSF.sustainActive || !window.SonicSF.sustainActive(ch)) { + try { window.SonicSF.controllerChange(ch, 123, 0); } catch (e) {} + } + const arSub = subTabsRef && subTabsRef.current && activeTabRef && subTabsRef.current.find(s => s.id === activeTabRef.current && s.type === 'PIANO_ROLL' && s.isArmed); if (arSub) { window.SonicSF.playNote(pitch, velocity, 60000, undefined, arSub.instrumentProgram, null, ch, arSub.synth_engine); } else { diff --git a/app/static/js/services/soundfontPlayer.js b/app/static/js/services/soundfontPlayer.js index c1a7759..914ea19 100644 --- a/app/static/js/services/soundfontPlayer.js +++ b/app/static/js/services/soundfontPlayer.js @@ -36,6 +36,7 @@ let _initPromise = null; let _currentSfId = null; const _scheduledNotes = []; + const _sustainStates = new Array(16).fill(false); const SonicSF = { loadedFonts: {}, @@ -122,6 +123,9 @@ _channels[channel].bank = value; _channels[channel].isPercussion = (value === 128); } + if (controller === 64) { + _sustainStates[channel] = value >= 64; + } }, programChange: function (channel, program) { @@ -154,6 +158,11 @@ return { ..._channels[channel] }; }, + sustainActive: function (channel) { + if (channel < 0 || channel > 15) return false; + return _sustainStates[channel]; + }, + pitchBend: function (channel, value) { if (channel < 0 || channel > 15) return; if (_initialized && _synthInstance) {