fix GUI VSTi trắng/không load: DPI per-monitor v2 + WS_CLIPCHILDREN + view->onSize() sau attached; restore API manager header/cpp (2596372 xoá nhầm) và deploy exe mới
This commit is contained in:
@@ -9,6 +9,8 @@
|
||||
#define FS_SYNTH (static_cast<fluid_synth_t*>(synth))
|
||||
#define FS_SETTINGS (static_cast<fluid_settings_t*>(settings))
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
|
||||
@@ -187,6 +189,10 @@ bool InstrumentEngineManager::assign(uint32_t channel, InstrumentType type,
|
||||
if (it != channels_.end()) oldInst = std::move(it->second);
|
||||
channels_[channel] = std::move(inst);
|
||||
paths_[channel] = path;
|
||||
// Fresh instance is by construction not reloading — clear the channel
|
||||
// flag so real-time MIDI dispatch (which drops reloading channels)
|
||||
// flows to it again.
|
||||
reloadingCh_[channel] = false;
|
||||
}
|
||||
oldInst.reset();
|
||||
return true;
|
||||
@@ -203,6 +209,7 @@ void InstrumentEngineManager::unload(uint32_t channel) {
|
||||
if (it != channels_.end()) oldInst = std::move(it->second);
|
||||
channels_.erase(channel);
|
||||
paths_.erase(channel);
|
||||
reloadingCh_[channel] = false;
|
||||
}
|
||||
oldInst.reset();
|
||||
}
|
||||
@@ -221,13 +228,86 @@ INativeInstrument* InstrumentEngineManager::get(uint32_t channel) {
|
||||
|
||||
void InstrumentEngineManager::setReloading(uint32_t channel, bool on) {
|
||||
std::lock_guard<std::mutex> lock(mu_);
|
||||
if (channel < 16) reloadingCh_[channel] = on;
|
||||
auto it = channels_.find(channel);
|
||||
if (it != channels_.end()) it->second->setReloading(on);
|
||||
}
|
||||
|
||||
bool InstrumentEngineManager::isReloading(uint32_t channel) const {
|
||||
std::lock_guard<std::mutex> lock(mu_);
|
||||
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_).
|
||||
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);
|
||||
}
|
||||
|
||||
// Real-time MIDI dispatch: hold mu_ for the WHOLE call so assign()/unload()
|
||||
// (map swap + old-instance destruction outside the lock) and reload()/reloadForGUI()
|
||||
// (state_ deleted in place on the worker) can never destroy/free the instance
|
||||
// while dispatch is inside a method on it — use-after-free when loading a new
|
||||
// VSTi while other channels keep playing. Reloading channels are skipped: their
|
||||
// instance is mid-teardown and must not be touched.
|
||||
void InstrumentEngineManager::noteOn(uint32_t channel, uint32_t pitch, float velocity) {
|
||||
std::lock_guard<std::mutex> lock(mu_);
|
||||
if (channelQuiet(channel)) return;
|
||||
auto it = channels_.find(channel);
|
||||
if (it == channels_.end()) return;
|
||||
it->second->noteOn(channel, pitch, velocity, 0);
|
||||
}
|
||||
|
||||
void InstrumentEngineManager::noteOff(uint32_t channel, uint32_t pitch) {
|
||||
std::lock_guard<std::mutex> lock(mu_);
|
||||
if (channelQuiet(channel)) return;
|
||||
auto it = channels_.find(channel);
|
||||
if (it == channels_.end()) return;
|
||||
it->second->noteOff(channel, pitch, 0);
|
||||
}
|
||||
|
||||
void InstrumentEngineManager::controlChange(uint32_t channel, uint32_t cc, uint32_t value) {
|
||||
std::lock_guard<std::mutex> lock(mu_);
|
||||
if (channelQuiet(channel)) return;
|
||||
auto it = channels_.find(channel);
|
||||
if (it == channels_.end()) return;
|
||||
it->second->controlChange(channel, cc, value);
|
||||
}
|
||||
|
||||
void InstrumentEngineManager::programChange(uint32_t channel, uint32_t program) {
|
||||
std::lock_guard<std::mutex> lock(mu_);
|
||||
if (channelQuiet(channel)) return;
|
||||
auto it = channels_.find(channel);
|
||||
if (it == channels_.end()) return;
|
||||
it->second->programChange(channel, program);
|
||||
}
|
||||
|
||||
void InstrumentEngineManager::pitchBend(uint32_t channel, uint32_t bend14) {
|
||||
std::lock_guard<std::mutex> lock(mu_);
|
||||
if (channelQuiet(channel)) return;
|
||||
auto it = channels_.find(channel);
|
||||
if (it == channels_.end()) return;
|
||||
it->second->pitchBend(channel, bend14);
|
||||
}
|
||||
|
||||
void InstrumentEngineManager::allNotesOff() {
|
||||
std::lock_guard<std::mutex> lock(mu_);
|
||||
for (auto& [ch, inst] : channels_) {
|
||||
if (channelQuiet(ch)) continue; // mid-rebuild / editor open: do not touch the instance
|
||||
for (uint32_t n = 0; n < 128; ++n) inst->noteOff(ch, n, 0);
|
||||
}
|
||||
}
|
||||
@@ -242,6 +322,7 @@ void InstrumentEngineManager::renderAll(float* outputL, float* outputR, uint32_t
|
||||
scratchR_.resize(numSamples);
|
||||
}
|
||||
for (auto& [ch, inst] : channels_) {
|
||||
if (channelQuiet(ch)) continue; // editor open on this plugin DLL: do not process
|
||||
std::memset(scratchL_.data(), 0, numSamples * sizeof(float));
|
||||
std::memset(scratchR_.data(), 0, numSamples * sizeof(float));
|
||||
inst->processAudioBlock(scratchL_.data(), scratchR_.data(), numSamples);
|
||||
|
||||
Reference in New Issue
Block a user