Files
SonicForgeStudio/native_bridge/juce_fx/JuceFxEngine.h
T
admin df4a22b9b4 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.
2026-09-04 10:40:46 +07:00

88 lines
4.1 KiB
C++

// native_bridge/juce_fx/JuceFxEngine.h
// JUCE AudioProcessorGraph engine (G1): đọc input ring → graph (rỗng) →
// ghi output ring. Tách khỏi loop để G2 chỉ thêm plugin vào graph.
#pragma once
#include <cstdint>
#include <memory>
#include <string>
#include <vector>
class JuceFxEngine {
public:
JuceFxEngine();
~JuceFxEngine();
// Không copy.
JuceFxEngine(const JuceFxEngine&) = delete;
JuceFxEngine& operator=(const JuceFxEngine&) = delete;
// Tạo graph mới (input node -> [VST3 theo chain] -> output node).
// sampleRate/blockSize đổi → teardown graph cũ + prepare lại (validate
// header G1). blockSize là kích thước mỗi SHM block (256).
void prepare(uint32_t sampleRate, uint32_t blockSize);
// G2: đặt chain (mảng JSON fx_chain) trước prepare — các slot bypass /
// không phải vst3 / load fail chạy passthrough (latency 0).
void setChain(const std::string& chainJson);
// Audio thread: xử lý n mẫu stereo in-place (n <= blockSize * FXRT_IN_SLOTS).
void process(float* inL, float* inR, uint32_t n);
// Graph latency samples (G1 chain rỗng = 0; G2 = getLatencySamples thật).
uint32_t latencySamples() const;
// Latency thật từng slot theo thứ tự chain (0 = skip/bypass/fail).
std::vector<uint32_t> entryLatencies() const;
// ── Editor host (Phase 2 — Reaper-style): editor của CHÍNH instance DSP
// trong graph, không instance thứ 2 / không feeder. Audio thread
// process() KHÔNG bao giờ chạm editor; mọi thao tác đi qua queue và chỉ
// thực thi trong pumpEditorQueue() trên GUI thread (JUCE message thread).
enum class EditorAction {
Open, // tạo editor (createEditorIfNeeded) cho slot — giữ instance DSP
Close, // huỷ editor, GIỮ instance DSP + state (mở lại nhanh)
Show, // hiện editor + host window (M2)
Hide, // ẩn editor + host window, GIỮ editor+instance (mở lại nhanh)
Resize, // đổi kích thước editor (M2: host window)
Capture // đọc state processor (getStateInformation) -> captured[slot]
};
// Thread-safe (gọi từ bất kỳ thread nào, kể cả ctrl-reader): xếp lệnh.
// w/h dùng cho Open/Resize (kích thước editor mong muốn).
void requestEditor(uint32_t slot, EditorAction action, int w = 0, int h = 0);
// GUI thread (JUCE message thread): drain queue + thực thi lệnh editor.
// Trả true nếu xử lý >= 1 lệnh. Không gọi từ audio thread.
bool pumpEditorQueue();
// Thread-safe đọc: slot có editor đang mở không.
bool isEditorOpen(uint32_t slot) const;
// Thread-safe: lấy + xoá state capture gần nhất của slot (rỗng nếu chưa).
// Raw bytes (chưa base64) — M3 encode khi đẩy về engine Python.
std::string takeCapturedState(uint32_t slot);
// ── GUI host support (M2): GuiHost chạy trên GUI thread dùng các API này
// để attach editor vào host window + teardown an toàn. Header giữ JUCE-free
// (editorHandle trả void* = juce::Component*).
// GUI thread: con trỏ editor Component của slot (null nếu chưa mở). Chỉ
// gọi trên message thread, cùng lúc pumpEditorQueue().
void* editorHandle(uint32_t slot);
// Thread-safe: số slot chain hiện tại (sau prepare; trước = 0).
uint32_t slotCount() const;
// Thread-safe: có editor nào đang mở không (teardown đồng bộ).
bool hasOpenEditor() const;
// Thread-safe: enqueue Close cho MỌI slot đang mở — main thread gọi trước
// engine.prepare()/shutdown() khi GUI thread đang chạy (editor là JUCE
// Component, phải đóng trên message thread; GuiHost chờ + pump).
void closeAllEditors();
// Thread-safe đọc: editor slot đang hiển thị (Show/Hide) không.
bool isEditorVisible(uint32_t slot) const;
void shutdown();
private:
struct Slot; // G2: một mục fx_chain (type/path/presetB64/bypass)
struct Impl;
std::unique_ptr<Impl> impl_;
};