fix crash daw_vst_bridge 0xc000041d khi mở GUI Nexus rồi switch sang Ample: over-gate JUCE message window (g_juceOwnerTids, chỉ chạy khi close_in_flight) + gỡ VEH tạm và mọi log [dbg] chẩn đoán, giữ [NativeBridge] production; deploy exe FINAL (đã verify 3 run driver)

This commit is contained in:
2026-08-15 11:35:50 +07:00
parent 2596372ab1
commit 90241f626f
4 changed files with 472 additions and 137 deletions
-48
View File
@@ -213,14 +213,12 @@ bool Vst3Instrument::loadPlugin(const std::string& path, double sampleRate) {
using namespace VST3::Hosting;
std::string err;
std::cerr << "[dbg] loadPlugin: Module::create ..." << std::endl;
Module::Ptr module = Module::create(path, err);
if (!module) {
std::cerr << "[Vst3Instrument] Module::create failed: " << err << std::endl;
return false;
}
const PluginFactory& factory = module->getFactory();
std::cerr << "[dbg] loadPlugin: Module::create OK" << std::endl;
// Pick the first Audio Module class; prefer an Instrument subcategory.
// classInfos() returns a TEMPORARY vector (by value) — never keep a
@@ -244,16 +242,12 @@ bool Vst3Instrument::loadPlugin(const std::string& path, double sampleRate) {
return false;
}
std::cerr << "[dbg] loadPlugin: createInstance ..." << std::endl;
std::cerr << "[dbg] loadPlugin: chosen name=" << chosen.name() << " category=" << chosen.category()
<< " subcat=" << chosen.subCategoriesString() << std::endl;
IPtr<IComponent> component = factory.createInstance<IComponent>(chosen.ID());
if (!component) {
std::cerr << "[Vst3Instrument] createInstance<IComponent> failed" << std::endl;
return false;
}
IPtr<HostApplication> hostApp = owned(new HostApplication());
std::cerr << "[dbg] loadPlugin: initialize ..." << std::endl;
FUnknownPtr<IPluginBase> plugBase(component.get());
if (!plugBase || plugBase->initialize(hostApp) != kResultOk) {
std::cerr << "[Vst3Instrument] component initialize failed" << std::endl;
@@ -269,13 +263,8 @@ bool Vst3Instrument::loadPlugin(const std::string& path, double sampleRate) {
} else {
Steinberg::TUID cid = {};
tresult cidRes = component->getControllerClassId(cid);
std::cerr << "[dbg] loadPlugin: getControllerClassId=" << (int)cidRes
<< " cid=";
for (int b = 0; b < 16; ++b) std::cerr << std::hex << (int)(unsigned char)cid[b] << ' ';
std::cerr << std::dec << std::endl;
if (cidRes == kResultTrue || cidRes == kResultOk) {
controller = factory.createInstance<IEditController>(VST3::UID(cid));
std::cerr << "[dbg] loadPlugin: controller from factory=" << (controller ? 1 : 0) << std::endl;
if (controller) {
FUnknownPtr<IPluginBase> ctrlBase(controller.get());
if (!ctrlBase || ctrlBase->initialize(hostApp) != kResultOk) controller = nullptr;
@@ -326,13 +315,11 @@ bool Vst3Instrument::loadPlugin(const std::string& path, double sampleRate) {
std::cerr << "[Vst3Instrument] no IAudioProcessor" << std::endl;
return false;
}
std::cerr << "[dbg] loadPlugin: setupProcessing ..." << std::endl;
ProcessSetup setup{kRealtime, kSample32, (int32)maxBlockSize_, sampleRate};
if (processor->setupProcessing(setup) != kResultOk) {
std::cerr << "[Vst3Instrument] setupProcessing failed" << std::endl;
return false;
}
std::cerr << "[dbg] loadPlugin: setActive ..." << std::endl;
if (component->setActive(true) != kResultOk) {
std::cerr << "[Vst3Instrument] setActive failed" << std::endl;
return false;
@@ -342,7 +329,6 @@ bool Vst3Instrument::loadPlugin(const std::string& path, double sampleRate) {
// Build per-bus buffers sized maxBlockSize_ (HostProcessData owns them;
// we must NOT override channelBuffers with external pointers — unprepare
// would delete[] them).
std::cerr << "[dbg] loadPlugin: processData.prepare ..." << std::endl;
if (!s->processData.prepare(*component, (int32)maxBlockSize_, kSample32)) {
std::cerr << "[Vst3Instrument] processData.prepare failed" << std::endl;
return false;
@@ -356,7 +342,6 @@ bool Vst3Instrument::loadPlugin(const std::string& path, double sampleRate) {
outChannels = bi.channelCount;
}
std::cerr << "[dbg] loadPlugin: prepare OK, wiring state" << std::endl;
// SDK EventList default maxSize=50 is far too small for the STOP
// all-notes-off sweep (128 note-offs per channel). addEvent beyond the
// cap fails SILENTLY → notes never released → stuck sound loop.
@@ -554,7 +539,6 @@ bool Vst3Instrument::reloadForGUI() {
// PHAN NAY PHAI chay tren worker thread — apartment cua channel song
// o day; chay tren thread tam thi apartment moi chet ngay sau do
// (reopen lan sau -> treo nhu bridge_like).
std::cerr << "[dbg] openGUI: re-attach - reloading fresh plugin instance" << std::endl;
if (!reload()) return false;
s = static_cast<Vst3HostState*>(state_);
if (!s || !s->controller) return false;
@@ -569,35 +553,21 @@ bool Vst3Instrument::attachView(void* parentWindowHandle) {
return false;
#else
auto* s = static_cast<Vst3HostState*>(state_);
std::cerr << "[dbg] openGUI hwnd=" << (void*)(uintptr_t)parentWindowHandle
<< " controller=" << (s ? (s->controller ? 1 : 0) : -1) << std::endl;
if (!s || !s->controller || !parentWindowHandle) return false;
IPlugView* rawView = nullptr;
tresult qi = s->controller->queryInterface(IPlugView::iid, (void**)&rawView);
std::cerr << "[dbg] openGUI: controller qi IPlugView=" << (int)qi << " raw=" << (void*)rawView << " isSingle=" << (s->controllerIsComponent ? 1 : 0) << std::endl;
FUnknownPtr<IPlugView> view(rawView);
if (!view) {
// Mot so plugin khong expose IPlugView tren edit controller; thu component.
std::cerr << "[dbg] openGUI: controller no IPlugView, trying component" << std::endl;
IPlugView* rawViewC = nullptr;
tresult qic = s->component->queryInterface(IPlugView::iid, (void**)&rawViewC);
std::cerr << "[dbg] openGUI: component qi IPlugView=" << (int)qic << " raw=" << (void*)rawViewC << std::endl;
view = FUnknownPtr<IPlugView>(rawViewC);
}
if (!view) {
// Official editorhost.cpp pattern: IEditController::createView(kEditor).
// JUCE-based plugins (Scaler2) expose the editor only this way.
std::cerr << "[dbg] openGUI: qi failed, trying controller->createView(kEditor)" << std::endl;
view = owned(s->controller->createView(Steinberg::Vst::ViewType::kEditor));
std::cerr << "[dbg] openGUI: createView view=" << (view ? "ok" : "null") << std::endl;
}
if (!view) { std::cerr << "[dbg] openGUI: no IPlugView" << std::endl; return false; }
view->setFrame(&s->plugFrame);
tresult ts = view->isPlatformTypeSupported(kPlatformTypeHWND);
std::cerr << "[dbg] openGUI: isPlatformTypeSupported=" << (int)ts << std::endl;
// Log only — proceed to attach anyway to support non-compliant plugins.
tresult ta = view->attached(parentWindowHandle, kPlatformTypeHWND);
std::cerr << "[dbg] openGUI: attached=" << (int)ta << std::endl;
if (ta != kResultOk) return false;
#ifdef _WIN32
HWND hwnd = (HWND)parentWindowHandle;
@@ -663,9 +633,6 @@ void Vst3Instrument::closeGUI() {
// path out. Callers (post_close_gui / load job) additionally destroy the
// editor's child windows right here on this thread so the plugin stops
// pumping; the leaked editor object is inert once its windows are gone.
if (s && s->view && guiAttached_)
std::cerr << "[dbg] closeGUI: skip view->removed() (Nexus deadlock) view="
<< (void*)s->view << std::endl;
if (s) s->view = nullptr;
guiAttached_ = false;
#endif
@@ -696,8 +663,6 @@ void Vst3Instrument::processAudioBlock(float* outputL, float* outputR, uint32_t
(double)s->processContext.projectTimeSamples / s->processContext.sampleRate *
(s->processContext.tempo / 60.0);
static uint32_t dbgN = 0;
static int dbgMaxShown = 0; // ev>0 blocks printed (raised: sweep must be visible)
// VST3: host buffers must be zeroed (silence) before process — plugins
// that skip output leave garbage otherwise (EZkeys 2 -> huge noise).
if (s->processData.numOutputs > 0) {
@@ -727,19 +692,6 @@ void Vst3Instrument::processAudioBlock(float* outputL, float* outputR, uint32_t
std::memset(outputL, 0, numSamples * sizeof(float));
std::memset(outputR, 0, numSamples * sizeof(float));
}
uint32_t evc = s->eventList.getEventCount();
int evt = -1;
if (evc > 0) {
const Event* e0 = s->eventList.getEventByIndex(0);
evt = e0 ? (int)e0->type : -2;
}
if ((++dbgN % 250) == 0 || (evc > 0 && dbgMaxShown < 5000)) {
if (evc > 0) ++dbgMaxShown;
std::cerr << "[dbg] pid=" << (int)GetCurrentProcessId() << " ch=" << channel_ << " n=" << numSamples << " ev=" << evc << " evt=" << evt
<< " pr=" << (int)pr << " nOut=" << s->processData.numOutputs
<< " mx=" << mx << " ts=" << s->processContext.projectTimeSamples
<< " nch=" << (s->processData.numOutputs > 0 ? s->processData.outputs[0].numChannels : -1) << std::endl;
}
s->eventList.clear();
s->paramChanges.clearQueue();
#endif