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
+46 -2
View File
@@ -209,6 +209,37 @@ int main(int argc, char* argv[]) {
uint32_t parentPid = 0;
if (const char* e = std::getenv("SF_PARENT_PID")) parentPid = (uint32_t)std::atoi(e);
// V8 bug 2: watchdog THREAD rieng - main loop chi check parent_alive giua
// cac block; neu VST process() chan loop thi khong bao gio thoat -> orphan.
// Thread nay chay doc lap, parent chet -> TerminateProcess ngay. Kem
// start-time check chong PID reuse (OpenProcess tra handle cua process
// khac chiem lai PID -> tuong parent con song mai).
if (parentPid != 0) {
std::thread([parentPid]() {
auto proc_birth = [](HANDLE h) -> uint64_t {
FILETIME c, e, k, u;
if (GetProcessTimes(h, &c, &e, &k, &u))
return (uint64_t(c.dwHighDateTime) << 32) | c.dwLowDateTime;
return 0;
};
uint64_t birth = 0;
{
HANDLE h = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, parentPid);
if (h) { birth = proc_birth(h); CloseHandle(h); }
}
for (;;) {
Sleep(2000);
HANDLE h = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, parentPid);
if (!h) { TerminateProcess(GetCurrentProcess(), 0); return; }
uint64_t nowBirth = proc_birth(h);
CloseHandle(h);
if (birth != 0 && nowBirth != 0 && nowBirth != birth) {
TerminateProcess(GetCurrentProcess(), 0); return;
}
}
}).detach();
}
#ifdef _WIN32
// Real-time-ish timing: 1ms scheduler resolution
timeBeginPeriod(1);
@@ -252,6 +283,10 @@ int main(int argc, char* argv[]) {
}
const uint32_t block = AUDIO_BLOCK_SIZE;
uint64_t playheadSamples = 0;
// V8 bug 3: khi STOP da xu ly, bo qua NOTE_ON (velocity>0) den sau - JS
// note-on timer co the bay toi sau STOP (guardPlay tre do React re-render)
// -> retrigger note -> VST loop am. Chi PLAY moi nhan note-on lai.
bool transportStopped = false;
auto dispatch = [&](const SharedAudioBufferIPC::MidiEventIPC& evt) {
auto* inst = instruments.get(evt.channel);
@@ -261,9 +296,10 @@ int main(int argc, char* argv[]) {
// sampleOffset LUON LUON = 0 khi den day: events duoc dispatch ngay
// truoc segment chua no (A11 splitting), nen offset tuong doi la 0.
// Truyen offset tuyet doi truoc day lam sfizz/VST3 trigger tre.
if (evt.velocity > 0)
if (evt.velocity > 0) {
if (transportStopped) return; // V8 bug 3: drop note-on sau STOP
inst->noteOn(evt.channel, evt.pitch, evt.velocity / 127.0f, 0);
else
} else
inst->noteOff(evt.channel, evt.pitch, 0);
break;
case 0x8:
@@ -363,9 +399,17 @@ int main(int argc, char* argv[]) {
std::cout << "[NativeBridge] PANIC — all notes off" << std::endl;
} else if (c.type == 3) { // TRANSPORT (A13)
if (c.arg0 == 0) { // STOP → flush every note immediately
transportStopped = true;
// Release sustain pedal TRUOC (CC64=0) — nhieu VSTi giu note
// khi pedal con down -> note-off cua allNotesOff bi bo qua
// -> am treo loop (V8 bug 3).
for (uint32_t ch = 0; ch < 16; ++ch) {
if (auto* inst = instruments.get(ch)) inst->controlChange(ch, 64, 0);
}
instruments.allNotesOff();
std::cout << "[NativeBridge] transport STOP — all notes off" << std::endl;
} else if (c.arg0 == 1) { // PLAY
transportStopped = false;
playheadSamples = c.arg1;
std::cout << "[NativeBridge] transport PLAY playhead=" << playheadSamples << std::endl;
} else if (c.arg0 == 2) { // SET_POSITION (seek while stopped)