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).
10 KiB
10 KiB
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.cppchỉ 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 → inSF_FXGUI_PORT=<port>ra stdout (Python đọc). GET /frame→ chụp HWND plugin bằngBitBlt(fallbackPrintWindowPW_RENDERFULLCONTENT) → trảimage/jpegquality ~70.POST /input{type, x, y, button, deltaY, keyCode}→PostMessage/SendMessagetheo tọa độ scale client rect (gửiWM_MOUSEMOVEtrước click).POST /close→ detach view, thoát exit 0.GET /ping→ alive.
- Mode
- Toàn bộ Win32 API → bọc
#ifdef _WIN32hoặ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-onlykhô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_bridgeCHỈ khiWIN32(giữ Linux build không vỡ — Linux hiện buildmain_linux.cpprender-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, copydaw_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 trongsrc-tauri\binaries\. - Test: exe tồn tại, chạy
--helpkhô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:
- Tạo
job.json:{"path": "C:\\VST\\Ozone11.vst3", "name": "Ozone 11"}. native_bridge\build\Release\daw_vst_bridge.exe --fx-gui job.json→ đọc port từ stdout.curl http://127.0.0.1:<port>/ping→ alive.curl -o frame.jpg http://127.0.0.1:<port>/frame→ JPEG, kích thước = kích thước GUI plugin.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).curl -X POST http://127.0.0.1:<port>/close→ process thoát exit 0.
- Tạo
- 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_pathchố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-Origincho origin app (port động) — kiểm tra middleware hiện có trongplugins.py, thêm nếu thiếu.
- Spawn bridge với
- Lệnh kiểm tra:
python3 -m pytest tests/test_plugin_api.py -q→ PASS (thêm unit test: mocksubprocess.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:
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.curl http://<embed_url>/frame→ 200 JPEG.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ưuembed_url; đang mở → đóng. - Vùng embed:
<img src={url + '/frame'}>refreshsetInterval100ms; overlayonMouseDown/Move/Up+onWheel→fetch(url + '/input', POST)tọa độ theo bounding rect;onKeyDown/Uptrên container (chỉ khi panel focus). - Swap graph↔GUI: ẩn vùng canvas EQ/imager bằng
hiddenkhi 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. /pingfail (bridge chết) → trả graph + toast.
- State per-slot
- Lệnh kiểm tra:
node build.mjs(hoặcnpm 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).
clearIntervalkhi unmount/close (tránh leak).- Cập nhật
PLAN_MASTERBUS_VST_GUI_EMBED.mdtrạ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-existingtest_find_bridge_exe_devdo 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.