fix(fx-rt): burst 4-block input batch qua bridge — hết lag/giật/crackle master FX

- worklet gom 1024 mẫu (4 block) vào 1 frame interleaved, main thread tách 4 WS frame 512 floats
- bridge take=min(avail,4) xử lí 1 call process cho burst → overhead VST3 amortize 4 lần
- engine _pump_output pace theo deadline thay vì sleep cố định (outRead 131→187.5/s)
- FX_RT_ROUNDTRIP_SAMPLES 512→1792 (RTT batching ~7 block)
This commit is contained in:
2026-08-23 11:44:54 +07:00
parent bec82a20bc
commit 0acc3ee7ee
7 changed files with 108 additions and 52 deletions
+11 -2
View File
@@ -1071,6 +1071,7 @@ async def ws_fx_realtime(websocket: WebSocket, session_id: str):
# de bu delay dry-bypass path (app.jsx fxRtApplyPdc).
_last_lat = None
try:
_loop = asyncio.get_event_loop()
while True:
try:
_lats = sess.get_latencies()
@@ -1088,9 +1089,17 @@ async def ws_fx_realtime(websocket: WebSocket, session_id: str):
if not blks:
await asyncio.sleep(0.002)
continue
for blk in blks:
# Pace theo deadline (không sleep cố định sau mỗi send): thời
# gian send_bytes (WS → browser) CỘNG sleep cố định làm chu kì
# mỗi block > block_sec → engine drain chậm hơn realtime
# (đo: outRead 131/s thay vì 187.5/s → worklet zero-fill crackle).
# Gửi mỗi block cách nhau đúng block_sec kể từ mốc t0.
_t0 = _loop.time()
for _i, blk in enumerate(blks):
await websocket.send_bytes(blk)
await asyncio.sleep(block_sec)
_dt = _t0 + (_i + 1) * block_sec - _loop.time()
if _dt > 0:
await asyncio.sleep(_dt)
except Exception:
pass
pump_task = asyncio.create_task(_pump_output())