wip(nexus): debug crash 0xc000041d khi mở GUI Nexus — lưu trạng thái điều tra (attached() hang; probe exact11 PASS, bridge hang; g_engine hypothesis disproven; chờ phân tích waitscan wait-object)

This commit is contained in:
2026-08-14 22:29:45 +07:00
parent 2596372ab1
commit 1964544d2d
18 changed files with 4996 additions and 129 deletions
@@ -8,6 +8,7 @@
#include <map>
#include <mutex>
#include <functional>
#include <memory>
#include <string>
#include <vector>
@@ -72,6 +73,19 @@ public:
INativeInstrument* get(uint32_t channel);
// Real-time MIDI dispatch (audio loop thread). Each call holds mu_ for the
// WHOLE call — lookup + reloading check + instrument call under one lock —
// so a worker thread's assign()/unload() can never swap the map and destroy
// the old instance while dispatch is inside a method on it (use-after-free
// when loading a new VSTi while others play). Events for unassigned or
// reloading channels are dropped (a mid-reload instance must not be touched
// while its worker rebuilds state_ in place).
void noteOn(uint32_t channel, uint32_t pitch, float velocity);
void noteOff(uint32_t channel, uint32_t pitch);
void controlChange(uint32_t channel, uint32_t cc, uint32_t value);
void programChange(uint32_t channel, uint32_t program);
void pitchBend(uint32_t channel, uint32_t bend14);
// Remove and destroy the instrument on `channel` (its destructor may call
// VST terminate — MUST run on the channel worker thread, caller's duty).
// Used by Option B: two live instances of the same plugin DLL (Nexus)
@@ -87,6 +101,16 @@ public:
// teardown never races the audio thread.
void setReloading(uint32_t channel, bool on);
// True while a channel is being rebuilt (instance teardown/reload on its
// worker thread): real-time code drops MIDI for it. Channel-level flag —
// survives the instance swap (the per-instance flag dies with the object).
bool isReloading(uint32_t channel) const;
// Editor-open predicate: while any VST editor is attached, channels whose
// 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();
@@ -103,6 +127,13 @@ private:
std::map<uint32_t, std::string> paths_; // last assigned path per channel
// Per-instrument scratch so engines that overwrite (not mix) stay additive.
std::vector<float> scratchL_, scratchR_;
// Channel-level reload flag (see isReloading) — indexed by MIDI channel.
bool reloadingCh_[16] = {};
// True when the channel's plugin DLL has an attached editor (or its reload
// 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_;
};
#endif // NATIVE_INSTRUMENT_ENGINE_H