fix: MIDI ARM không phát âm thanh sau khi load instrument - lazy-load soundfont trong playNote + giữ channel khi selectInstrument truyền channel tường minh

This commit is contained in:
2026-08-03 10:23:32 +07:00
parent 4d10b9485b
commit d8227904b6
3 changed files with 33 additions and 13 deletions
+27 -12
View File
@@ -258,16 +258,16 @@
if (!ok) return;
}
var engKey = (sfId || '') + ':' + bank + ':' + program;
if (!_engineChMap[engKey]) {
if (channel === undefined || channel === null) {
if (channel === undefined || channel === null) {
if (!_engineChMap[engKey]) {
var allocCh = this.allocateChannel(bank);
_engineChMap[engKey] = allocCh;
channel = allocCh;
} else {
_engineChMap[engKey] = channel;
channel = _engineChMap[engKey];
}
} else {
channel = _engineChMap[engKey];
} else if (!_engineChMap[engKey]) {
_engineChMap[engKey] = channel;
}
var sfHandle = _sfHandleMap.get(sfId);
if (sfHandle !== undefined) {
@@ -423,18 +423,33 @@
var finalBank = usedBank;
var finalProg = usedProg;
var finalSfId = synthEngine ? synthEngine.soundfont_id : undefined;
if (_channels[ch] && _channels[ch].program !== undefined) {
finalBank = _channels[ch].bank;
finalProg = _channels[ch].program;
if (_channels[ch].sfId !== undefined) {
finalSfId = _channels[ch].sfId;
}
var cachedCh = _channels[ch];
// A channel explicitly configured with a soundfont (via
// selectInstrument) is authoritative. But the default channel
// state (bank 0, program 0, no soundfont) must NOT mask the
// track's synth engine or the note's program — otherwise notes
// on a freshly-picked instrument are silently dropped.
if (cachedCh && cachedCh.sfId !== undefined) {
finalBank = cachedCh.bank;
finalProg = cachedCh.program;
finalSfId = cachedCh.sfId;
} else if (!synthEngine && program !== undefined && cachedCh && cachedCh.program !== undefined && cachedCh.program !== 0 && cachedCh.program !== null) {
finalBank = cachedCh.bank;
finalProg = cachedCh.program;
}
// Ensure the soundfont is actually loaded before the note plays.
// Quick instrument pick on a track does not pre-load it, so load
// lazily here and retry the note once the font is ready.
if (finalSfId && !_sfHandleMap.has(finalSfId)) {
self.loadSoundFont(finalSfId).then(function (ok) {
if (ok) doNote();
});
return;
}
// Program change at note time, not call time — ensures correct
// instrument for each item regardless of processing order.
// Skip if the channel already has this exact instrument (avoids
// per-note soundfont reloads that cause audible crackle/glitches).
var cachedCh = _channels[ch];
var progAlreadySet = cachedCh && cachedCh.program === finalProg && cachedCh.bank === finalBank && cachedCh.sfId === finalSfId;
if ((synthEngine || program !== undefined) && !progAlreadySet) {
var sfHandle = finalSfId ? _sfHandleMap.get(finalSfId) : undefined;