G1.4: bo mute-when-editor-open - channelQuiet chi con reloading; xoa editorOpen machinery (g_editorOpen/g_editorPathCount/clear_editor_open/setEditorOpenPredicate); audio loop process() binh thuong khi editor mo
This commit is contained in:
Binary file not shown.
@@ -110,7 +110,6 @@ public:
|
||||
// plugin DLL path has an open editor count as quiet (same-plugin channels
|
||||
// too -- the worker pumps the editor's window proc inside the DLL while the
|
||||
// audio loop process()es other instances of the same DLL).
|
||||
void setEditorOpenPredicate(std::function<bool(const std::string& lowerPath)> fn);
|
||||
|
||||
// Flush every sounding note on every assigned channel.
|
||||
void allNotesOff();
|
||||
@@ -137,7 +136,6 @@ private:
|
||||
// is in progress): real-time code drops MIDI and skips rendering. Lowercased
|
||||
// compare inside -- Windows plugin paths are case-insensitive.
|
||||
bool channelQuiet(uint32_t ch) const;
|
||||
std::function<bool(const std::string&)> editorOpenFn_;
|
||||
std::atomic<bool> isBypassed_{false};
|
||||
};
|
||||
|
||||
|
||||
@@ -260,24 +260,12 @@ bool InstrumentEngineManager::isReloading(uint32_t channel) const {
|
||||
return channel < 16 && reloadingCh_[channel];
|
||||
}
|
||||
|
||||
void InstrumentEngineManager::setEditorOpenPredicate(std::function<bool(const std::string&)> fn) {
|
||||
std::lock_guard<std::mutex> lock(mu_);
|
||||
editorOpenFn_ = std::move(fn);
|
||||
}
|
||||
|
||||
// Quiet = reloading OR an editor attached for the channel's plugin DLL path.
|
||||
// Called with mu_ held by the real-time dispatch (the predicate locks
|
||||
// g_editorMutex -- lock order mu_ -> g_editorMutex; g_editorMutex is never
|
||||
// held while taking mu_).
|
||||
// Quiet = reloading (mid-rebuild) only. G1.4: bo mute-when-editor-open —
|
||||
// editor co the mo trong luc PLAY, audio loop van process() binh thuong.
|
||||
// Called with mu_ held by the real-time dispatch.
|
||||
bool InstrumentEngineManager::channelQuiet(uint32_t ch) const {
|
||||
if (ch >= 16 || reloadingCh_[ch]) return true;
|
||||
if (!editorOpenFn_) return false;
|
||||
auto it = paths_.find(ch);
|
||||
if (it == paths_.end() || it->second.empty()) return false;
|
||||
std::string lp = it->second;
|
||||
std::transform(lp.begin(), lp.end(), lp.begin(),
|
||||
[](unsigned char c) { return (char)::tolower(c); });
|
||||
return editorOpenFn_(lp);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Real-time MIDI dispatch: hold mu_ for the WHOLE call so assign()/unload()
|
||||
|
||||
@@ -125,19 +125,6 @@ static std::mutex g_attachMutex;
|
||||
static std::vector<std::string> g_attachPaths;
|
||||
static bool g_closeInFlight[16] = { false };
|
||||
|
||||
// Editor-open tracking: while a channel's VST editor (native window) is
|
||||
// attached, EVERY channel assigned the same plugin DLL path must stay quiet —
|
||||
// the plugin's window proc runs on the editor channel's worker while the
|
||||
// audio loop calls process() on other instances of the same DLL (2 threads
|
||||
// in one DLL -> Nexus USER32 crash). g_editorPathCount = refcount per
|
||||
// lowercase plugin path; g_editorOpenPath/g_editorOpen per channel.
|
||||
// Lock order: g_editorMutex is taken while holding the engine mutex
|
||||
// (channelQuiet) or standalone in non-rt jobs — never the reverse.
|
||||
static std::mutex g_editorMutex;
|
||||
static std::map<std::string, int> g_editorPathCount;
|
||||
static std::string g_editorOpenPath[16];
|
||||
static bool g_editorOpen[16] = { false };
|
||||
|
||||
static LRESULT CALLBACK VstWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
||||
if (uMsg == WM_CLOSE) {
|
||||
uint32_t ch = UINT32_MAX;
|
||||
@@ -442,22 +429,6 @@ static void unmute_if_not_closing(uint32_t y, const char* why) {
|
||||
g_engine->setReloading(y, false);
|
||||
}
|
||||
|
||||
// Editor closed / instrument replaced: drop the channel's editor-open state
|
||||
// (refcounted per lowercase plugin path). Called from non-rt jobs only —
|
||||
// never from the audio loop.
|
||||
static void clear_editor_open(uint32_t ch) {
|
||||
std::lock_guard<std::mutex> lk(g_editorMutex);
|
||||
if (!g_editorOpen[ch]) return;
|
||||
g_editorOpen[ch] = false;
|
||||
std::string pth = g_editorOpenPath[ch];
|
||||
g_editorOpenPath[ch].clear();
|
||||
if (!pth.empty()) {
|
||||
auto it = g_editorPathCount.find(pth);
|
||||
if (it != g_editorPathCount.end() && --it->second <= 0)
|
||||
g_editorPathCount.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
// closeGUI() MUST run on the UiThread (its COM STA apartment) — the view was
|
||||
// attached there. Calling view->removed() from another thread is a
|
||||
// cross-apartment COM call that corrupts the plugin; Nexus then hangs on the
|
||||
@@ -544,9 +515,6 @@ static void close_editor_now(uint32_t ch, HWND hwnd) {
|
||||
<< " — plugin threw (createInstance)" << std::endl;
|
||||
}
|
||||
}
|
||||
// Editor detached + fresh instance loaded: drop editor-open
|
||||
// state (channelQuiet falls back to reloading flags only).
|
||||
clear_editor_open(ch);
|
||||
// createInstance is done: unmuting is safe again. But if an
|
||||
// attach for the SAME plugin path is still running (its
|
||||
// createView must not race process() on any same-path
|
||||
@@ -570,7 +538,6 @@ static void close_editor_now(uint32_t ch, HWND hwnd) {
|
||||
} else {
|
||||
// Instrument already gone (unloaded) — nothing to rebuild.
|
||||
g_engine->setReloading(ch, false);
|
||||
clear_editor_open(ch);
|
||||
std::lock_guard<std::mutex> lk(g_attachMutex);
|
||||
g_closeInFlight[ch] = false;
|
||||
}
|
||||
@@ -672,14 +639,6 @@ int main(int argc, char* argv[]) {
|
||||
#ifdef _WIN32
|
||||
g_engine = &instruments;
|
||||
#endif
|
||||
// Editor-open predicate: channelQuiet() checks whether ANY editor is
|
||||
// attached for the channel's plugin DLL path (refcounted in
|
||||
// g_editorPathCount, updated by the open/close GUI jobs).
|
||||
instruments.setEditorOpenPredicate([](const std::string& lp) {
|
||||
std::lock_guard<std::mutex> lk(g_editorMutex);
|
||||
auto it = g_editorPathCount.find(lp);
|
||||
return it != g_editorPathCount.end() && it->second > 0;
|
||||
});
|
||||
// Per-channel persistent workers: loadPlugin + openGUI run on the SAME
|
||||
// thread whose COM STA apartment stays alive for the channel's lifetime
|
||||
// (see ChannelWorker comment — a dead apartment hangs Nexus attached()).
|
||||
@@ -1015,23 +974,11 @@ int main(int argc, char* argv[]) {
|
||||
for (uint32_t y : samePathSilenced)
|
||||
unmute_if_not_closing(y, "openGUI");
|
||||
if (ok) {
|
||||
// Editor attached: mark the plugin path editor-open so the
|
||||
// audio loop stops processing EVERY channel assigned this
|
||||
// DLL while the editor lives (its window proc runs on this
|
||||
// worker; process() elsewhere on the same DLL -> Nexus crash).
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(g_editorMutex);
|
||||
if (!gp.empty()) {
|
||||
g_editorOpen[guiCh] = true;
|
||||
g_editorOpenPath[guiCh] = gp;
|
||||
++g_editorPathCount[gp];
|
||||
}
|
||||
}
|
||||
|
||||
disable_ime_contexts((HWND)hwnd);
|
||||
|
||||
std::cout << "[NativeBridge] GUI attached hwnd=" << hwnd
|
||||
<< " (channel muted while editor open)" << std::endl;
|
||||
<< " plugin=" << arg2 << " ch=" << guiCh
|
||||
<< std::endl;
|
||||
instruments.setReloading(guiCh, false);
|
||||
}
|
||||
@@ -1166,9 +1113,6 @@ int main(int argc, char* argv[]) {
|
||||
std::cerr << "[NativeBridge] LOAD close-editor EXCEPTION ch=" << ch
|
||||
<< " — plugin window proc threw" << std::endl;
|
||||
}
|
||||
// Editor detached: drop editor-open state before the
|
||||
// instrument is replaced (assign).
|
||||
clear_editor_open(ch);
|
||||
ShowWindow(hToHide, SW_HIDE);
|
||||
}
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user