fix(export): carry bridge-captured VSTi preset into offline render

Offline render tao bridge moi khong co preset -> plugin load init patch
-> am khac realtime (user tuong fallback). Gio doc presetBase64 tu
bridge_state.json (channel == track.id, plugin_path khop basename) va
truyen vao render_offline khi track khong nhung preset_data.
This commit is contained in:
2026-08-25 21:14:48 +07:00
parent 014d02283d
commit 57fa2e78fe
2 changed files with 50 additions and 1 deletions
+37
View File
@@ -137,6 +137,43 @@ def _preset_b64(preset_id, preset_path, preset_data_b64) -> str:
return ""
def bridge_state_preset_b64(channel=None, plugin_path=None) -> str:
"""presetBase64 từ bridge_state.json — bridge C++ đang giữ preset user
chỉnh realtime (capture mỗi ~2s). Export tạo bridge mới không có preset →
plugin load init patch → âm khác realtime (user tưởng "fallback"). Fallback
này nối: dùng preset mà bridge đã capture cho channel đó.
Match: channel == int(track.id) (scheduleMidiNoteDispatch pushEvent
channel: trkId) + path khớp plugin (basename, case-insensitive). Không tìm
thấy → "" (giữ hành vi cũ — không đoán bừa preset channel khác)."""
try:
st_path = os.path.join(os.environ.get("APPDATA", ""), "SonicForgeDAW",
"state", "bridge_state.json")
if not os.path.isfile(st_path):
return ""
with open(st_path, encoding="utf-8", errors="replace") as fh:
st = json.load(fh)
try:
ch = int(channel) if channel is not None else None
except Exception:
ch = None
want = None
if plugin_path:
want = os.path.basename(os.fspath(plugin_path)).lower()
for ins in st.get("instruments") or []:
if ch is not None and ins.get("channel") != ch:
continue
ip = ins.get("path") or ""
if want and os.path.basename(ip).lower() != want:
continue
pb = ins.get("presetBase64") or ""
if pb:
return pb
except Exception:
pass
return ""
def _run_notes_job(job: dict, label: str) -> tuple:
"""Chạy job MIDI render qua native_bridge --render → (out_path, duration_sec).