# WALKTHROUGH WINDOWS — Nhúng native VST GUI (phần Windows) Máy Windows thực hiện nốt phần còn lại theo `TASKS_LINUX_WINDOWS.md` (tasks 0W1, 0W2, 1W1, 2W1, 3W1, 4W1). Code Linux đã commit và push — **pull code mới về trước**: ```powershell git pull origin standalone-shm-bridge git submodule update --init --recursive -- native_bridge/vst3sdk ``` Điều kiện máy: VS Build Tools 2019+, CMake, git, git-lfs (nếu vst3sdk dùng). --- ## 0W1 — Build bridge ```powershell powershell -ExecutionPolicy Bypass -File build/scripts/build_native_bridge.ps1 ``` Lưu ý thay đổi mới trong phần này (so với lần build cũ): - `native_bridge/vcpkg.json` **thêm `libjpeg-turbo`** — vcpkg manifest tự cài, không cần làm gì thêm, nhưng lần build đầu sẽ tải thêm package này. - `native_bridge/CMakeLists.txt`: thêm `src/FxGuiServer.cpp` vào target `daw_vst_bridge` (chỉ khi WIN32) + `find_package(JPEG REQUIRED)` + link `JPEG::JPEG`. Nếu script build cũ không chạy `cmake -S native_bridge` mà dùng đường dẫn cố định, hãy đảm bảo nó re-configure (xóa `native_bridge/build` nếu cần). - Script phải copy `daw_vst_bridge.exe` + DLL (fluidsynth, jpeg) sang `src-tauri\binaries\` (chỉ các DLL cần thiết; libjpeg-turbo thường static theo manifest, nếu build động thì copy luôn `jpeg62.dll`). **PASS khi**: `native_bridge\build\Release\daw_vst_bridge.exe` tồn tại và `daw_vst_bridge.exe --help` không crash. --- ## 0W2 — Self-check bridge `--fx-gui` (chưa cần app) 1. Tạo `job.json` cạnh exe: ```json {"path": "C:\\VST\\Ozone11.vst3", "name": "Ozone 11"} ``` (đổi path sang plugin VST3 bất kỳ đã cài trên máy Windows). 2. Chạy (giữ terminal mở): ```powershell native_bridge\build\Release\daw_vst_bridge.exe --fx-gui job.json ``` - stdout in dòng `SF_FXGUI_PORT=` → ghi lại port. - **Không có cửa sổ plugin hiện ra** — window bị đặt off-screen (-20000,-20000) để capture; điều khiển qua HTTP, đây là thiết kế. 3. Kiểm tra từ terminal khác: ```powershell curl http://127.0.0.1:/ping curl -o frame.jpg http://127.0.0.1:/frame curl -X POST http://127.0.0.1:/input -H "Content-Type: application/json" -d '{"type":"mousemove","x":100,"y":100,"button":0}' curl -X POST http://127.0.0.1:/input -H "Content-Type: application/json" -d '{"type":"mousedown","x":100,"y":100,"button":0}' curl -X POST http://127.0.0.1:/input -H "Content-Type: application/json" -d '{"type":"mouseup","x":100,"y":100,"button":0}' curl -X POST http://127.0.0.1:/input -H "Content-Type: application/json" -d '{"type":"wheel","x":100,"y":100,"deltaY":120}' curl -X POST http://127.0.0.1:/close ``` - `/frame` → JPEG (mở `frame.jpg` xem GUI plugin hiển thị đúng, không đen). - `/input` → click trúng nút trong GUI (plugin đổi trạng thái — để biết được, hãy mở song song GUI plugin bằng app cũ hoặc quan sát frame.jpg trước/sau click). - `/close` → tiến trình thoát exit 0. **PASS khi**: frame không đen, input điều khiển được, close sạch. > Nếu `/frame` ra ảnh đen dù GUI thật hiển thị: bridge đã tự fallback > `PrintWindow PW_RENDERFULLCONTENT` khi `BitBlt` đen; plugin layered/DirectX > (hiếm) có thể cần xử lý thêm — ghi lại plugin nào bị để theo dõi. --- ## 1W1 — Test API thật (backend FastAPI chạy trên Windows) Chạy app như bình thường (backend + frontend). Frontend gọi: - `POST /api/v1/plugins/fx-gui` `{path, name, embed: true}` → trả `{success, started, already_running, embed_url, cmd}`. - `POST /api/v1/plugins/fx-gui/close` `{path}` → trả `{success, closed}`. Cách test nhanh bằng curl (cần token — lấy từ app sau khi login, hoặc dùng UI thay vì curl; endpoint yêu cầu `Authorization: Bearer `): ```powershell curl -X POST http://127.0.0.1:8000/api/v1/plugins/fx-gui -H "Authorization: Bearer " -H "Content-Type: application/json" -d '{"path":"C:\\VST\\Ozone11.vst3","name":"Ozone 11","embed":true}' curl http:///frame -o frame.jpg curl -X POST http://127.0.0.1:8000/api/v1/plugins/fx-gui/close -H "Authorization: Bearer " -H "Content-Type: application/json" -d '{"path":"C:\\VST\\Ozone11.vst3"}' ``` - `embed:true` (mặc định `false` → cửa sổ rời kiểu cũ, giữ nguyên). - Port backend có thể khác 8000 — xem log app. - CORS đã mở `*` + bridge tự trả `Access-Control-Allow-Origin: *` → browser LAN gọi thẳng `embed_url` được. **PASS khi**: open trả `embed_url` truy cập được `/frame`; close làm process chết (`Get-Process daw_vst_bridge` không còn). --- ## 2W1 — E2E MasteringModal 1. Mở app → **Mastering Panel**. 2. Thêm VST (Ozone) vào master chain → **bấm nút GUI** trên slot. 3. Kỳ vọng: GUI plugin hiện **TRONG panel** (thay vùng graph EQ/imager), header hiện "VST GUI — nhúng (frame-capture · ~10fps)". 4. Click/scroll/kéo trong vùng GUI → plugin phản hồi (thay preset, xoay nút). 5. Bấm "✕ Đóng GUI" → về graph; bấm nút GUI lại → mở lại. 6. Xóa slot khi GUI đang mở → GUI đóng + slot xóa, không crash. 7. Tắt bridge thủ công (Task Manager kill `daw_vst_bridge`) → sau ~2s panel toast "Bridge VST GUI đã mất kết nối" và tự trả về graph. **PASS khi**: toàn bộ thao tác trên ổn định. --- ## 3W1 — E2E FXRackModal 1. Mở app → **FX Rack Panel** (track bất kỳ). 2. Thêm VST FX vào insert chain → bấm nút GUI → GUI nhúng trong panel (thay vùng WORKSPACE CONTROLS + WAVE OBSERVER). 3. Điều khiển → đóng → graph trả về. 4. Track cũ có module **Carla** → vẫn hiện fallback "Carla Bridge đã bị gỡ khỏi FX Rack" + nút gỡ module (không vỡ). **PASS khi**: ổn định như 2W1. --- ## 4W1 — Regression full Test tay toàn bộ: - Mastering + FX Rack GUI nhúng (2W1/3W1). - Render offline (`--render-fx`) không vỡ — export WAV có FX. - Carla (MasteringModal) vẫn chạy. - Preset upload, scan plugin vẫn OK. **PASS khi**: không có regression so với trước embed. --- ## Ghi chú chung - Frame capture ~10fps (img refresh 100ms) — đủ chỉnh thông số, không phải realtime video. - Feature chỉ chạy Windows desktop (có VST GUI); Linux giữ bridge SF2/SFZ. - Nếu sửa gì trên Windows: sửa ngược lên Linux repo (app.jsx là source, `app.precompiled.js` là bản build — đừng sửa tay). - Lỗi thường gặp: - `--fx-gui` không in port → check job.json path đúng VST3, bridge build có `libjpeg-turbo` (thiếu JPEG → lỗi link). - `/frame` đen → plugin layered window; ghi plugin + thử fallback đã có. - App không mở GUI → xem log backend: thiếu `embed` trong payload hoặc `find_bridge_exe` không thấy exe trong `install/` (cần copy exe + DLL vào `src-tauri\binaries\` và app dùng đúng thư mục đó).