diff --git a/install/daw_vst_bridge.exe b/install/daw_vst_bridge.exe index d4bd164..83389a8 100644 Binary files a/install/daw_vst_bridge.exe and b/install/daw_vst_bridge.exe differ diff --git a/native_bridge/src/main.cpp b/native_bridge/src/main.cpp index 220aff7..08b8701 100644 --- a/native_bridge/src/main.cpp +++ b/native_bridge/src/main.cpp @@ -956,6 +956,19 @@ int main(int argc, char* argv[]) { return; } } + // G0.1 (BUG_REPORT): mo GUI khi dang PLAY -> attachView chay tren worker + // thread trong luc audio loop process() cung DLL (2 thread 1 plugin) -> + // Nexus throw (createView/attached) -> GUI khong load + retry spam -> + // stall 3s -> watchdog kill bridge -> mat het instrument -> cam. Defer + // OPEN_GUI toi khi transport STOP (sweep duoi fulfill khi loaded && + // transportStopped). Khong doi: tranh mat am; user STOP la GUI tu mo. + if (!transportStopped) { + std::cerr << "[NativeBridge] GUI deferred ch=" << guiCh + << " plugin=" << pluginId << " (transport PLAY) - queued" << std::endl; + std::lock_guard lock(g_pendingGuiMutex); + g_pendingGui[guiCh] = { (void*)arg1, pluginId }; + return; + } if (!workers[guiCh]) { workers[guiCh] = std::make_unique(); } @@ -994,6 +1007,28 @@ int main(int argc, char* argv[]) { } } #endif + // G0.1b: silence same-path instances on the MAIN thread BEFORE the + // attach job runs - renderAll of this loop iteration (and any before + // the worker sets reloading_) would otherwise process() another Nexus + // while the job's reload() (createInstance/terminate) enters the DLL + // -> 2 threads in 1 DLL -> Nexus hang -> writeIndex stall -> watchdog + // kills the bridge (observed: defer OK, attach after STOP still + // restarted). setReloading is a flag under the engine mutex; renderAll + // skips reloading channels, so no process() can race the job. The job + // keeps its own setReloading + restore logic unchanged. Dat o day (sau + // window create) de window fail khong keo mute vinh vien. + { + std::string gp0 = lower_plugin_path(guiCh); + if (!gp0.empty()) { + for (uint32_t y = 0; y < 16; ++y) { + if (y == guiCh) continue; + if (!instruments.get(y)) continue; + if (lower_plugin_path(y) == gp0) + instruments.setReloading(y, true); + } + instruments.setReloading(guiCh, true); + } + } workers[guiCh]->post([&instruments, guiCh, hwnd, arg2 = pluginId]() { if (!instruments.get(guiCh)) { std::cerr << "[NativeBridge] GUI attach FAILED hwnd=" << hwnd @@ -1424,7 +1459,8 @@ int main(int argc, char* argv[]) { { std::lock_guard lock(g_pendingGuiMutex); for (auto it = g_pendingGui.begin(); it != g_pendingGui.end(); ) { - if (instruments.get(it->first)) { + // G0.1: giu entry khi dang PLAY - handleOpenGui se defer lai + if (transportStopped && instruments.get(it->first)) { readyGui.push_back({ it->first, it->second }); it = g_pendingGui.erase(it); } else ++it;