Merge remote-tracking branch 'origin/standalone-shm-bridge' into standalone-shm-bridge

This commit is contained in:
2026-08-16 21:27:50 +07:00
4 changed files with 387 additions and 5 deletions
+102
View File
@@ -0,0 +1,102 @@
# 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.
+102
View File
@@ -0,0 +1,102 @@
# LICENSE — SonicForgeStudio
## 1. Mã nguồn dự án
MIT License
Copyright (c) 2026 SonicForge Studio contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
File văn bản MIT đầy đủ: `LICENSE`.
## 2. Thành phần bên thứ ba
Kiểm tra ngày 2026-08-15 (verify từ PyPI/GitHub/wheel). Các thành phần giữ
license gốc; chi tiết + attribution: `THIRD_PARTY_LICENSES.md`.
### 2.1. npm (`package.json`)
| Thành phần | License |
|---|---|
| react / react-dom 19.x | MIT |
| @babel/cli, @babel/core, @babel/preset-react | MIT |
| jsdom | MIT |
| @tauri-apps/cli 2.x (desktop shell) | Apache-2.0 OR MIT |
### 2.2. Python (`requirements.txt`)
| Thành phần | License |
|---|---|
| fastapi | MIT |
| uvicorn | BSD-3-Clause |
| celery | BSD-3-Clause |
| redis | MIT |
| python-multipart | Apache-2.0 |
| librosa | ISC |
| pydub | MIT |
| numpy | BSD-3-Clause (kèm code nhúng: 0BSD, MIT, Zlib, CC0-1.0) |
| scipy | BSD-3-Clause (kèm OpenBLAS BSD-3, GCC runtime GPL-3.0-with-exception) |
| soundfile | BSD-3-Clause |
| jinja2 | BSD-3-Clause |
| httpx | BSD-3-Clause |
| jsonschema | MIT |
| mido | MIT |
| pyfluidsynth | MIT (wrapper — link FluidSynth **LGPL-2.1+**) |
| sf2utils 1.0.0 | **LGPL-3.0+** (LICENSE.txt trong wheel; metadata PyPI ghi nhầm "GPLv3+") |
| pedalboard 0.9.19 | **GPL-3.0** ⚠️ — xem mục 3 |
### 2.3. Native bridge (`native_bridge/`, C++)
| Thành phần | License |
|---|---|
| fluidsynth (vcpkg) | LGPL-2.1+ |
| vst3sdk (git submodule, `native_bridge/vst3sdk`) | MIT (© 2026 Steinberg Media Technologies GmbH) |
| vestige (dự kiến thêm khi implement VST2, xem `DESIGN_VST2_BACKWARD_COMPAT.md`) | header mã nguồn mở — xác nhận lại file license gốc khi thêm vào repo |
### 2.4. Nhúng (`app/static`)
| Thành phần | License |
|---|---|
| `css/tailwind.min.css` | MIT |
| Lucide icons | ISC |
| `js/vendor/libfluidsynth-2.3.0-sf3.js` + `.wasm` (FluidSynth Emscripten) | **LGPL-2.1+** |
| `js/services/spessasynth_processor.min.js` | MIT — file chết, không include trong `index.html` |
### 2.5. Nội dung âm thanh (`app/storage`)
| Thành phần | License | Trạng thái |
|---|---|---|
| "General MIDI SoundFont v3.0" — © 2006-2010 Rich "Weeds" Nagel | "Some rights reserved" (không rõ điều kiện) | ⚠️ cần attribution hoặc thay SF2 license rõ |
| SGM-V2.01 | Freeware — hạn chế redistribution | ⚠️ không nhúng vào bản phân phối |
## 3. Lưu ý pháp lý khi phân phối
1. **pedalboard (GPL-3.0)** — dùng runtime ở server (`app/core/render_engine.py`,
`app/core/vst_engine.py`, `app/api/v1/plugins.py`) cho render VST3.
GPL-3.0 copyleft → phân phối bản server gộp pedalboard có thể kéo toàn bộ
phần combined theo GPL. Cần: tách pedalboard ra subprocess/plugin riêng
(không import trong process MIT chính) hoặc thay thế bằng host khác.
2. **sf2utils (LGPL-3.0+)** — dùng runtime (`app/core/soundfont_inspector.py`).
LGPL cho phép app MIT dùng nếu giữ notice + (khi phân phối binary) cung cấp
khả năng relink/object tương ứng.
3. **FluidSynth (LGPL-2.1+)** — vừa nhúng Emscripten (`app/static`) vừa link
tĩnh qua vcpkg (`native_bridge`). Bắt buộc: giữ license notice, cung cấp
link/object relinkable khi phân phối bản build.
4. **vst3sdk (MIT)** — tương thích hoàn toàn với dự án MIT.
5. **VST2 SDK của Steinberg** — discontinued, license không cấp mới → hướng
dùng **vestige** (header mã nguồn mở) theo `DESIGN_VST2_BACKWARD_COMPAT.md`,
không nhúng VST2 SDK chính hãng.
6. **SoundFont** — SGM-V2.01 không đưa vào bản phân phối; SF2 Rich Nagel cần
attribution hoặc thay thế.
+146
View File
@@ -0,0 +1,146 @@
# PLAN: thay pedalboard (GPL-3.0) bằng native_bridge — render VSTi offline
Ngày: 2026-08-15
Trạng thái: KẾ HOẠCH (chưa sửa code sản phẩm). Windows sửa code bridge/desktop;
Linux làm bridge Linux + Docker + test so sánh.
## 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.
+37 -5
View File
@@ -1,6 +1,7 @@
# THIRD-PARTY LICENSES — SonicForgeStudio
Kiểm tra ngày 2026-08-07. Danh sách thành phần bên thứ ba + license.
Kiểm tra ngày 2026-08-15 (verify từ PyPI/GitHub/LICENSE.txt trong wheel).
Danh sách thành phần bên thứ ba + license. Bản tổng hợp: `LICENSE.md`.
## 1. Dependencies (npm — package.json)
| Thành phần | License | Ghi chú |
@@ -8,6 +9,35 @@ Kiểm tra ngày 2026-08-07. Danh sách thành phần bên thứ ba + license.
| react / react-dom 19.x | MIT | OK |
| @babel/cli, @babel/core, @babel/preset-react | MIT | Chỉ build-time |
| jsdom | MIT | Chỉ build-time/test |
| @tauri-apps/cli 2.x | Apache-2.0 OR MIT | Desktop shell (src-tauri) — build-time |
## 1b. Dependencies (Python — requirements.txt)
| Thành phần | License | Ghi chú |
|---|---|---|
| fastapi | MIT | OK |
| uvicorn | BSD-3-Clause | OK |
| celery | BSD-3-Clause | OK |
| redis | MIT | OK |
| python-multipart | Apache-2.0 | OK |
| librosa | ISC | OK |
| pydub | MIT | OK |
| numpy | BSD-3-Clause (kèm 0BSD, MIT, Zlib, CC0-1.0) | OK |
| scipy | BSD-3-Clause (kèm OpenBLAS BSD-3, GCC runtime GPL-3.0-with-exception) | OK — exception cho phép dùng |
| soundfile | BSD-3-Clause | OK (libsndfile core là LGPL-2.1+) |
| jinja2 | BSD-3-Clause | OK |
| httpx | BSD-3-Clause | OK |
| jsonschema | MIT | OK |
| mido | MIT | OK |
| pyfluidsynth | MIT (wrapper) | OK — link FluidSynth LGPL-2.1+ |
| sf2utils 1.0.0 | **LGPL-3.0+** | ⚠️ LICENSE.txt trong wheel là LGPLv3 (metadata PyPI ghi nhầm "GPLv3+"). Dùng runtime `soundfont_inspector.py` — giữ notice + relinkable khi phân phối binary |
| pedalboard 0.9.19 | **GPL-3.0** | ⚠️ RỦI RO — dùng runtime render VST3 (render_engine/vst_engine/plugins). Copyleft mạnh → tách subprocess hoặc thay thế trước khi phân phối server |
## 1c. Native bridge (native_bridge/, C++)
| Thành phần | License | Ghi chú |
|---|---|---|
| fluidsynth (vcpkg) | LGPL-2.1+ | Link tĩnh qua vcpkg — bắt buộc notice + relinkable object |
| vst3sdk (git submodule) | MIT | © 2026 Steinberg Media Technologies GmbH — tương thích MIT project |
| vestige (dự kiến cho VST2) | mã nguồn mở | Chưa thêm vào repo — xác nhận license gốc khi implement |
## 2. Thư viện nhúng (app/static)
| File | Nguồn | License | Trạng thái |
@@ -31,7 +61,9 @@ Kiểm tra ngày 2026-08-07. Danh sách thành phần bên thứ ba + license.
## KẾT LUẬN
- **Không phát hiện vi phạm bản quyền rõ ràng** (không có code GPL bị nhúng vào project MIT; LGPL của FluidSynth tương thích nếu giữ notice).
- **3 điểm cần xử lý trước khi phân phối công khai:**
1. Bổ sung `LICENSE` text (MIT + LGPL-2.1) + attribution cho SpessaSynth (MIT notice) và Tailwind.
2. Ghi attribution SF2 Rich Nagel ("General MIDI SoundFont v3.0 — © 2006-2010 Rich 'Weeds' Nagel — Some rights reserved") hoặc thay soundfont khác license rõ.
3. Không nhúng SGM-V2.01 vào bản phân phối (hạn chế redistribution).
- **Cần xử lý trước khi phân phối công khai:**
1. **pedalboard (GPL-3.0)** — dependency runtime server render VST3 → rủi ro copyleft cao nhất. Tách subprocess/plugin hoặc thay thế.
2. **sf2utils (LGPL-3.0+)** — giữ notice + relinkable object khi phân phối binary.
3. Bổ sung `LICENSE` text (MIT + LGPL-2.1) + attribution cho SpessaSynth (MIT notice) và Tailwind.
4. Ghi attribution SF2 Rich Nagel ("General MIDI SoundFont v3.0 — © 2006-2010 Rich 'Weeds' Nagel — Some rights reserved") hoặc thay soundfont khác license rõ.
5. Không nhúng SGM-V2.01 vào bản phân phối (hạn chế redistribution).