FIX: (1) masteringConnected default true + ensureMasteringRouting/refreshCarlaStatus ở mọi đường play — MIDI item/preview qua mastering ngay khi chạy app; (2) _instrumentEpoch chống cache stale + retry bank 0 — hết chọn Synth String nghe Piano; (3) /carla-status + auto-open Carla + route exclusive chỉ khi Carla sống (fallback FluidSynth tránh câm); (4) keybed giữ note theo thời gian bấm (auto-off 5s phòng hờ, mouseup dừng ngay)

This commit is contained in:
2026-08-10 09:51:58 +00:00
parent f492104869
commit 75eba27dcf
7 changed files with 135 additions and 26 deletions
+54 -8
View File
@@ -101,6 +101,38 @@ const scheduleCarlaNote = (synthEngine, channel, pitch, velocity, startWallTime,
} catch (e) { /* routing thất bại im lặng — soundfont vẫn chơi qua FluidSynth */ }
};
// Carla bridge alive tracking + auto-open
// window.__carlaRunning: undefined = chưa biết | true = đang chy | false = đã chết.
// Quyết đnh route MIDI item EXCLUSIVE qua Carla hay fallback FluidSynth
// tránh "câm toàn phn" khi Carla b đóng (route ch-Carla mà Carla chết = im lng).
const refreshCarlaStatus = () => {
try {
if (!window.SonicAPI || !window.SonicAPI.carlaStatus) return;
window.SonicAPI.carlaStatus().then(st => {
window.__carlaRunning = !!(st && st.running);
}).catch(() => { window.__carlaRunning = false; });
} catch (e) {}
};
// Carla chưa chy T ĐNG m vi VSTi ca track (fire-and-forget) đ MIDI
// item play qua Carla bridge đúng yêu cu.
const ensureCarlaForPlayback = (synthEngine) => {
try {
if (!window.SonicCarlaMidi || !window.SonicCarlaMidi.shouldRoutePlayback(synthEngine)) return;
if (!window.SonicAPI || !window.SonicAPI.carlaStatus) return;
window.SonicAPI.carlaStatus().then(st => {
if (st && st.running) { window.__carlaRunning = true; return; }
window.__carlaRunning = false;
const pid = synthEngine && synthEngine.plugin_id;
if (pid) {
window.SonicAPI.openInCarla(pid).then(r => {
if (r && r.success) { window.__carlaRunning = true; }
else { window.__carlaRunning = false; }
}).catch(() => { window.__carlaRunning = false; });
}
}).catch(() => { window.__carlaRunning = false; });
} catch (e) {}
};
// Handle ?sfs=<encoded> from double-clicking a .sfs file (opens domain -> loads project)
(function handleSfsDeepLink() {
@@ -9101,7 +9133,10 @@ const PianoRollTabEditor = ({ st, zoom, bpm, viewportWidth, activeTracks, onClos
window.triggerMidiVuActivity((st.parent_tab_id && st.parent_tab_id.startsWith('session_') ? '_sess_' : '') + st.trackId, 100);
}
if (window.SonicSF) {
window.SonicSF.playNote(pitch, 100, 500, undefined, kbCtx.program, null, kbCtx.ch, kbCtx.synthEngine);
// FIX: gi note theo thi gian bm phím durationMs ln (5s)
// ch là auto-off phòng h; mouseup/mouseleave gi stopNote dng
// NGAY (trưc đây 500ms note t tt gia chng khi gi phím).
window.SonicSF.playNote(pitch, 100, 5000, undefined, kbCtx.program, null, kbCtx.ch, kbCtx.synthEngine);
}
// MIDI Carla (track VSTi + ARM + Carla local): preview realtime
if (window.SonicCarlaMidi && window.SonicCarlaMidi.shouldRoute(kbCtx.synthEngine, st.isArmed)) {
@@ -9120,7 +9155,8 @@ const PianoRollTabEditor = ({ st, zoom, bpm, viewportWidth, activeTracks, onClos
window.triggerMidiVuActivity((st.parent_tab_id && st.parent_tab_id.startsWith('session_') ? '_sess_' : '') + st.trackId, 100);
}
if (window.SonicSF) {
window.SonicSF.playNote(pitch, 100, 200, undefined, kbCtx.program, null, kbCtx.ch, kbCtx.synthEngine);
// gi note khi kéo qua phím (mouse enter) dng bng mouseup/leave
window.SonicSF.playNote(pitch, 100, 5000, undefined, kbCtx.program, null, kbCtx.ch, kbCtx.synthEngine);
}
if (window.SonicCarlaMidi && window.SonicCarlaMidi.shouldRoute(kbCtx.synthEngine, st.isArmed)) {
window.SonicCarlaMidi.noteOn(kbCtx.ch, pitch, 100);
@@ -16392,7 +16428,7 @@ const App = () => {
const [fxRackTarget, setFxRackTarget] = useState(null);
window.__openFxRack = (trackId, trackName) => setFxRackTarget({ trackId, trackName });
const [masteringSettings, setMasteringSettings] = useState({
masterConnected: false,
masterConnected: true, // FIX: bt ON mc đnh MIDI item/preview PHI đưc x lí qua mastering FX ngay khi chy app (không cn bt/tt power)
activeModule: 'eq',
eqActive: true,
imagerActive: true,
@@ -21078,6 +21114,10 @@ const App = () => {
const startTrackPlayback = offsetTime => {
const context = getAudioContext();
// FIX: đng b mastering + Carla status NGAY khi play MIDI item phi
// qua mastering FX (khi bt) và qua Carla bridge (khi VSTi loaded).
try { if (window.__ensureMasteringRouting) window.__ensureMasteringRouting(); } catch (e) {}
refreshCarlaStatus();
const allPlayTracks = activeTracksRef.current && activeTracksRef.current.length ? activeTracksRef.current : activeTracks;
// Capture items signature at schedule time updatePlayhead so sánh vi
// signature này đ phát hin items đi v trí gia lúc play (re-schedule).
@@ -21134,6 +21174,7 @@ const App = () => {
if ((track.type === 'MIDI' || midiItems.length > 0) && window.SonicSF) {
// Preview cache: capture the soundfont (pre track-FX) for fast offline export
ensureMidiCapture(track, activeTrackNodesRef.current[track.id]);
if (window.SonicCarlaMidi && window.SonicCarlaMidi.shouldRoutePlayback(track.synth_engine)) ensureCarlaForPlayback(track.synth_engine);
var trkCh = assignTrackMidiChannel(track, allPlayTracks);
// Ensure instrument is loaded in FluidSynth
if (track.synth_engine && track.synth_engine.type === 'soundfont' && track.synth_engine.soundfont_id) {
@@ -21156,7 +21197,7 @@ const App = () => {
// 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));
const routeToCarla = !!(window.SonicCarlaMidi && window.SonicCarlaMidi.shouldRoutePlayback(track.synth_engine)) && window.__carlaRunning !== false;
if (offsetTime < noteStartSec) {
const delay = noteStartSec - offsetTime;
const startTime = context.currentTime + delay;
@@ -21303,7 +21344,8 @@ const App = () => {
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));
const subRouteCarla = !!(window.SonicCarlaMidi && window.SonicCarlaMidi.shouldRoutePlayback(subTrack.synth_engine)) && window.__carlaRunning !== false;
if (subRouteCarla || window.SonicCarlaMidi.shouldRoutePlayback(subTrack.synth_engine)) ensureCarlaForPlayback(subTrack.synth_engine);
if (offsetTime < noteStartMain) {
const delay = noteStartMain - offsetTime;
@@ -21372,6 +21414,8 @@ const App = () => {
// Solo playback for Local Selection Loop (LOOP_MAKER.md §2.2)
const startLocalTrackPlayback = (trackId, offsetTime) => {
const context = getAudioContext();
try { if (window.__ensureMasteringRouting) window.__ensureMasteringRouting(); } catch (e) {}
refreshCarlaStatus();
const track = tracks.find(t => t.id === trackId);
if (!track) return;
const clips = track.clips && track.clips.length > 0 ? track.clips : track.buffer ? [{
@@ -21426,7 +21470,7 @@ const App = () => {
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));
const routeToCarla = !!(window.SonicCarlaMidi && window.SonicCarlaMidi.shouldRoutePlayback(track.synth_engine)) && window.__carlaRunning !== false;
if (offsetTime < noteStartSec) {
const delay = noteStartSec - offsetTime;
const startTime = context.currentTime + delay;
@@ -21469,6 +21513,8 @@ const App = () => {
const schedulePianoRollMidi = (st, offsetSeconds, notesOverride) => {
if (st.type !== 'PIANO_ROLL') return;
const context = getAudioContext();
try { if (window.__ensureMasteringRouting) window.__ensureMasteringRouting(); } catch (e) {}
refreshCarlaStatus();
const midiNotes = notesOverride || st.notes || [];
const bpmVal = parseInt(bpm) || 120;
const secondsPerBeat = 60.0 / bpmVal;
@@ -21504,7 +21550,7 @@ const App = () => {
const durMs = effectiveDur * 1000;
// 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));
const routeToCarla = !!(window.SonicCarlaMidi && window.SonicCarlaMidi.shouldRoutePlayback(synthEngine)) && window.__carlaRunning !== false;
if (!routeToCarla && window.SonicSF) {
window.SonicSF.playNote(note.pitch || 60, note.velocity || 0.8, durMs, scheduledTime, instrumentProgram, destNode, mainCh, synthEngine);
}
@@ -21540,7 +21586,7 @@ const App = () => {
var schedTime = startWallTime + effStart;
var durMs = effDur * 1000;
// Ghost note Carla bridge khi ghost track VSTi (ch route Carla)
var gRouteCarla = !!(window.SonicCarlaMidi && window.SonicCarlaMidi.shouldRoutePlayback(ghostSynth));
var gRouteCarla = !!(window.SonicCarlaMidi && window.SonicCarlaMidi.shouldRoutePlayback(ghostSynth)) && window.__carlaRunning !== false;
if (!gRouteCarla && window.SonicSF) {
window.SonicSF.playNote(note.pitch || 60, note.velocity || 0.8, durMs, schedTime, ghostProg, ghostDest, ghostCh, ghostSynth);
}