Files
SonicForgeStudio/md/RUST_PORT_PLAN.md
T

17 KiB
Raw Blame History

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. ✅ Đã làm (P0): xoá torch + torchvision khỏi bundle → 1.842 MB → 146,6 MB, không cần port. Chỉ cần thêm excludes trong engine.spec; đã kiểm chứng app không import torch (tools/p0_baseline.py, md/BASELINE_P0.md).
  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 — ✅ ĐÃ XONG (2026-10-12)

  • Xác nhận torch/torchvision không dùng (block import torch → scipy.signal + mọi app.core.* import OK) → thêm exclude vào engine.spec (torch/torchvision/torchaudio/triton/sympy/networkx/tqdm/einops/optree/tensorflow/keras/jax). Kết quả: bundle engine 1.841,8 MB / 4.187 file → 146,6 MB / 403 file (−92%), đã thay cả bản ship trong src-tauri/resources/daw_engine.
  • Chốt "hợp đồng API": md/api_contract/openapi.json (86 path / 95 operation / 53 schema) + md/api_contract/ws_protocol.md (WS realtime + worklet).
  • Golden test: tools/golden_conformance.py → md/api_contract/golden/manifest.json, 10 case DSP (zero-crossing, micro-crossfade, peak/RMS waveform, cut/loop, multitrack mixdown, analyze, LUFS/true-peak/mono-side). Tái lập ổn định (--check = 0 mismatch giữa các tiến trình); mixdown hash theo mẫu audio vì header WAV không ổn định.
  • Đo baseline: tools/p0_baseline.py → md/BASELINE_P0.md (cold start 5.700 ms, RSS 68 MB, import app.main 731 ms, mixdown 4 track × 30 s: min 516 ms = 0,017× realtime).

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.