fix crash bridge khi đổi SF→VSTi đang play: silence same-plugin theo path MỚI trước assign() (createInstance) — track restore giữ cùng DLL process song song audio loop = 2 threads 1 DLL Nexus crash; không tự mở GUI khi đang play (C++ mute channel tới khi đóng GUI → tắt âm)

This commit is contained in:
2026-08-14 17:08:17 +07:00
parent af59aaf257
commit 2596372ab1
4 changed files with 49 additions and 20 deletions
+32 -18
View File
@@ -227,13 +227,16 @@ private:
// Two threads inside one VST3 DLL (Nexus) crash/deadlock: the audio loop's
// process() on one instance must not race createInstance/createView/terminate
// on another. Windows plugin paths are case-insensitive — compare lowercased.
static std::string lower_plugin_path(uint32_t ch) {
std::string p = g_engine ? g_engine->pathOf(ch) : std::string();
static std::string lower_path_str(std::string p) {
std::transform(p.begin(), p.end(), p.begin(),
[](unsigned char c) { return (char)::tolower(c); });
return p;
}
static std::string lower_plugin_path(uint32_t ch) {
return g_engine ? lower_path_str(g_engine->pathOf(ch)) : std::string();
}
// Channels (other than ch) currently assigned the same plugin DLL path.
static std::vector<uint32_t> same_plugin_channels(uint32_t ch) {
std::vector<uint32_t> out;
@@ -820,8 +823,14 @@ int main(int argc, char* argv[]) {
// session-restore instances). Silence this channel (its old
// instance is being torn down / replaced) and every
// same-plugin channel for the whole job. Old path covers
// the old-instance teardown; the new path (after assign)
// covers the freshly created instance.
// the old-instance teardown; the new path (computed BEFORE
// assign — see spNew below) covers the freshly created
// instance. CRASH FIX (SF→VSTi while playing): the new
// path must be silenced BEFORE assign() — assign() itself
// runs createInstance (loadPlugin) on this worker, and a
// restored channel on ANOTHER track holding the SAME DLL
// kept process()ing on the audio loop during that window
// (old code silenced spNew only AFTER assign → crash).
instruments.setReloading(ch, true);
std::vector<uint32_t> spOld = same_plugin_channels(ch);
for (uint32_t y : spOld) {
@@ -829,6 +838,24 @@ int main(int argc, char* argv[]) {
std::cerr << "[dbg] load: silenced same-plugin ch=" << y
<< " during load ch=" << ch << std::endl;
}
// Channels (other than ch) already assigned the NEW path —
// silence BEFORE createInstance enters that DLL.
std::vector<uint32_t> spNew;
if (t == InstrumentType::VST3) {
std::string np = lower_path_str(path);
if (!np.empty()) {
for (uint32_t y = 0; y < 16; ++y) {
if (y == ch) continue;
if (!g_engine->get(y)) continue;
if (std::find(spOld.begin(), spOld.end(), y) != spOld.end()) continue;
if (lower_plugin_path(y) != np) continue;
g_engine->setReloading(y, true);
spNew.push_back(y);
std::cerr << "[dbg] load: silenced same-plugin (new path) ch=" << y
<< " during load ch=" << ch << std::endl;
}
}
}
#ifdef _WIN32
// DONG cua so editor dang mo cua channel TRUOC khi assign():
// thay the inst (VST3 -> SF2/inst khac) ma editor con song ->
@@ -879,25 +906,12 @@ int main(int argc, char* argv[]) {
std::cerr << "[NativeBridge] instrument load FAILED ch=" << ch
<< " type=" << (int)t << " " << path << std::endl;
}
// New-path channels (the freshly created instance's DLL) —
// silence any not already covered by the old path.
std::vector<uint32_t> spNew;
if (ok) spNew = same_plugin_channels(ch);
for (uint32_t y : spNew) {
if (std::find(spOld.begin(), spOld.end(), y) == spOld.end()) {
g_engine->setReloading(y, true);
std::cerr << "[dbg] load: silenced same-plugin ch=" << y
<< " (new path) during load ch=" << ch << std::endl;
}
}
// Restore. Failed load keeps the OLD instance — unmute it
// back (silenced at job start); a successful assign leaves
// the fresh instance unmuted by construction.
if (!ok) g_engine->setReloading(ch, false);
for (uint32_t y : spOld) unmute_if_not_closing(y, "load");
for (uint32_t y : spNew)
if (std::find(spOld.begin(), spOld.end(), y) == spOld.end())
unmute_if_not_closing(y, "load");
for (uint32_t y : spNew) unmute_if_not_closing(y, "load");
});
} else if (c.type == 1) { // PANIC
instruments.allNotesOff();