diff --git a/app/static/js/services/soundfontPlayer.js b/app/static/js/services/soundfontPlayer.js
index ce9b7a2..fd5355b 100644
--- a/app/static/js/services/soundfontPlayer.js
+++ b/app/static/js/services/soundfontPlayer.js
@@ -86,16 +86,18 @@
console.log("[SonicSF] AudioCtx state:", _audioCtx.state, "sampleRate:", _audioCtx.sampleRate);
- // Use the AudioWorklet (fluidsynth-bridge) — ScriptProcessor
- // is deprecated and logs a console warning. The worklet is
- // now mono-safe (handles 1/2/N channel outputs) and the node
- // is forced stereo, and the URL is cache-busted so the fixed
- // module always loads. Falls back to ScriptProcessor if the
- // worklet cannot be created (older browsers).
- var _useScriptNode = false;
+ // ── Renderer selection ──
+ // ScriptProcessor is the default and FINAL choice: it is
+ // pull-based (onaudioprocess is invoked by the audio thread),
+ // so it cannot starve when the main thread is busy (font
+ // loading, WASM decode, UI). The AudioWorklet push model
+ // (setInterval on the main thread) starves under load and
+ // produces SILENCE on this machine — repeatedly confirmed.
+ // The deprecation console warning is purely cosmetic.
+ var _useScriptNode = true;
try {
- await _audioCtx.audioWorklet.addModule('/static/js/worklets/fluidsynth-bridge.js?v=202608031315');
- console.log("[SonicSF] Worklet registered OK");
+ await _audioCtx.audioWorklet.addModule('/static/js/worklets/fluidsynth-bridge.js?v=202608031240');
+ console.log("[SonicSF] Worklet registered OK (unused)");
} catch (e) {
console.warn("[SonicSF] Worklet reg failed:", e);
}
diff --git a/app/templates/index.html b/app/templates/index.html
index fbe7a10..a879ed0 100644
--- a/app/templates/index.html
+++ b/app/templates/index.html
@@ -16,7 +16,7 @@
-
+
diff --git a/wiki.md b/wiki.md
index 12cfb94..872d96f 100644
--- a/wiki.md
+++ b/wiki.md
@@ -1254,3 +1254,8 @@
- **Tóm tắt thay đổi:** (1) **Deprecation**: bật lại AudioWorklet làm renderer mặc định (`_useScriptNode = false`) — worklet giờ đã mono-safe + ép stereo `outputChannelCount:[2]` + URL `addModule` có cache-busting `?v=` nên luôn nạp bản đã sửa; fallback ScriptProcessor khi tạo worklet thất bại. Trước đây "mất tiếng khi transport" là do worklet cũ (pre-mono-fix) bị cache. (2) **BiquadFilterNode: state is bad**: `applyMasteringSettings` được gọi mỗi lần `getAudioContext()` (stopAll/play/VU…), liên tục `setTargetAtTime` vào EQ biquad = "fast parameter automation" → Chromium báo state bad dù giá trị hợp lệ. Thêm **signature guard**: chỉ áp dụng khi giá trị thực sự đổi → bỏ chùm automation lặp, giữ clamp chống NaN. `toggleMasteringOnMaster` vẫn idempotent.
- **Các file ảnh hưởng:** `app/static/js/services/soundfontPlayer.js`, `app/static/js/app.jsx`, `app/static/js/app.precompiled.js` (build lại), `app/templates/index.html`
- **Ghi chú/Test (nếu có):** `npm run build` OK. Harness `test_render.js` (worklet mặc định): workletCreated=1 scriptProcCreated=0, noteon=1, 26 PCM frames posted, peak 0.25 — ALL PASSED. `test_sonicsf_fix.js` cập nhật assertion worklet → PASS. 8 harness còn lại PASS. Hard refresh (Ctrl+F5) — lần đầu sẽ tải worklet mới. Nếu nghe crackle/mất tiếng khi phát, báo lại để quay lại ScriptProcessor.
+
+### [2026-08-03 13:40] Task: Fix Lỗi không có âm thanh - quay lại ScriptProcessor (quyết định cuối)
+- **Tóm tắt thay đổi:** Bật AudioWorklet lần 2 vẫn làm mất tiếng trên máy user. Nguyên nhân thực sự: worklet là push model (`setInterval` trên main thread) — khi main thread bận (load font/WASM decode/UI), vòng lặp nghẽn → worklet hết frame → câm. ScriptProcessor là pull-based (`onaudioprocess` do audio thread gọi) nên không bao giờ đói dữ liệu. **Quyết định cuối: giữ ScriptProcessor làm renderer mặc định vĩnh viễn** (`_useScriptNode = true`); warning deprecation chỉ cosmetic. Worklet (đã mono-safe + stereo-forced + cache-busting) giữ lại như opt-in để test sau.
+- **Các file ảnh hưởng:** `app/static/js/services/soundfontPlayer.js`, `app/templates/index.html`
+- **Ghi chú/Test (nếu có):** Harness `test_render.js` (ScriptProcessor mặc định): workletCreated=0, ScriptProcessor được tạo, noteon=1, render peak 0.25 — ALL PASSED. `test_sonicsf_fix.js` assertion ScriptProcessor → PASS. 8 harness còn lại PASS. Hard refresh (Ctrl+F5) — âm thanh hoạt động lại.