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:
2026-08-10 09:07:42 +00:00
parent 75795653c5
commit f492104869
5 changed files with 229 additions and 90 deletions
+135 -69
View File
@@ -20805,6 +20805,16 @@ const App = () => {
}
if (_prNode.gainNode) {
window.SonicSF.setOutputDestination(_prNode.gainNode);
// FIX: sync route gains NGAY ti thi đim routing trưc đây
// b qua node gi bypass cũ (to khi mastering OFF / audioBypass
// true) preview âm soundfont KHÔNG qua mastering cho ti khi bt/
// tt power (effect re-sync). MIDI preview route theo (midiBypass).
if (_prNode.route && _prNode.route.routeGain && _prNode.route.dryGain) {
const _prTrk2 = list.find(t => t.id === _activeSub.trackId);
const _b2 = effMidiBypass(_prTrk2 || { id: _activeSub.trackId });
_prNode.route.routeGain.gain.value = _b2 ? 0 : 1;
_prNode.route.dryGain.gain.value = _b2 ? 1 : 0;
}
return;
}
}
@@ -20845,6 +20855,13 @@ const App = () => {
if (node && node.gainNode && window.SonicSF && window.SonicSF.setOutputDestination) {
console.log('[SFRoute] dest=gainNode node', t.id, '(no sfEntry) — route.routeGain=' + (node.route ? node.route.routeGain.gain.value : 'MISSING'), 'route.dryGain=' + (node.route ? node.route.dryGain.gain.value : 'MISSING'));
window.SonicSF.setOutputDestination(node.gainNode);
// FIX: sync route gains node gi bypass cũ preview không qua
// mastering cho ti khi bt/tt power. MIDI preview theo .
if (node.route && node.route.routeGain && node.route.dryGain) {
const _b3 = effMidiBypass(t);
node.route.routeGain.gain.value = _b3 ? 0 : 1;
node.route.dryGain.gain.value = _b3 ? 1 : 0;
}
return;
}
}
@@ -20875,6 +20892,27 @@ const App = () => {
toggleMasteringOnMaster(!!_s.masterConnected, !!_s.isBypassed);
applyMasteringSettings(_s);
updateSfRouting();
// Force-sync MI node đang tn ti (route + sf route) theo trng thái
// hin ti phòng node to t trưc vi bypass cũ (mastering OFF lúc
// to node / audioBypass default true ca section) preview LUÔN qua
// mastering khi chain bt, không cn bt/tt power.
try {
const _list2 = (activeTracksRef.current && activeTracksRef.current.length) ? activeTracksRef.current : tracks;
_list2.forEach(_t => {
const _n = activeTrackNodesRef.current[_t.id];
if (!_n) return;
if (_n.sfRouteGain && _n.sfDryGain) {
const _mb = effMidiBypass(_t);
_n.sfRouteGain.gain.value = _mb ? 0 : 1;
_n.sfDryGain.gain.value = _mb ? 1 : 0;
}
if (_n.route && _n.route.routeGain && _n.route.dryGain) {
const _ab = routeBypassFor(_t);
_n.route.routeGain.gain.value = _ab ? 0 : 1;
_n.route.dryGain.gain.value = _ab ? 1 : 0;
}
});
} catch (e2) {}
} catch (e) {
console.warn('ensureMasteringRouting error:', e);
}
@@ -21115,22 +21153,28 @@ const App = () => {
if (offsetTime < noteEndSec) {
const durationMs = noteDurSec * 1000;
const program = track._isSectionClone ? track.instrumentProgram : (track.instrumentProgram !== undefined ? track.instrumentProgram : 0);
// Track VSTi + Carla local MIDI item PHI play qua Carla bridge
// (ch route Carla KHÔNG play qua FluidSynth GM na, tránh âm
// sai instrument chng lên). Không có Carla FluidSynth như cũ.
const routeToCarla = !!(window.SonicCarlaMidi && window.SonicCarlaMidi.shouldRoutePlayback(track.synth_engine));
if (offsetTime < noteStartSec) {
const delay = noteStartSec - offsetTime;
const startTime = context.currentTime + delay;
window.SonicSF.playNote(
note.pitch || 60,
note.velocity || 0.8,
durationMs,
startTime,
program,
gainNode,
trkCh,
track.synth_engine
);
if (!routeToCarla && window.SonicSF) {
window.SonicSF.playNote(
note.pitch || 60,
note.velocity || 0.8,
durationMs,
startTime,
program,
gainNode,
trkCh,
track.synth_engine
);
}
// MIDI items Carla bridge (track VSTi + Carla local): phát VSTi
// realtime yêu cu: MIDI item PHI play qua Carla khi VSTi loaded.
scheduleCarlaNote(track.synth_engine, trkCh, note.pitch || 60, note.velocity || 0.8, startTime, durationMs);
if (routeToCarla) scheduleCarlaNote(track.synth_engine, trkCh, note.pitch || 60, note.velocity || 0.8, startTime, durationMs);
// Trigger VU meter flash when the note starts playing
setTimeout(() => {
// Guard: stop setTimeout sót không đưc fire (VU nhy
@@ -21144,18 +21188,20 @@ const App = () => {
} else {
const playOffset = offsetTime - noteStartSec;
const remainingDurMs = (noteEndSec - offsetTime) * 1000;
window.SonicSF.playNote(
note.pitch || 60,
note.velocity || 0.8,
remainingDurMs,
context.currentTime,
program,
gainNode,
trkCh,
track.synth_engine
);
if (!routeToCarla && window.SonicSF) {
window.SonicSF.playNote(
note.pitch || 60,
note.velocity || 0.8,
remainingDurMs,
context.currentTime,
program,
gainNode,
trkCh,
track.synth_engine
);
}
// MIDI items Carla bridge (track VSTi + Carla local)
scheduleCarlaNote(track.synth_engine, trkCh, note.pitch || 60, note.velocity || 0.8, context.currentTime, remainingDurMs);
if (routeToCarla) scheduleCarlaNote(track.synth_engine, trkCh, note.pitch || 60, note.velocity || 0.8, context.currentTime, remainingDurMs);
// Trigger VU meter flash instantly
if (window.triggerMidiVuActivity) {
window.triggerMidiVuActivity((activeTab && activeTab.startsWith('session_') ? '_sess_' : '') + track.id, note.velocity || 0.8);
@@ -21255,21 +21301,27 @@ const App = () => {
const notePlayEndMain = Math.min(noteEndMain, secEnd);
const program = subTrack.instrumentProgram;
var subCh = assignTrackMidiChannel(subTrack, secTracks);
// MIDI item trong SECTION Carla bridge khi VSTi loaded
// (ch route Carla không play FluidSynth GM sai âm)
const subRouteCarla = !!(window.SonicCarlaMidi && window.SonicCarlaMidi.shouldRoutePlayback(subTrack.synth_engine));
if (offsetTime < noteStartMain) {
const delay = noteStartMain - offsetTime;
const startTime = context.currentTime + delay;
const playDurMs = (notePlayEndMain - noteStartMain) * 1000;
window.SonicSF.playNote(
note.pitch || 60,
note.velocity || 0.8,
playDurMs,
startTime,
program,
subNode,
subCh,
subTrack.synth_engine
);
if (!subRouteCarla && window.SonicSF) {
window.SonicSF.playNote(
note.pitch || 60,
note.velocity || 0.8,
playDurMs,
startTime,
program,
subNode,
subCh,
subTrack.synth_engine
);
}
if (subRouteCarla) scheduleCarlaNote(subTrack.synth_engine, subCh, note.pitch || 60, note.velocity || 0.8, startTime, playDurMs);
// Trigger VU meter flash đúng nhp (c subTrack VU
// section tab + parent track VU MAIN): MIDI section đi
// SF masterBus.input (không qua sub-node analyser)
@@ -21287,16 +21339,19 @@ const App = () => {
}, delay * 1000);
} else {
const remainingDurMs = (notePlayEndMain - offsetTime) * 1000;
window.SonicSF.playNote(
note.pitch || 60,
note.velocity || 0.8,
remainingDurMs,
context.currentTime,
program,
subNode,
subCh,
subTrack.synth_engine
);
if (!subRouteCarla && window.SonicSF) {
window.SonicSF.playNote(
note.pitch || 60,
note.velocity || 0.8,
remainingDurMs,
context.currentTime,
program,
subNode,
subCh,
subTrack.synth_engine
);
}
if (subRouteCarla) scheduleCarlaNote(subTrack.synth_engine, subCh, note.pitch || 60, note.velocity || 0.8, context.currentTime, remainingDurMs);
if (window.triggerMidiVuActivity) {
// VU key theo CONTEXT (tách MAIN vs SECTION 07:20)
window.triggerMidiVuActivity((activeTab && activeTab.startsWith('session_') ? '_sess_' : '') + subTrack.id, note.velocity || 0.8);
@@ -21369,35 +21424,42 @@ const App = () => {
if (offsetTime < noteEndSec) {
const durationMs = noteDurSec * 1000;
const program = track.instrumentProgram !== undefined ? track.instrumentProgram : 0;
// MIDI item Carla bridge khi VSTi loaded (ch route Carla không
// play FluidSynth GM sai âm chng lên)
const routeToCarla = !!(window.SonicCarlaMidi && window.SonicCarlaMidi.shouldRoutePlayback(track.synth_engine));
if (offsetTime < noteStartSec) {
const delay = noteStartSec - offsetTime;
const startTime = context.currentTime + delay;
window.SonicSF.playNote(
note.pitch || 60,
note.velocity || 0.8,
durationMs,
startTime,
program,
gainNode,
lcCh,
track.synth_engine
);
if (!routeToCarla && window.SonicSF) {
window.SonicSF.playNote(
note.pitch || 60,
note.velocity || 0.8,
durationMs,
startTime,
program,
gainNode,
lcCh,
track.synth_engine
);
}
// MIDI items Carla bridge (track VSTi + Carla local)
scheduleCarlaNote(track.synth_engine, lcCh, note.pitch || 60, note.velocity || 0.8, startTime, durationMs);
if (routeToCarla) scheduleCarlaNote(track.synth_engine, lcCh, note.pitch || 60, note.velocity || 0.8, startTime, durationMs);
} else {
const remainingDurMs = (noteEndSec - offsetTime) * 1000;
window.SonicSF.playNote(
note.pitch || 60,
note.velocity || 0.8,
remainingDurMs,
context.currentTime,
program,
gainNode,
lcCh,
track.synth_engine
);
if (!routeToCarla && window.SonicSF) {
window.SonicSF.playNote(
note.pitch || 60,
note.velocity || 0.8,
remainingDurMs,
context.currentTime,
program,
gainNode,
lcCh,
track.synth_engine
);
}
// MIDI items Carla bridge (track VSTi + Carla local)
scheduleCarlaNote(track.synth_engine, lcCh, note.pitch || 60, note.velocity || 0.8, context.currentTime, remainingDurMs);
if (routeToCarla) scheduleCarlaNote(track.synth_engine, lcCh, note.pitch || 60, note.velocity || 0.8, context.currentTime, remainingDurMs);
}
}
});
@@ -21440,12 +21502,15 @@ const App = () => {
const effectiveDur = noteDurSec - Math.max(0, offsetSeconds - noteStartSec);
const scheduledTime = startWallTime + effectiveStart;
const durMs = effectiveDur * 1000;
if (window.SonicSF) {
// Track VSTi + Carla local note PHI play qua Carla bridge (ch route
// Carla không play FluidSynth GM sai âm chng lên)
const routeToCarla = !!(window.SonicCarlaMidi && window.SonicCarlaMidi.shouldRoutePlayback(synthEngine));
if (!routeToCarla && window.SonicSF) {
window.SonicSF.playNote(note.pitch || 60, note.velocity || 0.8, durMs, scheduledTime, instrumentProgram, destNode, mainCh, synthEngine);
}
// MIDI items Carla (track VSTi + Carla local): phát VSTi realtime
// (schedule theo audio clock bng setTimeout preview, timing gn đúng).
if (window.SonicCarlaMidi && window.SonicCarlaMidi.shouldRoutePlayback(synthEngine)) {
if (routeToCarla) {
const carlaDelay = Math.max(0, (scheduledTime - context.currentTime) * 1000);
const carlaVel = Math.round((note.velocity || 0.8) * 127);
const carlaCh = (synthEngine && synthEngine.midi_channel !== undefined) ? synthEngine.midi_channel : mainCh;
@@ -21474,11 +21539,12 @@ const App = () => {
var effDur = durSec - Math.max(0, offsetSeconds - startSec);
var schedTime = startWallTime + effStart;
var durMs = effDur * 1000;
if (window.SonicSF) {
// Ghost note Carla bridge khi ghost track VSTi (ch route Carla)
var gRouteCarla = !!(window.SonicCarlaMidi && window.SonicCarlaMidi.shouldRoutePlayback(ghostSynth));
if (!gRouteCarla && window.SonicSF) {
window.SonicSF.playNote(note.pitch || 60, note.velocity || 0.8, durMs, schedTime, ghostProg, ghostDest, ghostCh, ghostSynth);
}
// Ghost notes Carla bridge (ghost track VSTi + Carla local)
scheduleCarlaNote(ghostSynth, ghostCh, note.pitch || 60, note.velocity || 0.8, schedTime, durMs);
if (gRouteCarla) scheduleCarlaNote(ghostSynth, ghostCh, note.pitch || 60, note.velocity || 0.8, schedTime, durMs);
}
});
});