fix(fx): realtime VST ngắt quãng khi mở MASTERING PANEL + PWR master không ảnh hưởng âm; pacing WS input/output, gate fxRt theo masterConnected, worklet cap 32
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
# PLAN: VST FX SHM realtime
|
||||
|
||||
Mục tiêu: VST3 FX (master FX chain + track chain) xử lý THẬT realtime qua
|
||||
fx_vst_bridge — không còn pass-through khi nghe live.
|
||||
|
||||
Kiến trúc (cloud-FX loop, latency ~2 block):
|
||||
WebAudio (masterBus.output)
|
||||
→ AudioWorklet (sf-fx-realtime.js) — input block
|
||||
→ WebSocket (engine /ws/fx-realtime/{id})
|
||||
→ Python SHM input ring (SonicForge_FXRT_*)
|
||||
→ fx_vst_bridge.exe --realtime-fx (RealtimeFxChain::process, SEH-guarded)
|
||||
→ SHM output ring
|
||||
→ Python → WebSocket → AudioWorklet output → graph
|
||||
|
||||
SHM layout FxRealtimeIPC (C++ struct = Python ctypes mirror, all u32/float 4B):
|
||||
header u32: magic(0x46585254) state sampleRate blockSize running heartbeat
|
||||
inWrite inRead inSlots outWrite outRead outSlots (48 bytes)
|
||||
inL[4][256] inR[4][256] outL[8][256] outR[8][256]
|
||||
|
||||
Files:
|
||||
1. native_bridge/include/FxRealtimeIPC.h — struct + constants (mới)
|
||||
2. native_bridge/src/RealtimeFxLoop.cpp — loop (mới)
|
||||
3. native_bridge/src/main_fx.cpp — thêm --realtime-fx
|
||||
4. native_bridge/CMakeLists.txt — thêm 2 file vào fx_vst_bridge
|
||||
5. app/core/fx_realtime.py — session SHM + spawn (mới)
|
||||
6. app/api/v1/plugins.py — /fx-realtime/start, /stop, WS
|
||||
7. app/static/js/sf-fx-realtime.js — AudioWorklet (mới)
|
||||
8. app/static/js/app.jsx — fxRealtimeManager wiring
|
||||
9. engine.spec — hiddenimport websockets
|
||||
|
||||
v1 scope: MASTER chain realtime (chỗ VST3 bị skip trong rebuildMasteringGraph).
|
||||
Track chain realtime: ponytail — per-track session sau (export offline đã có).
|
||||
|
||||
## Trạng thái: ✅ v1 DONE (2026-08-20)
|
||||
|
||||
- Bridge build OK (native_bridge/build/Release/fx_vst_bridge.exe) + deploy sidecar
|
||||
(src-tauri/binaries/fx_vst_bridge-x86_64-pc-windows-msvc.exe +
|
||||
src-tauri/target/release/fx_vst_bridge.exe).
|
||||
- Engine build OK (websockets bundled) + deploy target/release + resources.
|
||||
- Frontend build OK (app.precompiled.js + sf-fx-realtime.js static serve).
|
||||
- E2E đã test trên engine deploy (port 8000):
|
||||
- POST /fx-realtime/start (purecomp.vst3, 44100) → session_id + ws_url ✓
|
||||
- WS binary loop: chain rỗng = passthrough bit-exact (peak 0.5/rms 0.35) ✓
|
||||
- WS + purecomp: peak 0.5→0.462, rms 0.35→0.246 (compressor attenuate) ✓
|
||||
- WS disconnect → session tự stop, fx_vst_bridge.exe thoát ✓
|
||||
- POST /fx-realtime/stop → stopped:true ✓
|
||||
- WS token sai → reject (handshake 403) ✓
|
||||
- FIX phát hiện khi test: WS drain output chỉ trong vòng receive_bytes → output
|
||||
thừa kẹt SHM ring khi client ngừng gửi → tách _pump_output() task riêng.
|
||||
|
||||
## Trạng thái: ✅ TRACK REALTIME DONE (2026-08-20)
|
||||
|
||||
- Track chain realtime: mọi luồng âm thanh track qua bridge
|
||||
(fx_vst_bridge --realtime-fx + SHM SonicForge_FXRT_*) trước main out.
|
||||
- Module-level `fxRtTracks` map 'trackId:audio|sf' + fxRtTrackChain/Paths/
|
||||
Start/Splice/Stop/Reconcile/StopAll trong app.jsx; gọi từ rebuildTrackFxGraph,
|
||||
startTrackPlayback, stopAllPlayback, FX Rack panel.
|
||||
- `fxRtTrackPaths`: audio nếu clips.length>0 || buffer || sections.length>0;
|
||||
sf nếu midiItems.length>0 || type==='MIDI' || instrumentId.
|
||||
- E2E ổn định (pw_e2e2.py ×3): splice 3 audio + 3 sf, track audio out
|
||||
peak≈0.47 rms≈0.33, sf câm hợp lệ (MIDI taiko không route sfEntry), master
|
||||
Ozone peak≈0.85-0.99. Master câm khi track mastering_bypass=true — hợp lệ.
|
||||
- FIX bug bypass toggle: reconcile đọc state CŨ (React setState async) khi
|
||||
`onChange` gọi `__rebuildTrackFxGraph(track.id)` đồng bộ → bypass không stop
|
||||
session. Fix: `rebuildTrackFxGraph = (trackId, patch)` merge
|
||||
`track = { ...track, ...patch }` TRƯỚC khi rebuild/reconcile; 4 call site
|
||||
(bypass, fxActive, setVstChain, setChain) truyền patch giá trị MỚI.
|
||||
Verify: toggle bypass-on → reconcile want=[] → stop ngay; bypass-off →
|
||||
want=["sf"] → start mới + spliced.
|
||||
- Debug log tạm đã gỡ (giữ `[FX RT track] spliced` + console.warn lỗi);
|
||||
rebuild bundle 1370231 bytes, served LEN khớp local.
|
||||
|
||||
Ponytail còn lại:
|
||||
- Sub-tab (piano roll) play chưa start fxRt — chỉ main/section play.
|
||||
- Chain đổi giữa lúc play chưa restart session (start/stop theo play boundary).
|
||||
- Browser-side queue drop-oldest (8 block) — thay adaptive stretch nếu cần.
|
||||
- Chưa test UI thật trong WebView (graph insertion AudioWorkletNode) — plumbing
|
||||
đã verify qua WS; mở app + bật master VST chain + play để xác nhận âm thanh.
|
||||
|
||||
## Trạng thái: ✅ MASTER REALTIME UI VERIFIED (2026-08-20, engine sống)
|
||||
|
||||
- Verify UI-level: login → inject `window.currentMasteringSettings.vstFxChain`
|
||||
(path đúng `C:\Program Files\Common Files\VST3\Sonible\purecomp.vst3`) →
|
||||
insert clip → Play. Monkey-patch `SonicAPI.fxRealtimeStart` ghi payload→sid.
|
||||
Kết quả (pw_master3.py): call #1 = master (purecomp, engine trả session_id +
|
||||
ws_url) → WS `SonicForge_FXRT_d19c01fc33da` nhận audio 738 frame, out
|
||||
peak 0.4622 / rms 0.1442 vs input sine 0.5/0.35 = attenuate ✓.
|
||||
Track sessions (call #2/#3) chạy song song; stop → WS close, `--realtime-fx`
|
||||
bridge thoát, chỉ còn 2 `--fx-gui` của user (không đụng). Engine @8000 OK.
|
||||
- WS-level (rt_test2.py) trước đó: master realtime attenuate peak 0.4621 rms
|
||||
0.2462 với path đúng `Sonible\purecomp.vst3` (path sai `SoniBook` = passthrough
|
||||
thầm lặng).
|
||||
- Nguyên nhân "VST FX PLUGIN trong master chain peak -inf" (trả lời user):
|
||||
1) Engine bị kill lúc test → `SonicAPI.fxRealtimeStart` fail → `fxRtStart`
|
||||
catch + toast cảnh báo, KHÔNG session → masterBus.output nối thẳng
|
||||
analyser → âm nghe được nhưng KHÔNG qua VST → meter plugin -inf.
|
||||
2) Chain rỗng / vstBypass=true → `fxRtChain()` = [] → không session (âm qua
|
||||
thẳng, không lỗi) → meter -inf.
|
||||
3) Meter trong GUI embed (`--fx-gui`) là của instance GUI RIÊNG (config JSON
|
||||
chỉ path+name; VstGuiEmbed chỉ /frame /ping /input — KHÔNG có audio
|
||||
endpoint) → GUI embed KHÔNG nhận audio realtime SHM session → meter -inf
|
||||
VÔ ĐIỀU KIỆN kể cả khi realtime đang chạy. Audio thật đi qua instance
|
||||
`--realtime-fx` riêng (không hiển thị meter). → ponytail thật: user không
|
||||
thấy meter plugin thật; nơi thấy tín hiệu = master VU meter của app
|
||||
(post-chain) hoặc WS session.
|
||||
- Lưu ý: `masterFxList` (Plugin Picker mastering) load trong useEffect([]) của
|
||||
MasteringModal mount sẵn từ đầu → trước khi SonicAPI sẵn sàng → picker rỗng
|
||||
trong headless; track modal mount trễ hơn nên đầy. Workaround: chờ SonicAPI
|
||||
rồi mới mở modal, hoặc inject chain trực tiếp. (Không phải lỗi engine.)
|
||||
Reference in New Issue
Block a user