# Thiết kế: tương thích ngược VSTi cũ (VST2, 32-bit) — bridge âm thanh Ngày: 2026-08-15 Trạng thái: THIẾT KẾ (chưa sửa code sản phẩm). Linux làm thiết kế + spike khả thi; code theo thoả thuận triển khai (Windows). ## 1. Mục tiêu Standalone bridge (`standalone-shm-bridge`) hiện chỉ host VST3. Nhiều VSTi cũ (vintage, freeware, 32-bit) chỉ có bản VST2. Mục tiêu: VST2 64-bit phát được qua bridge chính (headless, realtime), không phá luồng VST3 hiện tại. ## 2. Hiện trạng (đã xác minh trên code) ### VST2 không được implement trong bridge - `native_bridge/src/NativeInstrumentEngine.cpp:166-180` — `create_instrument()`: `case VST2: return nullptr` + comment "ponytail: VST2 host (VST2.4 SDK, Steinberg discontinued) not implemented". - Enum đã có sẵn: `native_bridge/src/INativeInstrument.h:8-12` (VST3=0, VST2=1, SF2/SF3=2, SFZ=3). - `StateStore.h:14` — type 1 = VST2. ### Backend đã nhận diện VST2 (scan + UI) - `app/api/v1/plugins.py:117-130,224-247` — file `.dll` (không phải folder `.vst3`) → `"type":"VST2"`. - `app/vst_engine.py:282-300` — scan `.vst3/.so/.dll`. - JS mapping: `nativeBridgeService.js:7` `INSTRUMENT_TYPE={VST3:0,VST2:1,SF2:2,SF3:2,SFZ:3}`. → Hệ quả: UI liệt kê plugin VST2 là loại hợp lệ, user assign → bridge `create_instrument` trả nullptr → `assign` false → fail **im lặng**, không có lỗi nào hiển thị. Đây là bug UX chính cần sửa kèm. ### Đường khác không thay thế - Carla (Windows) hỗ trợ VST2 nhưng là đường GUI/preset riêng (`plugins.py:530-630` carla-midi/carla-play-notes/open-in-carla), KHÔNG phải đường audio bridge chính. - Preset `.fxp/.fxb` nằm trong `PRESET_EXTENSIONS` (`vst_engine.py:592`) nhưng `apply_preset_to_plugin` gọi `load_preset` của VST3Plugin — không chạy VST2. ### Hạ tầng tái dùng được - `SandboxVst3Host` + `SandboxHostIPC` double-buffer (`SharedMemoryIPC.h:33-39`), `plugin_host_main.cpp`, env `SF_SANDBOX_VST3` — pattern sẵn cho helper process 32-bit. - Build: `native_bridge/vcpkg.json` chỉ fluidsynth+pkgconf; VST3 SDK là git submodule `vst3sdk` (không có vestige — cần thêm header nếu làm VST2 host); CMake `-EHa`. ## 3. Thiết kế đề xuất ### 3.1. VST2 64-bit — host `Vst2Instrument` dùng vestige (làm trước) - **vestige** (`vestige/aeffect.h`, mã nguồn mở, từ dự án LMMS): header-only, tự định nghĩa lại interface + ABI VST2.4 (vtable layout, dispatcher opcode). Không cần Steinberg VST2 SDK (đã discontinued, license không cấp mới) → sạch pháp lý, zero dependency build, không submodule mới. - `Vst2Instrument` implement cùng interface `INativeInstrument`: assign / SHM double-buffer / renderAll tái dùng nguyên trạng. - Phạm vi audio headless: `processReplacing`, `setSampleRate`, `setBlockSize`, `resume`/`suspend`, `getParameter`/`setParameter`, `effGetChunk`/`effSetChunk` (preset .fxp/.fxb), `effGetParamLabel` (tên tham số cho UI). - GUI editor: **defer** (không window, không thread GUI). Nhiều VSTi cổ vẫn phát headless; plugin nào đòi GUI mới ra tiếng thì ghi rõ giới hạn ở UI. - Sửa kèm bug im lặng: khi `create_instrument` trả nullptr → trả lỗi rõ ràng lên UI thay vì fail câm. ### 3.2. VST2 32-bit — helper process (defer, effort cao) - Helper `plugin_host.exe` 32-bit, tái dùng pattern `SandboxVst3Host` + `SandboxHostIPC` double-buffer + env `SF_SANDBOX_VST3`. - Lý do defer: cần bản build 32-bit riêng, xử lý wow64 + marshalling (MIDI/sample rate/block size qua IPC), khó debug. Làm sau khi 64-bit ổn định. ### 3.3. Quirk plugin cũ (khi test thực tế) - Block size: thử 256 / 512 / 1024 (nhiều plugin cũ chỉ nhận bội số cố định). - Sample rate: 44.1 kHz là mặc định an toàn nhất. - Thread affinity: open + process cùng 1 thread; tránh đổi thread giữa `resume` và vòng render. - Plugin 32-bit đòi GUI: một số chỉ phát sau khi editor từng mở — ghi rõ giới hạn, không cố host GUI trong bridge. ### 3.4. Giới hạn docker/server - `pedalboard` không hỗ trợ VST2 → pipeline VSTi→SF2 (`DESIGN_DOCKER_VSTI_PLAY.md`) chỉ nhận VST3. VST2 không render được asset SF2 trên server. Ghi rõ ở UI. ## 4. Kiến trúc thêm mới (tối thiểu) ``` native_bridge/ vestige/aeffect.h # header mã nguồn mở (thêm file) src/Vst2Instrument.h/.cpp # host VST2, implement INativeInstrument src/NativeInstrumentEngine.cpp # case VST2 -> new Vst2Instrument ``` Không đổi ABI, không đổi `SharedMemoryIPC`, không đổi JS service layer. ## 5. Rủi ro / giới hạn - Vài plugin rất cổ đòi host callback lạ (`effGetPlugCategory`, vendor opcode) → patch nhỏ riêng từng plugin. - Vestige không cung cấp editor GUI → plugin phụ thuộc GUI sẽ câm. - ABI VST2 ổn định từ 1999 → 64-bit .dll hiện đại + cổ đều theo, rủi ro thấp. ## 6. Thứ tự triển khai 1. `Vst2Instrument` + vestige: load, assign, render thử 1 plugin VST2 64-bit. 2. Sửa bug fail im lặng khi không host được. 3. Preset .fxp/.fxb qua `effSetChunk`/param. 4. Test block size / sample rate / thread affinity với plugin cổ. 5. (Defer) 32-bit helper process.