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:
+135
-69
@@ -20805,6 +20805,16 @@ const App = () => {
|
||||
}
|
||||
if (_prNode.gainNode) {
|
||||
window.SonicSF.setOutputDestination(_prNode.gainNode);
|
||||
// ⚠️ FIX: sync route gains NGAY tại thời điểm routing — trước đây
|
||||
// bỏ qua → node giữ bypass cũ (tạo khi mastering OFF / audioBypass
|
||||
// true) → preview âm soundfont KHÔNG qua mastering cho tới khi bật/
|
||||
// tắt 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 tới khi bật/tắt 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 MỌI node đang tồn tại (route + sf route) theo trạng thái
|
||||
// hiện tại — phòng node tạo từ trước với bypass cũ (mastering OFF lúc
|
||||
// tạo node / audioBypass default true của section) → preview LUÔN qua
|
||||
// mastering khi chain bật, không cần bật/tắt 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 PHẢI play qua Carla bridge
|
||||
// (chỉ route Carla — KHÔNG play qua FluidSynth GM nữa, tránh âm
|
||||
// sai instrument chồng 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 cầu: MIDI item PHẢI 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 nhảy
|
||||
@@ -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 nhịp (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 chồng 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 PHẢI play qua Carla bridge (chỉ route
|
||||
// Carla — không play FluidSynth GM sai âm chồng 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 bằng setTimeout — preview, timing gần đú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);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user