Files
admin 1390ad545b 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).
2026-08-22 19:55:08 +07:00

48 lines
2.2 KiB
C++

// native_bridge/include/BuiltinFxChain.h
// Builtin DSP chain (PLAN_DAW_A.md Phase 2): 8 custom FX được port từ Python
// (render_engine.py `_apply_builtin_fx_chain`) + JS WebAudio (imager/maximizer,
// MASTER_MODULE_IO). Serial, in-place, stereo — engine xử lý TOÀN chain; chạy
// xen kẽ VST3 đúng thứ tự UI trong RenderFxJob (offline) + RealtimeFxChain.
#pragma once
#include <cstdint>
#include <memory>
#include <string>
#include <vector>
// Forward: sheredom JSON object (params). Khai báo để factory dùng.
struct json_object_s;
// Một FX builtin — stateful giữa các block (biquad z1/z2, env compressor...).
class BuiltinFx {
public:
virtual ~BuiltinFx() = default;
// Xử lý 1 block stereo in-place (L/R song song, interleaved-wise).
virtual void process(float* L, float* R, uint32_t n) = 0;
// SET_PARAM (SHM control ring, Phase 2.8): cập nhật tham số live.
// Trả false nếu slot không có param này (gọi từ realtime loop thread,
// cùng thread process → không cần lock).
virtual bool setParam(const std::string& key, double value) { (void)key; (void)value; return false; }
};
// Chain serial các BuiltinFx — giữ NGUYÊN thứ tự thêm vào.
class BuiltinFxChain {
public:
explicit BuiltinFxChain(double sampleRate) : sampleRate_(sampleRate) {}
void add(std::unique_ptr<BuiltinFx> fx, bool bypass);
// Chạy toàn chain serial, in-place.
void process(float* L, float* R, uint32_t n);
bool setParam(int slot, const std::string& key, double value);
size_t size() const { return entries_.size(); }
private:
struct Entry { std::unique_ptr<BuiltinFx> fx; bool bypass = false; };
std::vector<Entry> entries_;
double sampleRate_;
};
// Factory: id ∈ eq|eqpro|imager|maximizer|compressor|limiter|exciter|rebalance
// |gain|normalize (gain/normalize legacy giữ ở RenderFxJob — factory trả
// nullptr cho 2 loại này). params = JSON object (sheredom), có thể null.
std::unique_ptr<BuiltinFx> createBuiltinFx(const std::string& id,
const json_object_s* params,
double sampleRate);