FIX: (1) MIDI item route CHỈ qua Carla bridge khi VSTi loaded (bỏ FluidSynth GM sai âm) ở mọi đường playback + ghosts; (2) updateSfRouting sync route gains nhánh gainNode + ensureMasteringRouting force-sync mọi node — preview MIDI keyboard qua mastering không cần bật/tắt power; (3) stopNote/panic dừng fallback oscillator theo channel:pitch — hết âm kêu liên tục sau khi thả phím
This commit is contained in:
@@ -21,6 +21,10 @@
|
||||
let _pendingNoteTimers = [];
|
||||
let _loadedFonts = {};
|
||||
let _activeOscillators = {};
|
||||
// Fallback oscillator theo 'channel:pitch' — để stopNote/stopAll dừng được
|
||||
// note khi thả phím (trước đây stopNote không dừng oscillator → âm kêu
|
||||
// liên tục dù đã thả phím khi FluidSynth chưa sẵn sàng / font load fail).
|
||||
let _activeOscillatorsByKey = {};
|
||||
let _gainNode = null;
|
||||
let _pendingOutputDestination = null;
|
||||
let _outputDestination = null; // cache đích route — dedupe swap dư giữa stream
|
||||
@@ -479,6 +483,23 @@
|
||||
// Hủy note đang CHỜ LOAD soundfont (chưa noteon) — trước đây note
|
||||
// này vẫn bắn TRỄ sau khi thả phím → âm loop không dừng được.
|
||||
if (_pendingNoteOns[key]) delete _pendingNoteOns[key];
|
||||
// ⚠️ FIX: dừng fallback oscillator theo 'channel:pitch' — trước đây
|
||||
// stopNote chỉ noteoff FluidSynth, KHÔNG dừng oscillator (khi WASM
|
||||
// chưa sẵn sàng / font load fail → _playNoteFallback) → âm kêu liên
|
||||
// tục mặc dù đã thả phím (không xử lí noteoff).
|
||||
var _oscIds = _activeOscillatorsByKey[key];
|
||||
if (_oscIds && _oscIds.length) {
|
||||
var _nowT = getCtx().currentTime;
|
||||
_oscIds.slice().forEach(function (oid) {
|
||||
var entry = _activeOscillators[oid];
|
||||
if (entry) {
|
||||
try { entry.gain.gain.cancelScheduledValues(_nowT); entry.gain.gain.setValueAtTime(0, _nowT); } catch (e) {}
|
||||
try { entry.osc.stop(_nowT); } catch (e) {}
|
||||
delete _activeOscillators[oid];
|
||||
}
|
||||
});
|
||||
delete _activeOscillatorsByKey[key];
|
||||
}
|
||||
if (_initialized && _fluidModule) {
|
||||
var mappedChs = _activeNotes[key];
|
||||
if (mappedChs === undefined) mappedChs = [channel];
|
||||
@@ -711,6 +732,17 @@
|
||||
for (var c = 0; c < 16; c++) _fluidModule._fluid_synth_all_notes_off(_synthPtr, c);
|
||||
} catch (e) {}
|
||||
}
|
||||
// Dừng fallback oscillator (FluidSynth chưa sẵn sàng / font fail)
|
||||
try {
|
||||
var _pctx = getCtx();
|
||||
var _pnow = _pctx.currentTime;
|
||||
Object.values(_activeOscillators).forEach(function (entry) {
|
||||
try { if (entry.gain) { entry.gain.gain.cancelScheduledValues(_pnow); entry.gain.gain.setValueAtTime(0, _pnow); } } catch (e) {}
|
||||
try { if (entry.osc) entry.osc.stop(_pnow); } catch (e) {}
|
||||
});
|
||||
Object.keys(_activeOscillators).forEach(function (k) { delete _activeOscillators[k]; });
|
||||
_activeOscillatorsByKey = {};
|
||||
} catch (e) {}
|
||||
_activeNotes = {};
|
||||
},
|
||||
|
||||
@@ -768,7 +800,20 @@
|
||||
osc.stop(stopAt);
|
||||
var oscId = note + '_' + Date.now() + '_' + Math.random();
|
||||
_activeOscillators[oscId] = { osc: osc, gain: noteGain };
|
||||
setTimeout(function () { delete _activeOscillators[oscId]; }, (stopAt - ctx.currentTime) * 1000 + 100);
|
||||
// Đăng ký theo 'channel:pitch' để stopNote dừng được khi thả phím
|
||||
var oscKey = (channel !== undefined && channel >= 0 && channel < 16) ? (channel + ':' + note) : null;
|
||||
if (oscKey) {
|
||||
if (!_activeOscillatorsByKey[oscKey]) _activeOscillatorsByKey[oscKey] = [];
|
||||
_activeOscillatorsByKey[oscKey].push(oscId);
|
||||
}
|
||||
setTimeout(function () {
|
||||
delete _activeOscillators[oscId];
|
||||
if (oscKey && _activeOscillatorsByKey[oscKey]) {
|
||||
var _oi = _activeOscillatorsByKey[oscKey].indexOf(oscId);
|
||||
if (_oi >= 0) _activeOscillatorsByKey[oscKey].splice(_oi, 1);
|
||||
if (_activeOscillatorsByKey[oscKey].length === 0) delete _activeOscillatorsByKey[oscKey];
|
||||
}
|
||||
}, (stopAt - ctx.currentTime) * 1000 + 100);
|
||||
return osc;
|
||||
},
|
||||
|
||||
@@ -805,6 +850,7 @@
|
||||
} catch (e) {}
|
||||
});
|
||||
Object.keys(_activeOscillators).forEach(function (k) { delete _activeOscillators[k]; });
|
||||
_activeOscillatorsByKey = {};
|
||||
_activeNotes = {};
|
||||
},
|
||||
|
||||
|
||||
Reference in New Issue
Block a user