M2: GUI thread + host window trong juce_fx_bridge (Reaper-style — editor cua CHINH instance DSP)
JuceFxGuiHost: GUI thread rieng chay juce MessageManager runDispatchLoopUntil(10) + tick 30ms inline cadence (JUCE Timer KHONG fire tren GUI thread rieng — da xac minh selftest), PluginWindow (DocumentWindow native 'FX slot N') attach editor, reconcile dong editor+ window, teardown thu tu. runOnGui(): plugin instance phai tao tren GUI thread — JUCE plugin gan MM vao thread tao instance, editor tao thread khac -> treo (M1 chi chay vi main thread vua tao instance vua la message thread); prepare/shutdown bao qua runOnGui. JuceFxLoop: guiHost.start() TRUOC engine.prepare; re-prepare sau waitEditorsClosed(1500); teardown runOnGui(shutdown) truoc stop(). Idle ~0 CPU (khong feeder, khong instance 2). juce_fx_gui_selftest (khong ship) PASS tren purecomp + fast-compressor: open/hide/show/ resize/close, teardown sach; window native chup duoc (PrintWindow). Regression M1 selftest OK.
This commit is contained in:
@@ -196,6 +196,7 @@ struct JuceFxEngine::Impl {
|
||||
juce::AudioProcessor* proc = nullptr; // processor slot (không sở hữu)
|
||||
std::unique_ptr<juce::AudioProcessorEditor> editor; // sở hữu editor (GUI thread)
|
||||
bool open = false;
|
||||
bool visible = true; // M2: trạng thái Show/Hide (GuiHost sync window)
|
||||
std::string captured; // state capture gần nhất (raw)
|
||||
};
|
||||
struct EditorCmd {
|
||||
@@ -256,12 +257,16 @@ bool JuceFxEngine::pumpEditorQueue() {
|
||||
}
|
||||
se.editor.reset(ed); // engine sở hữu editor (M1)
|
||||
se.open = true;
|
||||
se.visible = true; // M2: editor mở = hiển thị (GuiHost mở window)
|
||||
if (c.w > 0 && c.h > 0) se.editor->setSize(c.w, c.h);
|
||||
std::cerr << "[JuceFxEngine] slot " << c.slot << " editor open "
|
||||
<< se.editor->getWidth() << "x"
|
||||
<< se.editor->getHeight() << std::endl;
|
||||
} else if (c.w > 0 && c.h > 0) {
|
||||
se.editor->setSize(c.w, c.h);
|
||||
} else {
|
||||
// Đã mở — Show lại (Reaper: editor còn sống, mở window lại).
|
||||
se.visible = true;
|
||||
se.editor->setVisible(true);
|
||||
if (c.w > 0 && c.h > 0) se.editor->setSize(c.w, c.h);
|
||||
}
|
||||
any = true;
|
||||
break;
|
||||
@@ -278,12 +283,12 @@ bool JuceFxEngine::pumpEditorQueue() {
|
||||
}
|
||||
case EditorAction::Show:
|
||||
case EditorAction::Hide: {
|
||||
// M1: editor chưa attach host window — setVisible chưa đủ. M2
|
||||
// (GUI thread + host window) sẽ xử lý show/hide thật.
|
||||
if (se.editor) {
|
||||
se.editor->setVisible(c.action == EditorAction::Show);
|
||||
any = true;
|
||||
}
|
||||
// M2: GuiHost đồng bộ window theo flag visible (editor setVisible
|
||||
// cho nội dung). Show = hiện window, Hide = ẩn (giữ editor+instance).
|
||||
const bool vis = (c.action == EditorAction::Show);
|
||||
se.visible = vis;
|
||||
if (se.editor) se.editor->setVisible(vis);
|
||||
any = true;
|
||||
break;
|
||||
}
|
||||
case EditorAction::Resize: {
|
||||
@@ -321,6 +326,46 @@ std::string JuceFxEngine::takeCapturedState(uint32_t slot) {
|
||||
return s;
|
||||
}
|
||||
|
||||
void* JuceFxEngine::editorHandle(uint32_t slot) {
|
||||
std::lock_guard<std::mutex> lk(impl_->editorMutex);
|
||||
if (slot >= impl_->editors.size()) return nullptr;
|
||||
return impl_->editors[slot].editor.get();
|
||||
}
|
||||
|
||||
uint32_t JuceFxEngine::slotCount() const {
|
||||
std::lock_guard<std::mutex> lk(impl_->editorMutex);
|
||||
return (uint32_t)impl_->editors.size();
|
||||
}
|
||||
|
||||
bool JuceFxEngine::hasOpenEditor() const {
|
||||
std::lock_guard<std::mutex> lk(impl_->editorMutex);
|
||||
for (const auto& se : impl_->editors)
|
||||
if (se.open) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void JuceFxEngine::closeAllEditors() {
|
||||
// Gom slot đang mở (editorMutex) rồi enqueue Close (queueMutex) — gọi từ
|
||||
// main thread trước khi prepare()/shutdown() khi GUI thread đang chạy.
|
||||
std::vector<uint32_t> open;
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(impl_->editorMutex);
|
||||
for (size_t i = 0; i < impl_->editors.size(); ++i)
|
||||
if (impl_->editors[i].open) open.push_back((uint32_t)i);
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(impl_->queueMutex);
|
||||
for (uint32_t s : open)
|
||||
impl_->editorQueue.push_back({s, EditorAction::Close, 0, 0});
|
||||
}
|
||||
}
|
||||
|
||||
bool JuceFxEngine::isEditorVisible(uint32_t slot) const {
|
||||
std::lock_guard<std::mutex> lk(impl_->editorMutex);
|
||||
if (slot >= impl_->editors.size()) return false;
|
||||
return impl_->editors[slot].open && impl_->editors[slot].visible;
|
||||
}
|
||||
|
||||
void JuceFxEngine::shutdown() {
|
||||
// Đóng mọi editor TRƯỚC khi clear graph — JUCE assert editor phải xoá
|
||||
// trước processor. Editor ops ở đây chạy trên thread gọi shutdown; M1
|
||||
@@ -332,6 +377,7 @@ void JuceFxEngine::shutdown() {
|
||||
if (se.editor) se.editor.reset(); // ~editor -> processor->editorBeingDeleted
|
||||
se.proc = nullptr;
|
||||
se.open = false;
|
||||
se.visible = false;
|
||||
se.captured.clear();
|
||||
}
|
||||
impl_->editors.clear();
|
||||
@@ -468,11 +514,15 @@ void JuceFxEngine::prepare(uint32_t sampleRate, uint32_t blockSize) {
|
||||
// Editor mapping: slot -> processor (Reaper-style — editor dùng ĐÚNG
|
||||
// instance trong graph). Editors cũ đã đóng ở shutdown() khi graph đổi;
|
||||
// chain không đổi (early-return trên) thì editors giữ nguyên + proc sống.
|
||||
impl_->editors.clear();
|
||||
impl_->editors.resize(impl_->slots.size());
|
||||
for (size_t i = 0; i < impl_->pluginNodes.size(); ++i)
|
||||
if (impl_->pluginNodes[i])
|
||||
impl_->editors[i].proc = impl_->pluginNodes[i]->getProcessor();
|
||||
// Lock editorMutex: GUI thread (GuiHost tick reconcile) có thể đang đọc.
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(impl_->editorMutex);
|
||||
impl_->editors.clear();
|
||||
impl_->editors.resize(impl_->slots.size());
|
||||
for (size_t i = 0; i < impl_->pluginNodes.size(); ++i)
|
||||
if (impl_->pluginNodes[i])
|
||||
impl_->editors[i].proc = impl_->pluginNodes[i]->getProcessor();
|
||||
}
|
||||
|
||||
for (int ch = 0; ch < 2; ++ch) {
|
||||
NCh src; src.nodeID = prev->nodeID; src.channelIndex = ch;
|
||||
|
||||
Reference in New Issue
Block a user