dc331f39d8
- config.py: SF_RENDER_ENGINE default 'bridge' (pedalboard GPL-3.0 đã gỡ)
- requirements.txt: bỏ pedalboard==0.9.19
- vst_engine.py: bỏ HAS_PEDALBOARD/check_pedalboard_safe/load_vst/import pedalboard;
midi_events_to_messages giữ làm utility thuần (không gate pedalboard)
- render_engine.py: bỏ nhánh elif vst and HAS_PEDALBOARD + import thừa
- plugins.py: preview/midi-render chỉ qua native_bridge; guard SF_RENDER_ENGINE=bridge
- runtime.py: _vst_render_available() check bridge exe (SF_BRIDGE_PATH/install/) thay find_spec('pedalboard')
- LICENSE.md/THIRD_PARTY_LICENSES.md: bỏ cảnh báo GPL-3.0 pedalboard, đánh số lại
- tests: bỏ test golden so pedalboard + test requires_pedalboard; 114 passed 0 skip
146 lines
7.9 KiB
Markdown
146 lines
7.9 KiB
Markdown
# PLAN: thay pedalboard (GPL-3.0) bằng native_bridge — render VSTi offline
|
|
|
|
Ngày: 2026-08-15
|
|
Trạng thái: HOÀN THÀNH — Phase 0-4 xong; Phase 5 xong (RENDER_ENGINE mặc định bridge; gỡ pedalboard khỏi requirements.txt + source (vst_engine/render_engine/plugins/runtime); midi_events_to_messages giữ làm utility thuần; LICENSE.md + THIRD_PARTY_LICENSES.md bỏ cảnh báo GPL-3.0; tests 114 pass, 0 skip). Docker image build chưa test được (máy không có docker) — recipe verify qua WSL.
|
|
|
|
## 1. Mục tiêu
|
|
Xóa dependency GPL-3.0 (`pedalboard`) khỏi cả 2 môi trường, chuyển toàn bộ
|
|
render VSTi offline (preview quick_render, /midi-render, export session) sang
|
|
host `native_bridge` (MIT) — GIỮ NGUYÊN luồng nghiệp vụ + play âm thanh:
|
|
|
|
- Docker: client play = FluidSynthWASM (không đổi); server preview/export =
|
|
native_bridge Linux (thay pedalboard).
|
|
- Standalone: realtime play = Tauri + bridge SHM (không đổi); Python sidecar
|
|
preview/export = native_bridge Windows (thay pedalboard).
|
|
|
|
Realtime play KHÔNG dùng pedalboard hôm nay → không bị đụng.
|
|
|
|
## 2. Hiện trạng dùng pedalboard (cần thay)
|
|
| Chỗ | Chức năng | Đường |
|
|
|---|---|---|
|
|
| `app/api/v1/plugins.py:878-953` `_render_midi_notes_pedalboard` | preview quick_render + /midi-render: MIDI clip → WAV | `VST3Plugin(midi_messages, duration)` |
|
|
| `app/core/render_engine.py:215-271` | export session track VSTi | `vst(midi_messages, duration)` + `apply_preset_to_plugin` |
|
|
| `app/core/render_engine.py:383-404` | track FX chorus/reverb | `Pedalboard([Chorus/Reverb])` — đã có fallback scipy |
|
|
| `app/core/vst_engine.py:516+` DecentSamplerManager | Pianobook .dspreset | `create_decent_sampler_instance` |
|
|
| `app/core/vst_engine.py:482-503` `midi_events_to_messages` | note events → raw MIDI bytes | dùng `pedalboard.midi_utils` (chỉ format bytes — bridge đã hiểu 0x90/0x80/0xB0/0xC0) |
|
|
| `engine.spec:92-97` | bundle pedalboard vào desktop | PyInstaller |
|
|
|
|
`app/core/runtime.py:377` — feature flag `preview_mode=quick_render` dựa trên
|
|
`find_spec("pedalboard")`.
|
|
|
|
## 3. Kiến trúc đích
|
|
|
|
### 3.1. Bridge thêm offline render mode (C++, `daw_vst_bridge`)
|
|
Mode realtime (SHM, Tauri) GIỮ NGUYÊN. Thêm entrypoint CLI:
|
|
|
|
```
|
|
daw_vst_bridge(.exe) --render <job.json> --out <clip.wav>
|
|
```
|
|
|
|
job.json: `{ instrument_type, plugin_path, preset (path|base64), sample_rate,
|
|
block_size, notes: [{pitch, velocity, start_beat, duration_beats}], bpm,
|
|
soundfont_bank/program (SF2/SFZ) }`
|
|
|
|
Luồng:
|
|
1. Parse job → tạo instrument qua `NativeInstrumentEngine::create_instrument`
|
|
(VST3 / SF2 / SFZ — không phụ thuộc GUI).
|
|
2. Preset: `.vstpreset` → giải mã base64 state blob → `loadSerializedState`
|
|
(state container VST3 chuẩn, cùng cơ chế `serializeState` đã có).
|
|
3. MIDI: chuyển note events → `noteOn/noteOff/controlChange/programChange`
|
|
với `sampleOffset` (đã hỗ trợ) — offline, không realtime.
|
|
4. Loop `processAudioBlock` hết duration → gom buffer → ghi WAV (thêm
|
|
WAV writer đơn giản, stdlib).
|
|
5. Exit 0/1 + log lỗi rõ (thay cho fail im lặng hiện tại).
|
|
|
|
### 3.2. Python client (mới, MIT)
|
|
`app/core/native_render.py` — spawn bridge `--render`, trả `(out_path, duration)`.
|
|
API giống `_render_midi_notes_pedalboard` để 2 endpoint + render_engine thay
|
|
thế trực tiếp. Không import pedalboard. Plugin path resolve bằng logic scan
|
|
có sẵn (`vst_engine.py`).
|
|
|
|
### 3.3. Chorus/Reverb (FX track)
|
|
Chuyển hẳn sang fallback scipy/numpy ĐÃ CÓ SẴN trong `render_engine.py`
|
|
(LFO delay chorus + noise-IR reverb) — 0 code mới, MIT. Chất lượng thấp hơn
|
|
pedalboard; ghi rõ ở doc, upgrade sau nếu cần (native DSP C++ riêng).
|
|
|
|
### 3.4. DecentSampler (.dspreset)
|
|
`.dspreset` là format riêng, không phải VST3 state. Lộ trình:
|
|
- Test: DS VST3 load state chứa preset (user mở DS GUI → save .vstpreset) →
|
|
đường `loadSerializedState` xử lý được.
|
|
- Nếu không: chặn Pianobook trên nền không có pedalboard + hướng dẫn convert
|
|
.dspreset → .vstpreset. KHÔNG giữ pedalboard vì 1 tính năng phụ.
|
|
|
|
## 4. Các phase
|
|
|
|
### Phase 0 — Offline render mode C++ (Windows + Linux)
|
|
- `native_bridge`: thêm `--render` CLI + job parser + WAV writer + offline
|
|
loop; unit test `native_bridge/tests/` (render 1 note VST3 + 1 SFZ, assert
|
|
WAV non-silent, duration đúng).
|
|
- CMake: đảm bảo build Linux (chạy thử trên máy này).
|
|
- **Kiểm chứng**: `--render` ra WAV đúng pitch/duration với plugin test.
|
|
|
|
### Phase 1 — Preset .vstpreset import
|
|
- Parser base64 state → `loadSerializedState`; test với .vstpreset do Carla/
|
|
pedalboard export sẵn (golden file).
|
|
|
|
### Phase 2 — Python client + thay preview
|
|
- `app/core/native_render.py`; đổi `plugins.py` quick_render + /midi-render
|
|
sang client mới (giữ response shape cũ — UI không đổi).
|
|
- Feature flag `SF_RENDER_ENGINE=bridge|pedalboard` (mặc định `pedalboard`
|
|
trong giai đoạn chuyển; đảo sang `bridge` sau phase 4).
|
|
|
|
### Phase 3 — Export session (render_engine)
|
|
- Track VSTi: `vst(midi_messages)` → `native_render` render từng track.
|
|
- FX: bật hẳn fallback scipy (bỏ nhánh `HAS_PEDALBOARD`).
|
|
- Giữ nguyên kết quả WAV export + mixdown (test so sánh trước/sau).
|
|
|
|
### Phase 4 — DecentSampler + Docker + bundle
|
|
- Dockerfile: build native_bridge Linux (CMake) vào image; chạy `--render`
|
|
dưới Xvfb `:99` (đã có). Không cần GUI plugin editor.
|
|
- `engine.spec`: gỡ `pedalboard`/`pedalboard.midi_utils` khỏi bundle.
|
|
- DecentSampler theo mục 3.4.
|
|
|
|
### Phase 5 — Đảo flag + xóa pedalboard
|
|
- Mặc định `SF_RENDER_ENGINE=bridge`; test toàn diện 2 môi trường.
|
|
- Gỡ `pedalboard` khỏi `requirements.txt`, bỏ nhánh chết, cập nhật
|
|
`LICENSE.md`/`THIRD_PARTY_LICENSES.md` (xóa dòng GPL-3.0 warning).
|
|
- Xóa file thừa (nếu có) + doc.
|
|
|
|
## 5. File thay đổi (dự kiến)
|
|
- Thêm: `native_bridge/src/RenderJob.{h,cpp}` (parse job + offline loop),
|
|
`native_bridge/src/WavWriter.cpp`, `app/core/native_render.py`,
|
|
`native_bridge/tests/test_offline_render.py`.
|
|
- Sửa: `native_bridge/src/main.cpp` (dispatch `--render`),
|
|
`native_bridge/CMakeLists.txt` (Linux build), `app/api/v1/plugins.py`,
|
|
`app/core/render_engine.py`, `app/core/vst_engine.py` (midi converter giữ —
|
|
đã ra bytes thuần, bỏ phụ thuộc pedalboard), `app/core/runtime.py` (flag),
|
|
`Dockerfile`, `engine.spec`, `requirements.txt`, `LICENSE.md`.
|
|
|
|
## 6. Giữ nguyên luồng — điểm kiểm chứng
|
|
| Luồng | Docker | Standalone |
|
|
|---|---|---|
|
|
| Realtime play | FluidSynthWASM — không đổi | Tauri+bridge SHM — không đổi |
|
|
| Preview VSTi | server render WAV → client Audio — cùng shape response | cùng |
|
|
| Export session | cùng pipeline WAV → download | cùng |
|
|
| Soundfont preview | pyfluidsynth — không đổi | pyfluidsynth — không đổi |
|
|
|
|
Mỗi phase: chạy bộ test hiện có (`native_bridge/tests/*`, API smoke) +
|
|
golden WAV so sánh pedalboard vs bridge (RMS/tolerance).
|
|
|
|
## 7. Rủi ro + rollback
|
|
- **VST3 plugin cần GUI mới process được**: headless fail → log rõ, trả 501
|
|
như cũ; không phá luồng.
|
|
- **.vstpreset state khác format nội bộ**: phase 1 spike trước; nếu lệch,
|
|
map params qua `setParamNormalized` (đã có đường controlChange).
|
|
- **DecentSampler**: mục 3.4.
|
|
- **Bridge crash giữa render**: subprocess exit non-zero → HTTPException rõ
|
|
(cải thiện hơn pedalboard fail hiện tại).
|
|
- **Rollback**: `SF_RENDER_ENGINE=pedalboard` đảo ngược tức thì tới hết
|
|
phase 4; pedalboard chỉ bị xóa ở phase 5 sau khi bridge ổn định.
|
|
|
|
## 8. Tiêu chí hoàn thành
|
|
- Không còn `pedalboard` trong requirements/engine.spec/source.
|
|
- Preview + export VSTi 2 môi trường ra WAV đúng (so sánh golden).
|
|
- Realtime play 2 môi trường không đổi (regression pass).
|
|
- `LICENSE.md` bỏ cảnh báo GPL-3.0.
|