them big_tasks.md (roadmap G0-G4, danh dau G1.1-G1.5 hoan thanh) + debug scripts/probes cua phien lam viec G0.1-G1.5 (test_g13/test_g12/test_g15_stress, patch_g1x, deploy/build bridge, probe_g0x)
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
# ROADMAP: Xử lý triệt để như DAW hiện đại — tách UI thread khỏi audio loop
|
||||
|
||||
Ngày: 2026-08-15 · Repo: `C:/Users/locpham/SonicForgeStudio` · Dựa trên bằng chứng
|
||||
`native_bridge/debug/BUG_REPORT.md` + source hiện tại (main.cpp, Vst3Instrument.cpp, lib.rs).
|
||||
|
||||
## Mục tiêu kiến trúc đích
|
||||
|
||||
DAW hiện đại (Cubase/Reaper/FL/Bitwig) tách:
|
||||
- **Audio thread**: real-time, chỉ gọi `process()`
|
||||
- **UI thread**: main UI thread, chạy `view->attached()` + message pump editor
|
||||
- (tuỳ chọn) **Plugin process riêng**: sandbox crash plugin khỏi engine
|
||||
|
||||
Bridge hiện tại gộp 2 thứ đầu vào 1 thread (`while(true)` vừa `renderAll()` vừa
|
||||
`PeekMessageW`, main.cpp:1220-1240) + attach job trên ChannelWorker → 2 thread 1
|
||||
DLL → Nexus throw/hang. Roadmap này tách UI khỏi audio đúng VST3 contract.
|
||||
|
||||
## Nguyên tắc vận hành (áp dụng cho MỌI task)
|
||||
|
||||
```
|
||||
1. Viết test tái hiện TRƯỚC (gui_probe variant / probe_appN / driver kịch bản)
|
||||
2. Implement tối thiểu (đúng phạm vi task)
|
||||
3. Chạy bộ test: gui_probe matrix + live driver + regression cũ
|
||||
4. Ghi nhận bug vào log + BUG_REPORT.md (mỗi bug: kịch bản, log, nguyên nhân)
|
||||
5. Fix → chạy lại → pass hết mới deploy
|
||||
6. Deploy exe vào install/ + commit (theo pattern git log hiện có)
|
||||
```
|
||||
|
||||
Không task nào merge nếu chưa: probe matrix pass + driver 3 run liên tiếp pass +
|
||||
screenshot GUI không trắng.
|
||||
|
||||
## GIAI ĐOẠN 0 — Ổn định hiện trạng (P0, ngăn máu chảy)
|
||||
|
||||
Làm ngay, độc lập kiến trúc. Không phải "xử lý triệt để" nhưng là nền để làm việc
|
||||
dài hạn không bị bug quấy phá.
|
||||
|
||||
| # | Task | File | Done khi |
|
||||
|---|---|---|---|
|
||||
| G0.1 | Chặn/defer OPEN_GUI khi transport PLAY (đợi STOP rồi attach; hoặc tạm dừng transport) | main.cpp handleOpenGui + Rust transport state | probe_app4_live: PLAY + OPEN_GUI → không EXCEPTION, attach sau STOP thành công |
|
||||
| G0.2 | Bỏ spam `openVstGuiRetry` 20×500ms → tối đa 2 lần, có backoff, không retry khi đang PLAY | app/static/js/app.precompiled.js | bridge.log không còn chuỗi EXCEPTION/FAILED lặp; stall không xảy ra |
|
||||
| G0.3 | Watchdog né giết khi attach-in-flight (flag SHM hoặc stall type riêng) | lib.rs:397 + shm | Stall do attach dài → không kill; stall thật → kill như cũ |
|
||||
| G0.4 | Save/restore state nhanh (getState trước khi reload, setState sau) | Vst3Instrument.cpp | Mở GUI → đóng → mở lại: preset giữ nguyên |
|
||||
|
||||
## GIAI ĐOẠN 1 — Tách GUI pump khỏi audio loop (P1, lõi triệt để)
|
||||
|
||||
**Vấn đề hiện tại**: main thread vừa render audio vừa pump message editor.
|
||||
Attach job chạy ChannelWorker (thread khác) → 2 thread 1 DLL.
|
||||
|
||||
**Đích**: main thread chỉ render audio. Thread UI mới (native UI thread) tạo window
|
||||
+ pump message editor + chạy toàn bộ attach/close. Đúng mô hình Steinberg
|
||||
`editorhost.cpp`: 1 UI thread, 1 audio thread.
|
||||
|
||||
| # | Task | File | Done khi |
|
||||
|---|---|---|---|
|
||||
| G1.1 | Thêm `UiThread` (thread riêng, COM STA, message pump riêng, job queue) | main.cpp mới class | gui_probe variant `ui_thread` tương đương bridge mới: Nexus attach OK không hang |
|
||||
| G1.2 | Chuyển tạo window + attach job từ ChannelWorker → UiThread; audio loop bỏ `PeekMessageW` | main.cpp | Probe bridge arch mới: 2 instance Nexus attach OK, không HANG (so với bridge_two HANG hiện tại) |
|
||||
| G1.3 | Chuyển close/resize/IME sang UiThread; bỏ pump gate cũ (g_juceTidsMutex...) nếu không còn cần | main.cpp | close editor đang PLAY không crash; không cần mute workaround |
|
||||
| G1.4 | Bỏ mute-when-editor-open (g_editorOpen/g_editorPathCount) — test lại | main.cpp | 6 Nexus + GUI ch5 mở khi PLAY: track khác vẫn kêu (mute hiện tại làm track câm) |
|
||||
| G1.5 | Regression: driver stress 6 Nexus + Ample + EZkeys, mở/đóng GUI khi PLAY | driver + probe | 3 run liên tiếp không crash/stall |
|
||||
|
||||
## GIAI ĐOẠN 2 — Persistence: restart không mất instrument (P2)
|
||||
|
||||
Trả lời câu hỏi "stop/play nghe lại". Hiện bridge kill = mất hết instance (state
|
||||
trong memory process).
|
||||
|
||||
| # | Task | File | Done khi |
|
||||
|---|---|---|---|
|
||||
| G2.1 | `saveState()`/`restoreState()` đầy đủ (IComponentHandler/getState, preset, MIDI routing) | Vst3Instrument.cpp + NativeInstrumentEngine | Save → reload → restore: âm thanh/preset giống hệt |
|
||||
| G2.2 | Bridge dump state ra file khi shutdown/trước kill (SIGHUP/SHM flag) | main.cpp + lib.rs | Kill bridge → state file có đủ 16 channel |
|
||||
| G2.3 | Frontend auto-reload sau respawn: đọc state file → bridgeLoad lại từng track | app + NativeBridgeService | Giết bridge giữa PLAY → bridge mới tự nạp lại, PLAY tiếp tục, không câm |
|
||||
| G2.4 | Bỏ `!isPlayingRef.current` chặn restore khi đang play | app.precompiled.js:816 | Restore chạy được cả khi PLAY |
|
||||
|
||||
## GIAI ĐOẠN 3 — Watchdog thông minh + health (P3)
|
||||
|
||||
| # | Task | File | Done khi |
|
||||
|---|---|---|---|
|
||||
| G3.1 | Heartbeat riêng (thread bridge ghi timestamp mỗi 100ms) tách khỏi writeIndex audio | main.cpp + shm.rs + lib.rs | Bridge sống nhưng audio stall → không kill; bridge chết → phát hiện <1s |
|
||||
| G3.2 | Phân loại stall: audio (render quá lâu) vs GUI job (attach/close) vs chết | lib.rs | Mỗi loại có policy riêng (GUI: đợi, không kill) |
|
||||
| G3.3 | Bridge tự phục hồi lỗi plugin: catch crash riêng channel (SEH quanh process của từng channel) | main.cpp renderAll | 1 plugin crash → mute channel đó, các channel khác chạy tiếp (giống DAW sandbox-lite) |
|
||||
|
||||
## GIAI ĐOẠN 4 — Sandbox plugin process riêng (P4, tuỳ chọn tham vọng)
|
||||
|
||||
VST3 không có chuẩn out-of-process như AUv3 → cần wrapper tự làm. Đây là bước xa
|
||||
nhất, chỉ làm khi G1-G3 chưa đủ.
|
||||
|
||||
| # | Task | File | Done khi |
|
||||
|---|---|---|---|
|
||||
| G4.1 | Nghiên cứu: host plugin trong process con (VST3 host trong exe thứ 2), audio qua SHM | thiết kế mới | PoC 1 plugin Nexus trong process con, GUI + audio OK |
|
||||
| G4.2 | Bridge → client process pool (1 process/plugin hoặc /nhóm) | thiết kế mới | Plugin crash → process con chết, bridge + GUI sống |
|
||||
| G4.3 | IPC audio real-time (SHM ring buffer double-buffer) | thiết kế mới | 6 Nexus song song, latency < 20ms, không xrun |
|
||||
|
||||
**Cân nhắc**: G4 là dự án riêng (ước lượng gấp 3-5× G1+G2). Khuyến nghị: làm G0-G3
|
||||
trước; G4 chỉ khi cần cô lập crash plugin thật sự (hiện G3.3 + G1 đã lo được 90%
|
||||
kịch bản bug).
|
||||
|
||||
## Thứ tự thực hiện đề xuất
|
||||
|
||||
```
|
||||
G0.1 → G0.2 → G0.3 → G0.4 (1-2 tuần, an toàn ngay, trả lời "stop/play nghe lại" một phần qua G0.4)
|
||||
↓
|
||||
G1.1 → G1.2 → G1.3 → G1.4 → G1.5 (3-5 tuần, lõi triệt để — mở GUI khi PLAY thành công)
|
||||
↓
|
||||
G2.1 → G2.2 → G2.3 → G2.4 (2-3 tuần, restart không câm)
|
||||
↓
|
||||
G3.1 → G3.2 → G3.3 (1-2 tuần, health đầy đủ)
|
||||
↓
|
||||
G4.* (tuỳ chọn, 2-3 tháng)
|
||||
```
|
||||
|
||||
## Bắt đầu ngay — task đầu tiên
|
||||
|
||||
**G0.1**: sửa `handleOpenGui` (main.cpp:943) — nếu transport PLAY, đưa OPEN_GUI
|
||||
vào `g_pendingGui` (đã có cơ chế defer cho "chưa load"), sweep xử lý khi transport
|
||||
STOP. Kèm test: `probe_app4_live.py` biến thể "PLAY rồi OPEN_GUI rồi STOP" — kỳ
|
||||
vọng không EXCEPTION, GUI attach sau STOP.
|
||||
|
||||
## Files liên quan hiện tại
|
||||
|
||||
- `native_bridge/src/main.cpp` — loop (1220), handleOpenGui (943), ChannelWorker, mute/close
|
||||
- `native_bridge/src/Vst3Instrument.cpp` — reload (615), reloadForGUI (528), attachView (550)
|
||||
- `native_bridge/src/gui_probe.cpp` — probe variants (bridge_two 243, two_workers_close 318)
|
||||
- `native_bridge/src/lib.rs` → thực tế `src-tauri/src/lib.rs` — watchdog (356-430), kill/spawn (50,135)
|
||||
- `app/static/js/app.precompiled.js` — openVstGuiRetry (470), restore (816)
|
||||
- `native_bridge/debug/` — BUG_REPORT.md, sweep_bridge_two_8s.json, probe_attach_detail.py, probe_app4_live.py
|
||||
Reference in New Issue
Block a user