From e785b88ea70405ee73c11be8a7b76776d5cc7fac Mon Sep 17 00:00:00 2001 From: 3dtours Date: Mon, 27 Jul 2026 11:21:51 +0700 Subject: [PATCH] fix: send All Notes Off (CC123) before each MIDI NoteOn to stop lingering release --- app/static/js/app.jsx | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/app/static/js/app.jsx b/app/static/js/app.jsx index d030321..677a667 100644 --- a/app/static/js/app.jsx +++ b/app/static/js/app.jsx @@ -6752,26 +6752,28 @@ const App = () => { const cmd = msg.data[0] >> 4; const pitch = msg.data[1]; const velocity = msg.data[2]; - if (cmd === 0x9 && velocity > 0) { - lastMidiNoteRef.current = { pitch, velocity, startTime: performance.now(), length: 0 }; - setLastMidiNote({ pitch, velocity, length: 0, time: Date.now() }); - activeMidiPitchesRef.current.add(pitch); - setActiveMidiPitches(new Set(activeMidiPitchesRef.current)); - { if (window.SonicSF) { - const ch = msg.data[0] & 0x0F; - 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 { - const armedTrack = activeTracksRef.current ? activeTracksRef.current.find(t => t.isArmed) : null; - if (armedTrack) { - const prog = armedTrack.instrumentProgram; - const se = armedTrack.synth_engine; - const dest = activeTrackNodesRef.current[armedTrack.id]?.gainNode || null; - window.SonicSF.playNote(pitch, velocity, 60000, undefined, prog, dest, ch, se); - } - } - } } + if (cmd === 0x9 && velocity > 0) { + lastMidiNoteRef.current = { pitch, velocity, startTime: performance.now(), length: 0 }; + 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); + if (arSub) { + window.SonicSF.playNote(pitch, velocity, 60000, undefined, arSub.instrumentProgram, null, ch, arSub.synth_engine); + } else { + const armedTrack = activeTracksRef.current ? activeTracksRef.current.find(t => t.isArmed) : null; + if (armedTrack) { + const prog = armedTrack.instrumentProgram; + const se = armedTrack.synth_engine; + const dest = activeTrackNodesRef.current[armedTrack.id]?.gainNode || null; + window.SonicSF.playNote(pitch, velocity, 60000, undefined, prog, dest, ch, se); + } + } + } } } else if (cmd === 0x8 || (cmd === 0x9 && velocity === 0)) { activeMidiPitchesRef.current.delete(pitch); setActiveMidiPitches(new Set(activeMidiPitchesRef.current));