fix(v8): 5 bugs — orphan bridge watchdog+state overwrite, stuck-note stop race, white VST GUI retry, VSTi auto-load via saved plugin_path, track-header button overflow

- native bridge: dedicated watchdog thread (parent death / PID-reuse via GetProcessTimes) -> TerminateProcess self; transportStopped flag drops note-on after STOP + CC64 sustain release + allNotesOff on stop
- tauri: set_bridge_child overwrites managed BridgeProcess state (app.manage is no-op when state exists) so Destroyed handler kills restarted bridge
- ui: stopAllPlayback syncs isPlayingRef/subTabsRef + second transport stop at 150ms; onStatusChange resets __bridgeLoadedChannels at callback start (auto-restart never emits bridge-down); openVstGuiRetry waits for async C++ load before OPEN_GUI; loadVstToBridge uses synth_engine.plugin_path / listPlugins fallback and persists plugin_path on load; shrink track-header Synth/GUI buttons
This commit is contained in:
2026-08-13 21:14:31 +07:00
parent e3f5dad2ac
commit 96d31ee685
5 changed files with 134 additions and 22 deletions
+17 -3
View File
@@ -24,6 +24,20 @@ struct EngineProcess(Mutex<Option<CommandChild>>);
struct BridgeProcess(Mutex<Option<CommandChild>>);
struct BridgeSampleRate(Mutex<u32>);
/// Overwrite the managed bridge child. `app.manage` is a NO-OP once the state
/// exists (StateManager::set keeps the first value), so restarts would leave
/// the state at None and the Destroyed handler would never kill the new
/// bridge — orphan daw_vst_bridge.exe. First call still uses manage().
fn set_bridge_child(app: &AppHandle, child: Option<CommandChild>) {
if let Some(state) = app.try_state::<BridgeProcess>() {
if let Ok(mut g) = state.0.lock() {
*g = child;
}
} else {
app.manage(BridgeProcess(Mutex::new(child)));
}
}
/// Kill the currently managed bridge child (if any) — a restart MUST never
/// leave the old bridge running, else two daw_vst_bridge.exe race on the same
/// SHM (double instrument load, double OPEN_GUI, garbled control queue).
@@ -145,7 +159,7 @@ fn spawn_bridge(
.spawn()
{
Ok((mut rx, child)) => {
app.manage(BridgeProcess(Mutex::new(Some(child))));
set_bridge_child(app, Some(child));
// B3: redirect bridge stdout/stderr → %APPDATA%/SonicForgeDAW/logs/bridge.log
// (tauri-shell pipe rồi vứt rx; đọc event ghi file — E5 UI tail được).
let log_dir = std::env::var("APPDATA").unwrap_or_else(|_| ".".into());
@@ -175,14 +189,14 @@ fn spawn_bridge(
}
Err(e) => {
println!("Failed to spawn daw_vst_bridge {bridge_exe:?}: {e}");
app.manage(BridgeProcess(Mutex::new(None)));
set_bridge_child(app, None);
false
}
}
}
None => {
println!("daw_vst_bridge binary not found — app will use WASM fallback");
app.manage(BridgeProcess(Mutex::new(None)));
set_bridge_child(app, None);
false
}
}