refactor(bridge): split fx bridge, stabilize VST3 host chain, drop old install engines

- remove diagnostic canaries from audio hot path (crackle fix) and
  stuck C5 note raw-MIDI test (Vst2Instrument::init noteOff)
- split native bridge into daw_vst_bridge (VSTi) + fx_vst_bridge (VST FX)
- VST3: processData prepare before setActive, zero input buses, accept
  both .vstpreset and bridge-state blob in RenderJob presets
- native_render/vst_engine: bridge-exe discovery + render_fx_chain + /fx-gui
- delete old install/ engine binaries (install via sidecar+resources now)
- add BUILD_LAYOUT.md, build_selfcheck, tools/ diagnostics
This commit is contained in:
2026-08-20 09:42:42 +07:00
parent 5df96aef1e
commit 7c22ae1f02
42 changed files with 2363 additions and 210 deletions
+27 -13
View File
@@ -19,33 +19,47 @@ from fastapi import HTTPException
from app.config import settings
BRIDGE_EXE = "daw_vst_bridge.exe" if os.name == "nt" else "daw_vst_bridge"
FX_BRIDGE_EXE = "fx_vst_bridge.exe" if os.name == "nt" else "fx_vst_bridge"
def find_bridge_exe() -> str:
"""Đường dẫn bridge exe: env SF_BRIDGE_PATH → bundle (frozen) → install/ (dev)."""
env = os.getenv("SF_BRIDGE_PATH", "").strip()
def find_bridge_exe(exe_name=BRIDGE_EXE, env_key="SF_BRIDGE_PATH") -> str:
"""Đường dẫn bridge exe: env <env_key> → bundle (frozen) → src-tauri/binaries → install/ (dev)."""
env = os.getenv(env_key, "").strip()
if env and os.path.isfile(env):
return env
# Tauri externalBin renames sidecars → <name>-x86_64-pc-windows-msvc.exe.
sidecar = exe_name[:-4] + "-x86_64-pc-windows-msvc.exe" if exe_name.lower().endswith(".exe") else exe_name
cands = []
if getattr(sys, "frozen", False):
root = getattr(sys, "_MEIPASS", "")
if root:
cands += [os.path.join(root, "binaries", BRIDGE_EXE),
os.path.join(root, BRIDGE_EXE)]
cands += [os.path.join(root, "binaries", exe_name),
os.path.join(root, "binaries", sidecar),
os.path.join(root, exe_name),
os.path.join(root, sidecar)]
# PyInstaller onedir: daw_engine.exe nam <app_root>/daw_engine/, bridge
# sidecar nam canh app root (khong trong _MEIPASS) - tim ca exe_dir.
exe_dir = os.path.dirname(os.path.abspath(sys.executable))
cands += [os.path.join(exe_dir, "binaries", BRIDGE_EXE),
os.path.join(exe_dir, BRIDGE_EXE),
os.path.join(os.path.dirname(exe_dir), "binaries", BRIDGE_EXE),
os.path.join(os.path.dirname(exe_dir), BRIDGE_EXE)]
cands.append(os.path.join(settings.BASE_DIR, "install", BRIDGE_EXE))
cands += [os.path.join(exe_dir, "binaries", exe_name),
os.path.join(exe_dir, "binaries", sidecar),
os.path.join(exe_dir, exe_name),
os.path.join(exe_dir, sidecar),
os.path.join(os.path.dirname(exe_dir), "binaries", exe_name),
os.path.join(os.path.dirname(exe_dir), "binaries", sidecar),
os.path.join(os.path.dirname(exe_dir), exe_name),
os.path.join(os.path.dirname(exe_dir), sidecar)]
# Canonical build output (build_native_bridge.ps1) + legacy install/ (dev).
cands.append(os.path.join(settings.BASE_DIR, "src-tauri", "binaries", sidecar))
cands.append(os.path.join(settings.BASE_DIR, "install", exe_name))
for p in cands:
if p and os.path.isfile(p):
return p
return ""
def find_fx_bridge_exe() -> str:
"""Đường dẫn FX bridge (fx_vst_bridge.exe): SF_FX_BRIDGE_PATH → bundle → install/."""
return find_bridge_exe(FX_BRIDGE_EXE, "SF_FX_BRIDGE_PATH")
def normalize_audio_peak(audio, target_db=0.0):
"""Scale audio (numpy array, peak) về target_db nếu vượt; giữ nguyên nếu dưới.
@@ -209,18 +223,18 @@ def render_fx_chain(input_wav, fx_chain, sample_rate, out_path=None) -> str:
out_path; lỗi → HTTPException (501 thiếu bridge, 404 plugin lạ, 500 render).
"""
from app.core.vst_engine import resolve_plugin_path
exe = find_bridge_exe()
exe = find_fx_bridge_exe()
if not exe:
raise HTTPException(
status_code=501,
detail="native_bridge không khả dụng — đặt SF_BRIDGE_PATH hoặc cài daw_vst_bridge",
detail="native_bridge không khả dụng — đặt SF_FX_BRIDGE_PATH hoặc cài fx_vst_bridge",
)
slots = []
for fx in fx_chain or []:
typ = fx.get("type")
if typ == "vst3":
p = (fx.get("path") or "").strip()
resolved = p if os.path.isfile(p) else resolve_plugin_path(p, ".vst3")
resolved = p if os.path.exists(p) else resolve_plugin_path(p, ".vst3")
if not resolved:
raise HTTPException(
status_code=404,