fix(fx): realtime VST ngắt quãng khi mở MASTERING PANEL + PWR master không ảnh hưởng âm; pacing WS input/output, gate fxRt theo masterConnected, worklet cap 32

This commit is contained in:
2026-08-21 21:48:56 +07:00
parent 4e3f2fd08a
commit bb6658e03d
17 changed files with 1813 additions and 142 deletions
+14 -8
View File
@@ -9,13 +9,19 @@ router = APIRouter()
# WebView2 standalone chặn anchor-download → không thấy save dialog. Giải pháp:
# frontend gọi /save-dialog → engine mở NATIVE SaveFileDialog (Windows Explorer)
# → trả đường dẫn user chọn → frontend gửi bytes qua /write → ghi file thật.
SAVE_DIALOG_TIMEOUT = 120 # user có thể để dialog mở lâu
SAVE_DIALOG_TIMEOUT = 120 # fallback native (PowerShell) — user có thể để dialog mở lâu
# Bridge timeout phải LỚN HƠN Rust wait (300s trong lib.rs) — nếu không, user
# chọn path sau 300s thì engine đã bỏ cuộc → save_file.response bị bỏ lại, file
# không được ghi dù user đã chọn nơi lưu (bug "hỏi nơi lưu nhưng không có file").
SAVE_BRIDGE_TIMEOUT = 360
def _save_file_via_tauri_bridge(default_name: str) -> Optional[str]:
"""Tauri shell (Rust watcher trong lib.rs) mở NATIVE SaveFileDialog qua
file IPC: engine ghi save_file.request (chứa tên mặc định) → Rust mở dialog
→ ghi save_file.response. Trả None nếu bridge không tồn tại (standalone)."""
→ ghi save_file.response. Trả None nếu bridge không tồn tại (standalone) →
caller fallback native. Trả "" nếu bridge ĐÃ dùng nhưng user hủy / hết hạn →
KHÔNG fallback (tránh 2 dialog cùng lúc + tránh ghi đè path user đã chọn)."""
root = os.environ.get("APPDATA") or os.path.expanduser("~")
ipc = os.path.join(root, "SonicForgeDAW", "ipc")
if not os.path.isdir(ipc):
@@ -35,7 +41,7 @@ def _save_file_via_tauri_bridge(default_name: str) -> Optional[str]:
os.remove(f)
with open(req, "w", encoding="utf-8") as fh:
fh.write(default_name or "untitled")
deadline = _time.time() + SAVE_DIALOG_TIMEOUT
deadline = _time.time() + SAVE_BRIDGE_TIMEOUT
while _time.time() < deadline:
if os.path.exists(resp):
try:
@@ -43,11 +49,11 @@ def _save_file_via_tauri_bridge(default_name: str) -> Optional[str]:
val = fh.read().strip()
finally:
os.remove(resp)
return val or None
return val # "" khi user hủy — KHÔNG fallback PowerShell (tránh 2 dialog)
_time.sleep(0.1)
except Exception:
pass
return None
return ""
return "" # bridge đã dùng nhưng hết hạn — KHÔNG fallback (dialog Rust vẫn có thể đang mở)
def _save_file_native_engine(default_name: str, filter_name: str, filter_ext: str) -> Optional[str]:
@@ -107,9 +113,9 @@ def save_file_dialog(req: SaveDialogRequest):
Trả {"path": "<đường dẫn user chọn>"} hoặc {"path": None} (hủy/không có
dialog). def (sync) → FastAPI chạy threadpool — không block loop."""
path = _save_file_via_tauri_bridge(req.default_name)
if path is None:
if path is None: # không có bridge (standalone thuần) → fallback native
path = _save_file_native_engine(req.default_name, req.filter_name, req.filter_ext)
return {"path": path}
return {"path": path or None}
@router.post("/write")