1390ad545b
- native_bridge/src/BuiltinFxChain.{h,cpp}: 8 builtin DSP port 1:1 từ
Python _apply_builtin_fx_chain (eq/eqpro/compressor/limiter/exciter/rebalance)
và JS MASTER_MODULE_IO (imager/maximizer). Biquad RBJ DF2T, block-wise
stateful. createBuiltinFx trả nullptr cho gain/normalize (legacy).
- RenderFxJob: FxSlot thêm bfx, parse builtin 8 loại, runBuiltinSlotSafe SEH,
realtimeRunChain nhánh builtin, chainGen()/entryLatencies(), setParam
áp live lên bfx; Vst3Fx latencySamples từ getLatencySamples().
- RealtimeFxLoop: drain ctrl ring (SET_PARAM -> chain.setParam, drop cũ khi
đầy) + REPORT_LATENCY khi gen đổi (ipc->lat[] ring, lastGen).
- FxRealtimeIPC.h: header 18 u32 (72B), ctrl/lat slots 8, FxCtrlCmd 24B,
FxLatReport 8B, static_asserts.
- app/core/fx_realtime.py: mirror header 72B (ctrl_write/read, lat_write/read,
slots), set_param ghi ctrl ring qua _ctrl_enqueue_locked (guard shm),
get_latencies drain lat ring qua _lat_drain.
- tests/test_builtin_fx_golden.py: golden SNR C++ vs Python (8 cases, ngưỡng
30dB) + order test eq/compressor xen kẽ.
- TASKS_DAW_A.md: tick 2.1-2.9.
Test: 136 passed (4 fx_realtime_chain + 8 builtin golden + regression).
65 lines
2.4 KiB
C++
65 lines
2.4 KiB
C++
// native_bridge/include/FxRealtimeIPC.h
|
|
// SHM layout cho fx_vst_bridge --realtime-fx (VST FX xử lý realtime, cloud-FX
|
|
// loop): engine (Python) tạo mapping, bridge mở và chạy vòng lặp audio.
|
|
// Tất cả field u32/float (4-byte) — KHÔNG padding — mirror chính xác bằng
|
|
// ctypes trong app/core/fx_realtime.py.
|
|
#pragma once
|
|
#include <cstdint>
|
|
|
|
#define FXRT_MAGIC 0x46585254u // "FXRT"
|
|
#define FXRT_BLOCK 256
|
|
#define FXRT_IN_SLOTS 4 // engine -> bridge
|
|
#define FXRT_OUT_SLOTS 8 // bridge -> engine
|
|
#define FXRT_CTRL_SLOTS 8 // SET_PARAM commands (engine -> bridge)
|
|
#define FXRT_LAT_SLOTS 8 // REPORT_LATENCY reports (bridge -> engine)
|
|
#define FXRT_STATE_STARTING 0
|
|
#define FXRT_STATE_READY 1
|
|
#define FXRT_STATE_ERROR 2
|
|
|
|
// Header 72 bytes (18 u32) — giữ thứ tự khớp fx_realtime.py.
|
|
struct FxRealtimeHeader {
|
|
volatile uint32_t magic;
|
|
volatile uint32_t state;
|
|
uint32_t sampleRate;
|
|
uint32_t blockSize;
|
|
volatile uint32_t running; // engine set 0 → bridge thoát
|
|
volatile uint32_t heartbeat; // bridge tăng mỗi 100ms (watchdog)
|
|
volatile uint32_t inWrite; // producer: engine
|
|
volatile uint32_t inRead; // consumer: bridge
|
|
uint32_t inSlots;
|
|
volatile uint32_t outWrite; // producer: bridge
|
|
volatile uint32_t outRead; // consumer: engine
|
|
uint32_t outSlots;
|
|
volatile uint32_t ctrlWrite; // producer: engine (SET_PARAM ring)
|
|
volatile uint32_t ctrlRead; // consumer: bridge
|
|
uint32_t ctrlSlots;
|
|
volatile uint32_t latWrite; // producer: bridge (REPORT_LATENCY ring)
|
|
volatile uint32_t latRead; // consumer: engine
|
|
uint32_t latSlots;
|
|
};
|
|
|
|
// SET_PARAM: {slot_idx, key[16], value} — 24 bytes.
|
|
struct FxCtrlCmd {
|
|
volatile uint32_t slot;
|
|
char key[16];
|
|
volatile float value;
|
|
};
|
|
static_assert(sizeof(FxCtrlCmd) == 24, "FxCtrlCmd must be 24 bytes");
|
|
|
|
// REPORT_LATENCY: {slot_idx, samples} — 8 bytes.
|
|
struct FxLatReport {
|
|
volatile uint32_t slot;
|
|
volatile uint32_t samples;
|
|
};
|
|
static_assert(sizeof(FxLatReport) == 8, "FxLatReport must be 8 bytes");
|
|
|
|
struct FxRealtimeIPC {
|
|
FxRealtimeHeader h;
|
|
float inL[FXRT_IN_SLOTS][FXRT_BLOCK];
|
|
float inR[FXRT_IN_SLOTS][FXRT_BLOCK];
|
|
float outL[FXRT_OUT_SLOTS][FXRT_BLOCK];
|
|
float outR[FXRT_OUT_SLOTS][FXRT_BLOCK];
|
|
FxCtrlCmd ctrl[FXRT_CTRL_SLOTS];
|
|
FxLatReport lat[FXRT_LAT_SLOTS];
|
|
};
|