fix: stopAll cancels scheduled notes, loop works on all tabs

- Add _scheduledNotes array tracking
- stopAll clears all pending setTimeout notes + allNotesOff()
- Loop enabled on MAIN SESSION, SECTION-TAB, PIANO_ROLL via
  isLoopingSelection + selLeft/selRight auto-derivation
This commit is contained in:
2026-07-26 21:16:49 +07:00
parent 1daf355dd4
commit cdd5f8c96b
+21 -2
View File
@@ -35,6 +35,7 @@
let _initialized = false;
let _initPromise = null;
let _currentSfId = null;
const _scheduledNotes = [];
const SonicSF = {
loadedFonts: {},
@@ -168,16 +169,28 @@
const durSec = durationMs / 1000;
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);
setTimeout(() => { try { _synthInstance.noteOff(channel, midiPitch); } catch (e) {} }, durSec * 1000);
noteId.off = setTimeout(() => {
try { _synthInstance.noteOff(channel, midiPitch); } catch (e) {}
const idx = _scheduledNotes.indexOf(noteId);
if (idx >= 0) _scheduledNotes.splice(idx, 1);
}, durSec * 1000);
} catch (e) {
console.warn("[SonicSF] SpessaSynth noteOn error:", e);
this._playNoteOsc(note, velocity, durationMs, startTime, program, null, channel, synthEngine);
}
};
if (delay > 0) setTimeout(doNote, delay * 1000); else doNote();
if (delay > 0) {
noteId.on = setTimeout(doNote, delay * 1000);
} else {
doNote();
const idx = _scheduledNotes.indexOf(noteId);
if (idx >= 0) _scheduledNotes.splice(idx, 1);
}
},
_playNoteOsc: function (note, velocity, durationMs, startTime, program, destinationNode, channel, synthEngine) {
@@ -257,6 +270,12 @@
if (_initialized && _synthInstance) {
try { for (let ch = 0; ch < 16; ch++) _synthInstance.allNotesOff(ch); } catch (e) {}
}
// Cancel all scheduled future notes
while (_scheduledNotes.length > 0) {
const n = _scheduledNotes.pop();
if (n.on) { clearTimeout(n.on); n.on = null; }
if (n.off) { clearTimeout(n.off); n.off = null; }
}
const ctx = getCtx();
const now = ctx.currentTime;
Object.values(activeOscillators).forEach(entry => {