Phase 2: BuiltinFxChain C++ (8 DSP) + control ring SET_PARAM/REPORT_LATENCY
- 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).
This commit is contained in:
@@ -166,11 +166,41 @@ int run_realtime_fx_loop(const std::string& jobPath, const std::string& shmName,
|
||||
uint32_t inMask = ipc->h.inSlots - 1;
|
||||
uint32_t outMask = ipc->h.outSlots - 1;
|
||||
uint64_t processed = 0;
|
||||
uint64_t lastGen = 0; // chain generation đã báo latency
|
||||
while (ipc->h.running) {
|
||||
if (parentPid && !parentAlive(parentPid)) {
|
||||
std::cerr << "[RealtimeFxLoop] parent gone — exiting" << std::endl;
|
||||
break;
|
||||
}
|
||||
// SET_PARAM ring (engine -> bridge, Phase 2.8): drain mỗi iteration —
|
||||
// áp dụng vào chain TRƯỚC block kế tiếp. Ring đầy → drop lệnh cũ.
|
||||
while (ipc->h.ctrlRead < ipc->h.ctrlWrite) {
|
||||
const uint32_t cs = ipc->h.ctrlRead & (FXRT_CTRL_SLOTS - 1);
|
||||
const FxCtrlCmd& cmd = ipc->ctrl[cs];
|
||||
const char* kend = std::find(cmd.key, cmd.key + sizeof(cmd.key), '\0');
|
||||
chain.setParam((int)cmd.slot,
|
||||
std::string(cmd.key, (size_t)(kend - cmd.key)),
|
||||
(double)cmd.value);
|
||||
MemoryBarrier();
|
||||
ipc->h.ctrlRead++;
|
||||
}
|
||||
// REPORT_LATENCY (bridge -> engine): chain swap (gen đổi) → báo lại
|
||||
// latency từng slot (builtin=0; VST3=getLatencySamples). Ring 8 —
|
||||
// engine drain định kỳ, đầy thì overwrite (drop cũ).
|
||||
const uint64_t gen = chain.chainGen();
|
||||
if (gen != lastGen) {
|
||||
const std::vector<uint32_t> lats = chain.entryLatencies();
|
||||
for (size_t i = 0; i < lats.size(); ++i) {
|
||||
const uint32_t ls = ipc->h.latWrite & (FXRT_LAT_SLOTS - 1);
|
||||
ipc->lat[ls].slot = (uint32_t)i;
|
||||
ipc->lat[ls].samples = lats[i];
|
||||
MemoryBarrier();
|
||||
ipc->h.latWrite++;
|
||||
}
|
||||
lastGen = gen;
|
||||
std::cerr << "[RealtimeFxLoop] latency reported: " << lats.size()
|
||||
<< " slot(s)" << std::endl;
|
||||
}
|
||||
const uint32_t avail = ipc->h.inWrite - ipc->h.inRead;
|
||||
if (avail == 0) { sleepMs(1); continue; }
|
||||
const uint32_t slot = ipc->h.inRead & inMask;
|
||||
|
||||
Reference in New Issue
Block a user