M1: engine editor host API (Reaper-style, editor cua CHINH instance DSP trong graph) + selftest
JuceFxEngine: requestEditor/pumpEditorQueue/isEditorOpen/takeCapturedState, queue thread-safe, thuc thi tren GUI thread; shutdown() dong editor truoc graph.clear(); prepare() map slot->processor. juce_fx_bridge link juce_gui_basics; target juce_fx_selftest (khong ship) verify open/close/capture voi VST3 that — PASS tren Focusrite fast-compressor_x64. Tien de M2 (GUI thread + host window).
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
// native_bridge/juce_fx/editor_selftest.cpp
|
||||
// M1 selftest (KHÔNG ship): verify editor host API trên instance DSP thật.
|
||||
// juce_fx_selftest.exe "<path.vst3>"
|
||||
// Main thread = JUCE message thread (initialiseJuce_GUI). Plugin không có
|
||||
// editor (createEditorIfNeeded null) → [FAIL] editor open — thử plugin khác.
|
||||
#include "JuceFxEngine.h"
|
||||
|
||||
#include <juce_audio_processors/juce_audio_processors.h>
|
||||
#include <juce_gui_basics/juce_gui_basics.h>
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
|
||||
static int failures = 0;
|
||||
|
||||
static void check(bool ok, const char* what) {
|
||||
std::printf("%s %s\n", ok ? "[PASS]" : "[FAIL]", what);
|
||||
if (!ok) ++failures;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (argc < 2) {
|
||||
std::fprintf(stderr, "usage: juce_fx_selftest <path.vst3>\n");
|
||||
return 2;
|
||||
}
|
||||
// Escape backslash + quote cho JSON path.
|
||||
std::string path(argv[1]), jpath;
|
||||
jpath.reserve(path.size() + 8);
|
||||
for (char c : path) {
|
||||
if (c == '\\' || c == '"') jpath += '\\';
|
||||
jpath += c;
|
||||
}
|
||||
juce::initialiseJuce_GUI(); // main thread = message thread
|
||||
|
||||
int rc = 1;
|
||||
{
|
||||
JuceFxEngine engine;
|
||||
const std::string chain =
|
||||
"[{\"type\":\"vst3\",\"path\":\"" + jpath + "\",\"bypass\":false}]";
|
||||
engine.setChain(chain);
|
||||
engine.prepare(48000, 256);
|
||||
|
||||
// Negative: slot ngoài chain — pump xử lý nhưng không có editor nào.
|
||||
engine.requestEditor(9, JuceFxEngine::EditorAction::Open);
|
||||
check(!engine.pumpEditorQueue(), "negative: slot 9 ngoài chain -> pump false");
|
||||
|
||||
// Open editor 400x300.
|
||||
engine.requestEditor(0, JuceFxEngine::EditorAction::Open, 400, 300);
|
||||
bool pumped = engine.pumpEditorQueue();
|
||||
// Pump message queue ngắn: editor constructor có thể tạo timer/callback.
|
||||
juce::MessageManager::getInstance()->runDispatchLoopUntil(50);
|
||||
check(pumped, "open: pumpEditorQueue true");
|
||||
check(engine.isEditorOpen(0), "open: isEditorOpen(0) true");
|
||||
|
||||
// Capture state — phải có dữ liệu nếu plugin đã nạp preset mặc định.
|
||||
engine.requestEditor(0, JuceFxEngine::EditorAction::Capture);
|
||||
check(engine.pumpEditorQueue(), "capture: pumpEditorQueue true");
|
||||
std::string cap = engine.takeCapturedState(0);
|
||||
check(!cap.empty(), "capture: takeCapturedState non-empty");
|
||||
std::string cap2 = engine.takeCapturedState(0);
|
||||
check(cap2.empty(), "capture: lần 2 rỗng (đã xoá)");
|
||||
|
||||
// Close — editor đóng, processor + state giữ nguyên.
|
||||
engine.requestEditor(0, JuceFxEngine::EditorAction::Close);
|
||||
check(engine.pumpEditorQueue(), "close: pumpEditorQueue true");
|
||||
check(!engine.isEditorOpen(0), "close: isEditorOpen(0) false");
|
||||
} // ~engine -> shutdown() (đóng editor trước graph) — trước shutdownJuce_GUI
|
||||
|
||||
juce::shutdownJuce_GUI();
|
||||
rc = (failures == 0) ? 0 : 1;
|
||||
std::printf(failures == 0 ? "SELFTEST OK\n" : "SELFTEST FAILED\n");
|
||||
return rc;
|
||||
}
|
||||
Reference in New Issue
Block a user