From 4ed1de638d387fa71aca3a018a23e03387d6123d Mon Sep 17 00:00:00 2001 From: locphamtran Date: Mon, 31 Aug 2026 18:20:53 +0700 Subject: [PATCH] V45.28: fix wobble preview VST2 loop/tremolo khi nhan chord - ring worklet bridgeAudioWorklet 32->48 block (~256ms) hap thu stall render loop C++ khi chord nhieu voice (stall >170ms -> underrun lap lai fade ve 0 nghe nhu wobble; 16->32 V45.27 da dung crackle, 32 chua du cho chord); overrun crossfade tich luy moi block drop cong 256 mau cap 1024 (~21ms) thay vi co dinh 64 mau (1.3ms qua ngan -> blip/wow khi drop loat block o chord nhieu voice). v=202608311820 --- app/static/js/services/bridgeAudioNode.js | 2 +- app/static/js/services/bridgeAudioWorklet.js | 29 +++++++++++++------- app/templates/index.html | 2 +- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/app/static/js/services/bridgeAudioNode.js b/app/static/js/services/bridgeAudioNode.js index c5a00a0..503f71d 100644 --- a/app/static/js/services/bridgeAudioNode.js +++ b/app/static/js/services/bridgeAudioNode.js @@ -32,7 +32,7 @@ console.warn('[BridgeAudioNode] AudioWorklet unavailable — ScriptProcessor fallback'); return false; } - var url = '/static/js/services/bridgeAudioWorklet.js?v=202608311809'; + var url = '/static/js/services/bridgeAudioWorklet.js?v=202608311820'; _ctx.audioWorklet.addModule(url).then(function () { if (!_initialized) return; // disconnect() happened while loading if (_useWorklet) return; // already set up (init retry) diff --git a/app/static/js/services/bridgeAudioWorklet.js b/app/static/js/services/bridgeAudioWorklet.js index 7f33b09..4e22d34 100644 --- a/app/static/js/services/bridgeAudioWorklet.js +++ b/app/static/js/services/bridgeAudioWorklet.js @@ -1,24 +1,28 @@ // app/static/js/services/bridgeAudioWorklet.js // VSTi crackle fix: audio sink chay tren audio thread (khong jank main thread). -// - Ring block 256 mau, toi da 32 block (~170ms @48k) — hap thu jitter pump -// (V45.27: 16->32 de dung crackle VST2 loop/tremolo — render loop C++ bi -// stall khi instrument xu li loop/tremolo nang CPU; 8->16 truoc do da dung -// tremolo crackle, 16 van chua du cho stall >85ms). Flush o play start -// (app.jsx) xoa ring nen do tre khong tang: ring thuong can o preview. +// - Ring block 256 mau, toi da 48 block (~256ms @48k) — hap thu jitter pump +// (V45.28: 32->48 de dung wobble VST2 loop/tremolo khi nhan chord — chord +// nhieu voice -> render loop C++ stall dai hon ~170ms -> underrun lap lai +// (fade ve 0) nghe nhu wobble; 8->16 (V45) dung tremolo crackle, 16->32 +// (V45.27) dung crackle, 32 van chua du cho stall chord). Flush o play +// start (app.jsx) xoa ring nen do tre khong tang: ring thuong can o preview. // - Underrun: fade ve 0 thay vi click (hard silence). // - Resume sau silence: fade vao tu 0. -// - Overrun: drop block cu nhat + crossfade 64 mau tai diem drop (het click). +// - Overrun: drop block cu nhat + crossfade tich luy — moi block drop cong +// 256 mau fade, cap 1024 (~21ms) — crossfade dai de tranh blip/wow khi +// chord nhieu voice bi drop loat block (64 mau = 1.3ms qua ngan). // - Stats: dem overrun/underrun, gui ve main thread moi ~0.5s — kiem tra // con crackle nao la do ring can (underrun) hay ring tran (overrun). class BridgeAudioSinkProcessor extends AudioWorkletProcessor { constructor() { super(); this._ring = []; - this._MAX = 32; + this._MAX = 48; this._gain = 1.0; this._lastOutL = 0.0; this._lastOutR = 0.0; - this._skipFade = 0; // >0: crossfade dang chay sau overrun drop + this._skipFade = 0; // >0: con lai cua crossfade dang chay sau overrun drop + this._fadeLen = 0; // tong chieu dai crossfade hien tai (cap 1024) this._skipFromL = 0.0; this._skipFromR = 0.0; this._wasUnderrun = false; @@ -31,14 +35,18 @@ class BridgeAudioSinkProcessor extends AudioWorkletProcessor { this._ring.push({ l: m.l, r: m.r }); while (this._ring.length > this._MAX) { // overrun: bo block cu nhat; lan consume toi se crossfade ranh gioi + // (tich luy: moi block drop cong 256 mau fade, cap 1024 — crossfade + // dai hon de tranh blip/wow khi drop loat block o chord nhieu voice) this._ring.shift(); - this._skipFade = 64; + this._skipFade = Math.min(this._skipFade + 256, 1024); + this._fadeLen = this._skipFade; this._stats.overruns++; } } else if (m.type === 'flush') { this._ring.length = 0; this._gain = 1.0; this._skipFade = 0; + this._fadeLen = 0; } }; } @@ -56,8 +64,9 @@ class BridgeAudioSinkProcessor extends AudioWorkletProcessor { const avail = blk.l.length; const take = Math.min(avail, n - w); if (this._skipFade > 0) { + const done = this._fadeLen - this._skipFade; for (let i = 0; i < take; i++) { - const t = i / 64; + const t = (done + i) / this._fadeLen; L[w + i] = (this._lastOutL * (1 - t) + blk.l[i] * t) * this._gain; R[w + i] = (this._lastOutR * (1 - t) + blk.r[i] * t) * this._gain; } diff --git a/app/templates/index.html b/app/templates/index.html index c18155b..8d3cc38 100644 --- a/app/templates/index.html +++ b/app/templates/index.html @@ -40,7 +40,7 @@ - +