17 KiB
Kế hoạch: Port SonicForgeStudio / ScoreFXStudio sang Rust
Ngày: 2026-09-07 · Phạm vi:
C:/Users/locpham/SonicForgeStudio(branchmain, HEAD19c1e03) 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 đệmFILL = 40 block = 10.240 mẫu ≈ **213 ms @48k**và bù bằngpdcDelay+ đồ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/masterFxDryGaincrossfade +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+torchvisioncó 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)
- Xoá
torch+torchvisionkhỏ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.specvà kiểm tra lại bằng test suite. - Vá
app/static/js/app.jsx37k dòng bằng bundler thật (esbuild/vite) thay vì Babel 1-file →app.precompiled.jsnhỏ hơn, build nhanh hơn, có source map. - Tách
app.jsxthà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. - 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/torchvisionkhô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.speckhô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.jstrỏ 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_enginescan → Rust + FFI.
P4 — Realtime control path bridge (3-5 tuần) ← tối ưu rẻ, hiệu quả cao
- Thay WS
fx-realtime+plugins.pyrelay 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.jsxthành module trước; đo lại. - Cân nhắc
egui/icedhoặ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.