FIX: sửa lỗi MIDI item với fx mastering tồn tại và không qua Carla

This commit is contained in:
2026-08-10 17:48:38 +07:00
parent a1dc074e35
commit 67ad2b8e4b
3 changed files with 83 additions and 15 deletions
+35 -4
View File
@@ -15283,9 +15283,14 @@ const App = () => {
setLastMidiNote({ pitch, velocity: scaledVel, length: 0, time: Date.now() }); setLastMidiNote({ pitch, velocity: scaledVel, length: 0, time: Date.now() });
activeMidiPitchesRef.current.add(pitch); activeMidiPitchesRef.current.add(pitch);
setActiveMidiPitches(new Set(activeMidiPitchesRef.current)); setActiveMidiPitches(new Set(activeMidiPitchesRef.current));
// Route MIDI input to ALL armed tracks on their dedicated channels // MIDI Keyboard Mastering FX Chain (main out): đng b routing
// Do NOT use raw MIDI hardware channel (msg.data[0] & 0x0F) // mastering + SF NGAY trưc khi phát âm MIDI keyboard hardware
if (window.SonicSF) { // PHI qua mastering FX khi chain đang bt (ging keybed; trưc
// đây ch keybed o gi __ensureMasteringRouting).
try { if (window.__ensureMasteringRouting) window.__ensureMasteringRouting(); } catch (er) {}
// Route MIDI input to ALL armed tracks on their dedicated channels
// Do NOT use raw MIDI hardware channel (msg.data[0] & 0x0F)
if (window.SonicSF) {
var allTracks = activeTracksRef.current || []; var allTracks = activeTracksRef.current || [];
var arSubs = subTabsRef && subTabsRef.current ? subTabsRef.current.filter(function(s) { return s.type === 'PIANO_ROLL' && s.isArmed; }) : []; var arSubs = subTabsRef && subTabsRef.current ? subTabsRef.current.filter(function(s) { return s.type === 'PIANO_ROLL' && s.isArmed; }) : [];
var armedTracks = allTracks.filter(function(t) { return t.isArmed; }); var armedTracks = allTracks.filter(function(t) { return t.isArmed; });
@@ -15305,6 +15310,11 @@ const App = () => {
heldMidiNotesRef.current[as.trackId] = (heldMidiNotesRef.current[as.trackId] || 0) + 1; heldMidiNotesRef.current[as.trackId] = (heldMidiNotesRef.current[as.trackId] || 0) + 1;
} catch (err) { } } catch (err) { }
window.SonicSF.playNote(pitch, scaledVel, 60000, undefined, asProg, null, asCh, asSe); window.SonicSF.playNote(pitch, scaledVel, 60000, undefined, asProg, null, asCh, asSe);
// MIDI Keyboard Carla bridge (piano roll sub-tab ARM):
// track VSTi ca sub-tab phát VSTi realtime ging keybed.
if (window.SonicCarlaMidi && window.SonicCarlaMidi.shouldRoute(asSe, true)) {
try { window.SonicCarlaMidi.noteOn(asCh, pitch, scaledVel); } catch (e) {}
}
}); });
} }
// Route to ALL armed tracks (not just the first one) // Route to ALL armed tracks (not just the first one)
@@ -15321,7 +15331,14 @@ const App = () => {
heldMidiNotesRef.current[at.id] = (heldMidiNotesRef.current[at.id] || 0) + 1; heldMidiNotesRef.current[at.id] = (heldMidiNotesRef.current[at.id] || 0) + 1;
} catch (err) { } } catch (err) { }
window.SonicSF.playNote(pitch, scaledVel, 60000, undefined, atProg, atDest, atCh, atSe); window.SonicSF.playNote(pitch, scaledVel, 60000, undefined, atProg, atDest, atCh, atSe);
}); // MIDI Keyboard Carla bridge (track VSTi + ARM + Carla
// local): phát VSTi realtime ging ht keybed o. Trưc
// đây ch keybed gi SonicCarlaMidi; keyboard hardware b
// b sót track VSTi không kêu khi bm đàn tht.
if (window.SonicCarlaMidi && window.SonicCarlaMidi.shouldRoute(atSe, at.isArmed)) {
try { window.SonicCarlaMidi.noteOn(atCh, pitch, scaledVel); } catch (e) {}
}
});
} }
} else if (cmd === 0x8 || (cmd === 0x9 && rawVel === 0)) { } else if (cmd === 0x8 || (cmd === 0x9 && rawVel === 0)) {
activeMidiPitchesRef.current.delete(pitch); activeMidiPitchesRef.current.delete(pitch);
@@ -15343,6 +15360,11 @@ const App = () => {
if (!st.synth_engine && st.midiChannel === undefined) return; if (!st.synth_engine && st.midiChannel === undefined) return;
var stCh = assignTrackMidiChannel(st, stopTracks); var stCh = assignTrackMidiChannel(st, stopTracks);
window.SonicSF.stopNote(stCh, pitch); window.SonicSF.stopNote(stCh, pitch);
// MIDI Keyboard Carla bridge: note-off khi th phím tránh
// kt âm VSTi (ging keybed o).
if (window.SonicCarlaMidi && window.SonicCarlaMidi.shouldRoute(st.synth_engine, st.isArmed)) {
try { window.SonicCarlaMidi.noteOff(stCh, pitch); } catch (e) {}
}
// Gim counter note đang gi hết note VU đưc phép decay/tt // Gim counter note đang gi hết note VU đưc phép decay/tt
// (tick s thy counter = 0 và không còn gi peak na) // (tick s thy counter = 0 và không còn gi peak na)
try { try {
@@ -24686,6 +24708,15 @@ const App = () => {
try { try {
toggleMasteringOnMaster(!!(masteringSettings && masteringSettings.masterConnected), !!(masteringSettings && masteringSettings.isBypassed)); toggleMasteringOnMaster(!!(masteringSettings && masteringSettings.masterConnected), !!(masteringSettings && masteringSettings.isBypassed));
} catch (e) { console.warn('offline mastering toggle error:', e); } } catch (e) { console.warn('offline mastering toggle error:', e); }
// Main out volume (master fader) áp vào offline bus file export phi
// đúng đ ln nghe đưc (flow: ... Mastering FX Chain Main out).
// Trưc đây offline masterBus.output luôn = 1.0 export sai volume.
try {
if (masterBus && masterBus.output) {
const mv = (typeof masterVolume === 'number' && isFinite(masterVolume)) ? masterVolume : 0;
masterBus.output.gain.setValueAtTime(mv <= -50 ? 0 : Math.pow(10, mv / 20), 0);
}
} catch (e) { console.warn('offline main-out volume error:', e); }
activeTracks.forEach(t => { activeTracks.forEach(t => {
const node = buildOfflineTrackNode(t, offlineCtx, offlineNodes); const node = buildOfflineTrackNode(t, offlineCtx, offlineNodes);
if (!node) return; if (!node) return;
File diff suppressed because one or more lines are too long
+22
View File
@@ -231,3 +231,25 @@ plugin/preset** (khác "Preview Synth WASM" cũ — âm giả).
- [ ] Docker (`SF_DOCKER=1`): capabilities `runtime=headless`, không hiện Carla Bridge, preset upload hoạt động, render VSTi Linux + soundfont từ mount OK - [ ] Docker (`SF_DOCKER=1`): capabilities `runtime=headless`, không hiện Carla Bridge, preset upload hoạt động, render VSTi Linux + soundfont từ mount OK
- [ ] `SF_RUNTIME=desktop` trên Linux có DISPLAY → chạy như desktop - [ ] `SF_RUNTIME=desktop` trên Linux có DISPLAY → chạy như desktop
- [ ] pytest: `86 passed, 7 skipped` - [ ] pytest: `86 passed, 7 skipped`
## 9. Flow MIDI Keyboard hardware (Web MIDI) — route đầy đủ
Hardware MIDI keyboard (Web MIDI API) đi qua ĐÚNG flow như keybed ảo:
```
MIDI Keyboard (hardware, Web MIDI)
├─ note-on → ensureMasteringRouting() (ép âm qua Mastering FX Chain khi bật)
│ → SonicSF.playNote() (track soundfont/GM — qua track node → mastering)
│ → SonicCarlaMidi.noteOn() (track VSTi + ARM + Carla local — OSC /Carla/0/note_on)
├─ note-off → SonicSF.stopNote() (dừng soundfont)
│ → SonicCarlaMidi.noteOff() (dừng VSTi trong Carla — tránh kẹt âm)
└─ CC64/CC1/Pitch Bend → SonicSF.controllerChange()/pitchBend() (armed tracks)
```
Trước đây chỉ keybed ảo (piano roll) gọi `SonicCarlaMidi` + `__ensureMasteringRouting`;
keyboard hardware bị bỏ sót → track VSTi không kêu khi bấm đàn thật, và âm soundfont
không qua mastering cho tới khi bật/tắt power. Đã sửa tại `onmidimessage` handler
(`app.jsx`): note-on/note-off route qua Carla bridge + ép đồng bộ mastering routing.
Export offline (`clientSideExport`) cũng áp **Main out volume** (master fader) vào
offline master bus — file WAV đúng độ lớn nghe được (trước đây luôn 1.0).