# Fix: VSTi play không smooth / cracking / noise trên standalone (Windows/Tauri) Ngày: 2026-08-16 Phạm vi: Linux review code — ghi nguyên nhân + hướng fix, KHÔNG sửa code. Pull về Windows sửa. ## Triệu chứng Load VSTi instrument và play: âm không smooth, không clear; âm sắc thỉnh thoảng cracking/noise. ## Đường âm hiện tại (đã trace trong code) 1. C++ bridge (`native_bridge/src/main.cpp`) render VST3 vào SHM **1 slot 256 frame** (`main.cpp:759`, `main.cpp:1414` — render xong mới tăng `bridgeWriteIndex`). 2. Rust pump thread poll mỗi ~1ms, **chỉ đọc block mới nhất** (`src-tauri/src/lib.rs:454-469`). 3. Mỗi block phát 1 event `bridge-audio` qua Tauri IPC (`lib.rs:467`, `app/static/js/services/nativeBridgeService.js:50`). 4. JS push vào ring 24 block (`bridgeAudioNode.js:55-65`), drain bằng **ScriptProcessorNode 4096** (`bridgeAudioNode.js:29-53`). ## Nguyên nhân gốc ### 1. SHM single-slot, không phải ring buffer `native_bridge/include/SharedMemoryIPC.h:17-21` — chính code ghi chú: "volatile is NOT a sync primitive. Real impl should use an interlocked/ index-flag pair or a Win32 event (SetEvent) signalled by the writer." C++ ghi đè cùng 1 slot mỗi vòng ~5.3ms (256/48000); Rust pump ngủ 1ms + emit async → **chỉ cần trễ > 1 block period là block bị ghi đè trước khi đọc** → gap. ### 2. Rust pump đọc-latest, không drain delta `src-tauri/src/lib.rs:454-466`: `if idx != last_index` → nếu pump/WebView bị jank (GC, React render, IME), index nhảy 2+ → **chỉ đọc block cuối, các block trước bị bỏ im lặng** → click/gap. ### 3. 1 event/block qua Tauri IPC `lib.rs:467` + `nativeBridgeService.js:50`: ~187 event/s (48000/256), mỗi event serialize Vec → đè main thread WebView → càng jitter, càng drop block. ### 4. Consumer bằng ScriptProcessor chạy trên MAIN THREAD `bridgeAudioNode.js:28-53`: callback trễ → `if (!_chunks.length) return;` → **fill silence → gap**. Overrun: `while (_chunks.length > RING_DEPTH) _chunks.shift()` (`bridgeAudioNode.js:63-64`) → **drop block cũ → click**. Không có pacing theo thời gian — drain "có gì chơi nấy". ### 5. Không có drift compensation C++ pace bằng steady_clock (`main.cpp:1424`), WebAudio chạy theo device clock. Ring 24 block (~139ms) chỉ hấp thụ jitter tạm; lệch nhịp kéo dài → underrun/ overrun định kỳ → cracking "lâu lâu" (đúng triệu chứng). ### Yếu tố VSTi phụ (giải thích "không clear / âm sắc lạ") - **Không latency compensation**: `getLatencySamples` chưa dùng (`native_bridge/src/Vst3Instrument.cpp:816-870`) — VSTi có delay nội bộ (chorus/reverb/lookahead) bị dịch pha → âm bẩn. - **Tempo hardcode 120**: `Vst3Instrument.cpp:357` `processContext.tempo = 120.0`, không update khi play — LFO/arp tempo-sync chạy sai BPM. - **Block 256 + sample-accurate split**: `main.cpp:1400-1413` gọi `processAudioBlock` theo sub-block (vd 100+156) — vài plugin nhạy block-size tạo artifact nhẹ. - `channelQuiet` mute channel khi mở editor (`main.cpp:759` renderAll skip) — cố ý, không phải lỗi. ## Hướng fix (Windows thực hiện) 1. **SHM multi-slot ring (4-16 slot)** cho main bridge — hoặc dùng đúng pattern double-buffer đã có sẵn `SandboxHostIPC` (`SharedMemoryIPC.h:33-39`) cho `daw_vst_bridge` (hiện main path dùng `SharedAudioBufferIPC` single-slot). 2. **Rust pump drain đủ delta**: vòng lặp đọc/phát tất cả block chênh lệch (không chỉ latest), hoặc batch emit mỗi 4-8 block để giảm IPC overhead. 3. **Thay ScriptProcessor bằng AudioWorklet** (chạy trên audio thread, không đè main thread) + ring ≥ 32 block + timestamp. 4. **Drift**: monitor buffer level (ring fill) → resample/throttle nhẹ để giữ ring ổn định, không để cạn/tràn. 5. **Latency compensation**: đọc `processor->getLatencySamples()` sau setupProcessing, trừ vào `projectTimeSamples` / bù offset khi render. 6. **Tempo sync**: push BPM thật qua control queue mỗi lần play (hiện chỉ có TRANSPORT/LOAD — thêm field tempo hoặc event mới), cập nhật `processContext.tempo` + `timeSigNumerator/Denominator`. ## Vị trí file liên quan - `native_bridge/include/SharedMemoryIPC.h` (SHM layout, single-slot) - `native_bridge/src/main.cpp` (audio loop, renderSegment, pacing) - `native_bridge/src/Vst3Instrument.cpp` (processAudioBlock, setupProcessing, processContext) - `src-tauri/src/lib.rs` (audio pump thread, emit bridge-audio) - `app/static/js/services/nativeBridgeService.js` (listener bridge-audio) - `app/static/js/services/bridgeAudioNode.js` (ScriptProcessor sink, ring) ## Ưu tiên P1: #2 + #4 (drop block + drift) — bỏ crackle phần lớn. P2: #3 (AudioWorklet) — hết jank main-thread. P3: #1 (multi-slot ring) — chắc chắn không mất block dù pump trễ. P4: #5/#6 (latency + tempo) — hết "không clear/âm sắc lạ".