fix(bridge): 3 bug âm thanh Qin/Nexus standalone
1) wavesynth tự phát khi mở app: probe calibrate() render vào live mix (renderAll process cùng instance) -> thêm calibratingCh_[16], renderAll bỏ qua channel đang calibrate; plugin_host panic (sustain off + all notes off + 128 noteOff) ngay sau preset apply để startup im lặng. 2) bấm GUI mở 2 cửa sổ Qin: sandbox VST2 child tự sở hữu top-level window -> ownsGuiWindow() + main.cpp forward OPEN_GUI control, không tạo native parent / không registry double-open. 3) play phát nhạc cụ sai: restore clobber — seed preset đè patch thật trong state file (ch3 63ba3667 -> 7f07473c) do saveStateJob chạy lúc child còn seed. Fix: queuePreset(waitApply=true) chờ child apply xong (presetOut memcmp), consume-before-apply (zero presetInLen trước khi apply), deferred double-load re-check trong main.cpp skip assign trùng path, watchdog respawn re-queue lastPreset_.
This commit is contained in:
@@ -1129,6 +1129,24 @@ int main(int argc, char* argv[]) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// G4.6: child-own GUI (sandbox VST2 like Qin). The child process
|
||||
// opens its OWN top-level window on control 4 — no native parent
|
||||
// window to create, no g_guiWindows registry, no same-path
|
||||
// silencing, no closing of other editors (separate process;
|
||||
// nothing to serialize). Just forward the OPEN_GUI control.
|
||||
if (auto* inst0 = instruments.get(guiCh)) {
|
||||
if (inst0->ownsGuiWindow()) {
|
||||
std::cerr << "[NativeBridge] GUI via child-own ch=" << guiCh
|
||||
<< " plugin=" << arg2 << std::endl;
|
||||
try {
|
||||
inst0->attachView(nullptr);
|
||||
} catch (...) {
|
||||
std::cerr << "[NativeBridge] GUI child-own attach EXCEPTION ch=" << guiCh
|
||||
<< std::endl;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
void* hwnd = (void*)arg1;
|
||||
#ifdef _WIN32
|
||||
HWND nativeHwnd = nullptr;
|
||||
@@ -1577,6 +1595,23 @@ int main(int argc, char* argv[]) {
|
||||
auto doAssign = std::function<void()>(
|
||||
[&instruments, t, ch, path, sampleRate, block, spOld, spNew]() {
|
||||
std::lock_guard<std::mutex> lg(g_loadMutex);
|
||||
// G4.6: deferred double-load re-check. Restore's
|
||||
// doRestore (also deferred via runOnMain) can assign
|
||||
// the SAME path FIRST — a second assign here replaces
|
||||
// the restored instance with a seed-only one (doAssign
|
||||
// applies NO preset) and clobbers the real patch in
|
||||
// the state file (ch3 63ba3667 -> 7f07473c observed).
|
||||
// Skip like the job-level guard; undo the silence.
|
||||
if (!path.empty() && !lower_plugin_path(ch).empty() &&
|
||||
lower_plugin_path(ch) == lower_path_str(path)) {
|
||||
std::cout << "[NativeBridge] LOAD skip (deferred re-check) ch=" << ch
|
||||
<< " path=" << path << std::endl;
|
||||
g_engine->setReloading(ch, false);
|
||||
for (uint32_t y : spOld) unmute_if_not_closing(y, "load-skip");
|
||||
for (uint32_t y : spNew) unmute_if_not_closing(y, "load-skip");
|
||||
g_stateDirty = true;
|
||||
return;
|
||||
}
|
||||
bool ok = false;
|
||||
try {
|
||||
ok = instruments.assign(ch, t, path, sampleRate, block);
|
||||
|
||||
Reference in New Issue
Block a user