fix: send All Notes Off (CC123) before each MIDI NoteOn to stop lingering release

This commit is contained in:
2026-07-27 11:21:51 +07:00
parent e866ad1c0d
commit e785b88ea7
+22 -20
View File
@@ -6752,26 +6752,28 @@ const App = () => {
const cmd = msg.data[0] >> 4; const cmd = msg.data[0] >> 4;
const pitch = msg.data[1]; const pitch = msg.data[1];
const velocity = msg.data[2]; const velocity = msg.data[2];
if (cmd === 0x9 && velocity > 0) { if (cmd === 0x9 && velocity > 0) {
lastMidiNoteRef.current = { pitch, velocity, startTime: performance.now(), length: 0 }; lastMidiNoteRef.current = { pitch, velocity, startTime: performance.now(), length: 0 };
setLastMidiNote({ pitch, velocity, length: 0, time: Date.now() }); setLastMidiNote({ pitch, velocity, length: 0, time: Date.now() });
activeMidiPitchesRef.current.add(pitch); activeMidiPitchesRef.current.add(pitch);
setActiveMidiPitches(new Set(activeMidiPitchesRef.current)); setActiveMidiPitches(new Set(activeMidiPitchesRef.current));
{ if (window.SonicSF) { // Stop previous notes on this channel before playing new note
const ch = msg.data[0] & 0x0F; { if (window.SonicSF) {
const arSub = subTabsRef && subTabsRef.current && activeTabRef && subTabsRef.current.find(s => s.id === activeTabRef.current && s.type === 'PIANO_ROLL' && s.isArmed); const ch = msg.data[0] & 0x0F;
if (arSub) { try { window.SonicSF.controllerChange(ch, 123, 0); } catch (e) {}
window.SonicSF.playNote(pitch, velocity, 60000, undefined, arSub.instrumentProgram, null, ch, arSub.synth_engine); const arSub = subTabsRef && subTabsRef.current && activeTabRef && subTabsRef.current.find(s => s.id === activeTabRef.current && s.type === 'PIANO_ROLL' && s.isArmed);
} else { if (arSub) {
const armedTrack = activeTracksRef.current ? activeTracksRef.current.find(t => t.isArmed) : null; window.SonicSF.playNote(pitch, velocity, 60000, undefined, arSub.instrumentProgram, null, ch, arSub.synth_engine);
if (armedTrack) { } else {
const prog = armedTrack.instrumentProgram; const armedTrack = activeTracksRef.current ? activeTracksRef.current.find(t => t.isArmed) : null;
const se = armedTrack.synth_engine; if (armedTrack) {
const dest = activeTrackNodesRef.current[armedTrack.id]?.gainNode || null; const prog = armedTrack.instrumentProgram;
window.SonicSF.playNote(pitch, velocity, 60000, undefined, prog, dest, ch, se); 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)) { } else if (cmd === 0x8 || (cmd === 0x9 && velocity === 0)) {
activeMidiPitchesRef.current.delete(pitch); activeMidiPitchesRef.current.delete(pitch);
setActiveMidiPitches(new Set(activeMidiPitchesRef.current)); setActiveMidiPitches(new Set(activeMidiPitchesRef.current));