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
|
// 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
|
// too -- the worker pumps the editor's window proc inside the DLL while the
|
||||||
// audio loop process()es other instances of the same DLL).
|
// 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.
|
// Flush every sounding note on every assigned channel.
|
||||||
void allNotesOff();
|
void allNotesOff();
|
||||||
@@ -137,7 +136,6 @@ private:
|
|||||||
// is in progress): real-time code drops MIDI and skips rendering. Lowercased
|
// is in progress): real-time code drops MIDI and skips rendering. Lowercased
|
||||||
// compare inside -- Windows plugin paths are case-insensitive.
|
// compare inside -- Windows plugin paths are case-insensitive.
|
||||||
bool channelQuiet(uint32_t ch) const;
|
bool channelQuiet(uint32_t ch) const;
|
||||||
std::function<bool(const std::string&)> editorOpenFn_;
|
|
||||||
std::atomic<bool> isBypassed_{false};
|
std::atomic<bool> isBypassed_{false};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -260,24 +260,12 @@ bool InstrumentEngineManager::isReloading(uint32_t channel) const {
|
|||||||
return channel < 16 && reloadingCh_[channel];
|
return channel < 16 && reloadingCh_[channel];
|
||||||
}
|
}
|
||||||
|
|
||||||
void InstrumentEngineManager::setEditorOpenPredicate(std::function<bool(const std::string&)> fn) {
|
// Quiet = reloading (mid-rebuild) only. G1.4: bo mute-when-editor-open —
|
||||||
std::lock_guard<std::mutex> lock(mu_);
|
// editor co the mo trong luc PLAY, audio loop van process() binh thuong.
|
||||||
editorOpenFn_ = std::move(fn);
|
// Called with mu_ held by the real-time dispatch.
|
||||||
}
|
|
||||||
|
|
||||||
// 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_).
|
|
||||||
bool InstrumentEngineManager::channelQuiet(uint32_t ch) const {
|
bool InstrumentEngineManager::channelQuiet(uint32_t ch) const {
|
||||||
if (ch >= 16 || reloadingCh_[ch]) return true;
|
if (ch >= 16 || reloadingCh_[ch]) return true;
|
||||||
if (!editorOpenFn_) return false;
|
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Real-time MIDI dispatch: hold mu_ for the WHOLE call so assign()/unload()
|
// 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 std::vector<std::string> g_attachPaths;
|
||||||
static bool g_closeInFlight[16] = { false };
|
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) {
|
static LRESULT CALLBACK VstWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
||||||
if (uMsg == WM_CLOSE) {
|
if (uMsg == WM_CLOSE) {
|
||||||
uint32_t ch = UINT32_MAX;
|
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);
|
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
|
// closeGUI() MUST run on the UiThread (its COM STA apartment) — the view was
|
||||||
// attached there. Calling view->removed() from another thread is a
|
// attached there. Calling view->removed() from another thread is a
|
||||||
// cross-apartment COM call that corrupts the plugin; Nexus then hangs on the
|
// 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;
|
<< " — 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
|
// createInstance is done: unmuting is safe again. But if an
|
||||||
// attach for the SAME plugin path is still running (its
|
// attach for the SAME plugin path is still running (its
|
||||||
// createView must not race process() on any same-path
|
// createView must not race process() on any same-path
|
||||||
@@ -570,7 +538,6 @@ static void close_editor_now(uint32_t ch, HWND hwnd) {
|
|||||||
} else {
|
} else {
|
||||||
// Instrument already gone (unloaded) — nothing to rebuild.
|
// Instrument already gone (unloaded) — nothing to rebuild.
|
||||||
g_engine->setReloading(ch, false);
|
g_engine->setReloading(ch, false);
|
||||||
clear_editor_open(ch);
|
|
||||||
std::lock_guard<std::mutex> lk(g_attachMutex);
|
std::lock_guard<std::mutex> lk(g_attachMutex);
|
||||||
g_closeInFlight[ch] = false;
|
g_closeInFlight[ch] = false;
|
||||||
}
|
}
|
||||||
@@ -672,14 +639,6 @@ int main(int argc, char* argv[]) {
|
|||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
g_engine = &instruments;
|
g_engine = &instruments;
|
||||||
#endif
|
#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
|
// Per-channel persistent workers: loadPlugin + openGUI run on the SAME
|
||||||
// thread whose COM STA apartment stays alive for the channel's lifetime
|
// thread whose COM STA apartment stays alive for the channel's lifetime
|
||||||
// (see ChannelWorker comment — a dead apartment hangs Nexus attached()).
|
// (see ChannelWorker comment — a dead apartment hangs Nexus attached()).
|
||||||
@@ -1015,23 +974,11 @@ int main(int argc, char* argv[]) {
|
|||||||
for (uint32_t y : samePathSilenced)
|
for (uint32_t y : samePathSilenced)
|
||||||
unmute_if_not_closing(y, "openGUI");
|
unmute_if_not_closing(y, "openGUI");
|
||||||
if (ok) {
|
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);
|
disable_ime_contexts((HWND)hwnd);
|
||||||
|
|
||||||
std::cout << "[NativeBridge] GUI attached hwnd=" << hwnd
|
std::cout << "[NativeBridge] GUI attached hwnd=" << hwnd
|
||||||
<< " (channel muted while editor open)" << std::endl;
|
<< " plugin=" << arg2 << " ch=" << guiCh
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
instruments.setReloading(guiCh, false);
|
instruments.setReloading(guiCh, false);
|
||||||
}
|
}
|
||||||
@@ -1166,9 +1113,6 @@ int main(int argc, char* argv[]) {
|
|||||||
std::cerr << "[NativeBridge] LOAD close-editor EXCEPTION ch=" << ch
|
std::cerr << "[NativeBridge] LOAD close-editor EXCEPTION ch=" << ch
|
||||||
<< " — plugin window proc threw" << std::endl;
|
<< " — 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);
|
ShowWindow(hToHide, SW_HIDE);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user