c382afe2a6
Linux parts (0L1-4L1 per TASKS_LINUX_WINDOWS.md): - native_bridge: FxGuiServer.cpp HTTP server (Winsock) — /frame BitBlt + PrintWindow fallback -> JPEG (libjpeg-turbo q70), /input PostMessage relay (mouse/wheel/key, coords scaled), /close, /ping; RenderFxJob fxGuiSetup + run_fx_gui_server (offscreen); main.cpp --fx-gui dispatch; vcpkg + CMakeLists WIN32-only + JPEG. - api: open_fx_gui embed flag spawn --fx-gui, parse SF_FXGUI_PORT -> embed_url, fx-gui/close endpoint; 4 unit tests. - ui: VstGuiEmbed component (frame refresh 100ms, ping 2s, input relay, scale coords) shared by MasteringModal + FXRackModal; swap graph<->GUI, cleanup on unmount, dead-bridge toast fallback. - docs: TASKS_LINUX_WINDOWS.md, WALKTHROUGH_WINDOWS.md, PLAN status. Windows tasks 0W1-4W1 remain (build + E2E real VST).
184 lines
10 KiB
Markdown
184 lines
10 KiB
Markdown
# TASKS: Nhúng VST GUI — tách theo máy (Linux / Windows)
|
|
|
|
Nguồn: `PLAN_MASTERBUS_VST_GUI_EMBED.md` (Phase 0-4). Mỗi task ghi rõ máy thực
|
|
hiện, file đụng, lệnh, deliverable, test, phụ thuộc.
|
|
|
|
Nguyên tắc tách:
|
|
- **Linux** (máy dev hiện tại): viết mọi source code (C++ bridge, Python API,
|
|
frontend JSX), build frontend, chạy unit test (mock bridge), commit.
|
|
- **Windows** (máy chạy VST thật): build bridge C++ (MSVC/vcpkg), mọi E2E thật
|
|
với plugin (Ozone...) — BitBlt/PrintWindow/SendMessage chỉ chạy Windows.
|
|
- Linux KHÔNG build được bridge (CMake bỏ VST3/GUI khi không WIN32; `main_linux.cpp`
|
|
chỉ render offline). Linux KHÔNG có VST GUI để test E2E thật.
|
|
|
|
Ký hiệu: `[L]` = làm trên Linux · `[W]` = làm trên Windows.
|
|
|
|
---
|
|
|
|
## PHASE 0 — Bridge `--fx-gui` (HTTP server + capture + input relay)
|
|
|
|
### Task 0L1 — Viết `FxGuiServer.cpp` (hoặc mở rộng RenderFxJob.cpp nếu <300 dòng)
|
|
- Máy: `[L]` · File: `native_bridge/src/FxGuiServer.cpp` (mới) + `native_bridge/src/RenderFxJob.cpp` (hook mode `--fx-gui`)
|
|
- Nội dung (giữ nguyên phần attach IPlugView có sẵn `fxGuiAttachSafe`):
|
|
- Mode `--fx-gui <job.json>`: sau khi attach view, khởi động HTTP server mini
|
|
port ngẫu nhiên → in `SF_FXGUI_PORT=<port>` ra stdout (Python đọc).
|
|
- `GET /frame` → chụp HWND plugin bằng `BitBlt` (fallback `PrintWindow`
|
|
`PW_RENDERFULLCONTENT`) → trả `image/jpeg` quality ~70.
|
|
- `POST /input` `{type, x, y, button, deltaY, keyCode}` → `PostMessage`/`SendMessage`
|
|
theo tọa độ scale client rect (gửi `WM_MOUSEMOVE` trước click).
|
|
- `POST /close` → detach view, thoát exit 0. `GET /ping` → alive.
|
|
- Toàn bộ Win32 API → bọc `#ifdef _WIN32` hoặc chỉ build khi WIN32 (xem Task 0L2).
|
|
- Lệnh kiểm tra: không build được trên Linux — chỉ kiểm tra bằng mắt/syntax
|
|
(`g++ -fsyntax-only` không đủ do thiếu windows.h → bỏ qua, sang Task 0W1).
|
|
- Deliverable: source bridge có mode `--fx-gui`.
|
|
- Phụ thuộc: không.
|
|
|
|
### Task 0L2 — Cập nhật `CMakeLists.txt` cho source mới
|
|
- Máy: `[L]` · File: `native_bridge/CMakeLists.txt`
|
|
- Thêm source file mới vào target `daw_vst_bridge` CHỈ khi `WIN32` (giữ Linux build
|
|
không vỡ — Linux hiện build `main_linux.cpp` render-only).
|
|
- Lệnh kiểm tra: `cmake -S native_bridge -B /tmp/nb-linux-check && cmake --build /tmp/nb-linux-check --target daw_vst_bridge` → PASS trên Linux.
|
|
- Deliverable: Linux build vẫn xanh, Windows build có file mới.
|
|
- Phụ thuộc: 0L1.
|
|
|
|
### Task 0W1 — Build bridge trên Windows
|
|
- Máy: `[W]` · Lệnh: `powershell -ExecutionPolicy Bypass -File build/scripts/build_native_bridge.ps1`
|
|
(bootstrap vcpkg, fluidsynth, sfizz 1.2.3, vst3sdk submodule, CMake VS2019 x64,
|
|
copy `daw_vst_bridge.exe` + `libfluidsynth-3.dll` → `src-tauri\binaries\`).
|
|
- Điều kiện máy: VS Build Tools 2019+, CMake, git, đã pull submodule
|
|
(`git submodule update --init --recursive -- native_bridge/vst3sdk`).
|
|
- Deliverable: `native_bridge/build/Release/daw_vst_bridge.exe` + sidecar trong `src-tauri\binaries\`.
|
|
- Test: exe tồn tại, chạy `--help` không crash.
|
|
- Phụ thuộc: 0L1, 0L2 (pull code mới về Windows trước).
|
|
|
|
### Task 0W2 — Self-check bridge `--fx-gui` thủ công
|
|
- Máy: `[W]`
|
|
- Lệnh:
|
|
1. Tạo `job.json`: `{"path": "C:\\VST\\Ozone11.vst3", "name": "Ozone 11"}`.
|
|
2. `native_bridge\build\Release\daw_vst_bridge.exe --fx-gui job.json` → đọc port từ stdout.
|
|
3. `curl http://127.0.0.1:<port>/ping` → alive.
|
|
4. `curl -o frame.jpg http://127.0.0.1:<port>/frame` → JPEG, kích thước = kích thước GUI plugin.
|
|
5. `curl -X POST http://127.0.0.1:<port>/input -H "Content-Type: application/json" -d '{"type":"mousemove","x":100,"y":100,"button":0}'` rồi `{"type":"mousedown","x":100,"y":100,"button":0}` + `mouseup` → click trúng nút trong GUI (quan sát đổi trạng thái).
|
|
6. `curl -X POST http://127.0.0.1:<port>/close` → process thoát exit 0.
|
|
- Deliverable: /frame trả ảnh đúng, /input điều khiển được, /close sạch.
|
|
- Phụ thuộc: 0W1.
|
|
|
|
---
|
|
|
|
## PHASE 1 — Python API (embed_url + registry + close + CORS)
|
|
|
|
### Task 1L1 — Mở rộng `open_fx_gui` + thêm `fx-gui/close`
|
|
- Máy: `[L]` · File: `app/api/v1/plugins.py`
|
|
- Nội dung:
|
|
- Spawn bridge với `--fx-gui` (thay/giữ `--open-fx-gui`), đọc port từ stdout
|
|
(`SF_FXGUI_PORT=`) với timeout → trả `{ success, embed_url: "http://127.0.0.1:<port>", already_running }`.
|
|
- Giữ registry `_FX_GUI_PROCESSES` + `_sf_plugin_path` chống mở trùng.
|
|
- Thêm `POST /fx-gui/close` `{path}` → tìm process theo `_sf_plugin_path` → terminate.
|
|
- CORS: đảm bảo `Access-Control-Allow-Origin` cho origin app (port động) — kiểm tra
|
|
middleware hiện có trong `plugins.py`, thêm nếu thiếu.
|
|
- Lệnh kiểm tra: `python3 -m pytest tests/test_plugin_api.py -q` → PASS (thêm unit
|
|
test: mock `subprocess.Popen` → assert spawn args, embed_url parse, close kill,
|
|
registry prune).
|
|
- Deliverable: API mới + unit test.
|
|
- Phụ thuộc: 0L1 (chỉ cần biết contract stdout port; có thể làm song song 0W).
|
|
|
|
### Task 1W1 — Test API thật trên Windows
|
|
- Máy: `[W]` · Điều kiện: chạy app (backend FastAPI) + bridge đã build (0W1).
|
|
- Lệnh:
|
|
1. `curl -X POST http://127.0.0.1:<app>/api/v1/plugins/fx-gui/open -H "Authorization: Bearer <token>" -H "Content-Type: application/json" -d '{"path":"C:\\VST\\Ozone11.vst3","name":"Ozone 11"}'` → `embed_url`.
|
|
2. `curl http://<embed_url>/frame` → 200 JPEG.
|
|
3. `curl -X POST .../fx-gui/close -d '{"path":"C:\\VST\\Ozone11.vst3"}'` → process chết (Task Manager / `Get-Process`).
|
|
- Deliverable: API chạy thật, embed_url truy cập được, close sạch.
|
|
- Phụ thuộc: 1L1, 0W1.
|
|
|
|
---
|
|
|
|
## PHASE 2 — MasteringModal: embed GUI trong panel
|
|
|
|
### Task 2L1 — Code embed trong `app/static/js/app.jsx` (MasteringModal + vstRow)
|
|
- Máy: `[L]` · File: `app/static/js/app.jsx`
|
|
- Nội dung (state ở component panel, truyền qua props như đã làm với `showCarla`):
|
|
- State per-slot `guiOpen: { url } | null` (MasteringModal).
|
|
- Nút GUI → toggle: mở → gọi API `fx-gui/open` → lưu `embed_url`; đang mở → đóng.
|
|
- Vùng embed: `<img src={url + '/frame'}>` refresh `setInterval` 100ms; overlay
|
|
`onMouseDown/Move/Up` + `onWheel` → `fetch(url + '/input', POST)` tọa độ theo
|
|
bounding rect; `onKeyDown/Up` trên container (chỉ khi panel focus).
|
|
- Swap graph↔GUI: ẩn vùng canvas EQ/imager bằng `hidden` khi GUI mở, hiện khi đóng.
|
|
- Click tên VST trong slot khi GUI đang đóng → mở lại embed (ping trước).
|
|
- Nút X đóng GUI → `POST /close`, clearInterval, trả graph. Xóa slot khi GUI mở
|
|
→ cũng gọi `/close`.
|
|
- `/ping` fail (bridge chết) → trả graph + toast.
|
|
- Lệnh kiểm tra:
|
|
- `node build.mjs` (hoặc `npm run build`) → BUILD OK (syntax JSX).
|
|
- Chạy backend Linux + mở app → verify UI không vỡ (GUI nhúng không test được
|
|
thật vì thiếu bridge — dùng mock nếu cần: server node trả /frame JPEG fake + /input log).
|
|
- Deliverable: MasteringModal nhúng GUI + swap + đóng sạch.
|
|
- Phụ thuộc: 1L1 (contract API).
|
|
|
|
### Task 2W1 — E2E thật MasteringModal
|
|
- Máy: `[W]` · Điều kiện: 2L1 + 0W1 + 1W1 pass.
|
|
- Test tay: mở app → Mastering Panel → thêm Ozone → GUI nhúng hiện TRONG panel
|
|
(thay vùng graph) → click/scroll điều khiển plugin → đóng → graph trả về →
|
|
click tên VST mở lại → Xóa slot khi GUI mở → GUI đóng + slot xóa, không crash.
|
|
- Deliverable: UI mastering hoàn chỉnh.
|
|
- Phụ thuộc: 2L1, 1W1.
|
|
|
|
---
|
|
|
|
## PHASE 3 — FXRackModal: embed GUI trong panel
|
|
|
|
### Task 3L1 — Code embed trong FXRackModal
|
|
- Máy: `[L]` · File: `app/static/js/app.jsx` (FXRackModal — vùng scope/eq canvas)
|
|
- Nội dung: tương tự 2L1 nhưng trong FXRackModal; lưu ý vùng thay thế là
|
|
`scopeCanvasRef`/`eqCurveRef` (đã có fallback Carla ở đây — không đụng).
|
|
- Lệnh kiểm tra: `node build.mjs` → BUILD OK; backend Linux + mở app → UI không vỡ.
|
|
- Deliverable: FXRackModal nhúng GUI + swap + đóng sạch.
|
|
- Phụ thuộc: 2L1 (tái dùng pattern), 1L1.
|
|
|
|
### Task 3W1 — E2E thật FXRackModal
|
|
- Máy: `[W]` · Điều kiện: 3L1.
|
|
- Test tay: FX Rack Panel → thêm VST FX → GUI nhúng trong panel → điều khiển →
|
|
đóng → graph trả về. Track cũ có module Carla → vẫn hiện fallback "đã bị gỡ" +
|
|
nút gỡ module (không vỡ).
|
|
- Deliverable: UI fx rack hoàn chỉnh.
|
|
- Phụ thuộc: 3L1.
|
|
|
|
---
|
|
|
|
## PHASE 4 — Dọn + commit + regression
|
|
|
|
### Task 4L1 — Dọn code, docs, commit
|
|
- Máy: `[L]`
|
|
- Nội dung:
|
|
- Toast lỗi đầy đủ (mở GUI fail, bridge chết, close fail).
|
|
- `clearInterval` khi unmount/close (tránh leak).
|
|
- Cập nhật `PLAN_MASTERBUS_VST_GUI_EMBED.md` trạng thái HOÀN THÀNH + ghi chú
|
|
giới hạn (FPS ~10-15, Windows-only).
|
|
- `git add -A && git commit` (tin nhắn: `embed native VST GUI in mastering + fx rack`).
|
|
- Lệnh kiểm tra:
|
|
- `node build.mjs` → BUILD OK.
|
|
- `python3 -m pytest tests/ -q` → toàn bộ test hiện có PASS (1 fail pre-existing
|
|
`test_find_bridge_exe_dev` do thiếu binary Linux — ghi chú, không phải regression).
|
|
- Deliverable: commit sạch, docs cập nhật.
|
|
- Phụ thuộc: 2L1, 3L1 (code ổn).
|
|
|
|
### Task 4W1 — Regression full trên Windows
|
|
- Máy: `[W]` · Điều kiện: 4L1 (pull code mới).
|
|
- Test tay toàn bộ: Mastering + FX Rack GUI nhúng; render offline (`--render-fx`)
|
|
không vỡ; Carla (MasteringModal) vẫn chạy; preset upload; scan plugin.
|
|
- Deliverable: bản Windows sẵn sàng dùng.
|
|
- Phụ thuộc: 4L1.
|
|
|
|
---
|
|
|
|
## Thứ tự thực hiện tối ưu
|
|
|
|
```
|
|
Linux: 0L1 → 0L2 ──→ 1L1 ──→ 2L1 ──→ 3L1 ──→ 4L1 (commit)
|
|
Windows: 0W1 → 0W2 ──→ 1W1 ──→ 2W1 ──→ 3W1 ──→ 4W1
|
|
(pull code sau 0L2) (pull sau 2L1) ...
|
|
```
|
|
|
|
Song song được: 1L1 (contract stdout) với 0W1/0W2; 2L1/3L1 với 0W/1W.
|
|
Chặn: mọi task Windows cần pull code từ Linux trước.
|