diff --git a/app/static/js/services/soundfontPlayer.js b/app/static/js/services/soundfontPlayer.js index 11c7799..0ee05eb 100644 --- a/app/static/js/services/soundfontPlayer.js +++ b/app/static/js/services/soundfontPlayer.js @@ -194,15 +194,16 @@ const now = ctx.currentTime; const delay = (typeof startTime === 'number' && startTime > now) ? (startTime - now) : 0; const noteId = { on: null, off: null }; - _scheduledNotes.push(noteId); const doNote = () => { try { _synthInstance.noteOn(channel, midiPitch, midiVel); - noteId.off = setTimeout(() => { - try { _synthInstance.noteOff(channel, midiPitch); } catch (e) {} - const idx = _scheduledNotes.indexOf(noteId); - if (idx >= 0) _scheduledNotes.splice(idx, 1); - }, durSec * 1000); + // Scheduled notes (timeline playback): auto noteOff after duration + // Immediate notes (MIDI keyboard): keep sounding until stopNote/stopAll + if (delay > 0) { + noteId.off = setTimeout(() => { + try { _synthInstance.noteOff(channel, midiPitch); } catch (e) {} + }, durSec * 1000); + } } catch (e) { console.warn("[SonicSF] SpessaSynth noteOn error:", e); this._playNoteOsc(note, velocity, durationMs, startTime, program, null, channel, synthEngine); @@ -210,10 +211,9 @@ }; if (delay > 0) { noteId.on = setTimeout(doNote, delay * 1000); + _scheduledNotes.push(noteId); } else { doNote(); - const idx = _scheduledNotes.indexOf(noteId); - if (idx >= 0) _scheduledNotes.splice(idx, 1); } },