// NativeMixer.h — track gain/pan + master brickwall limiter (T13). // // MIRROR server render pipeline (`app/core/render_engine.py` track volume/pan // + `app/core/mastering_engine.py` _apply_limiter): // - track gain: 10^(dB/20) // - pan constant-power: theta = ((pan+1)/2)*pi/2, L *= cos(theta), R *= sin(theta) // (pan == 0 -> unity, khong nhan — dung nhu render_engine.py) // - master: tong cac track (processInPlace ap dung gain/pan roi limiter) // - brickwall limiter: t_lin = 10^(thresholdDb/20) (clamp -24..0, default -1); // k = 1/max(0.02, t_lin); tk = tanh(k); out = tanh(x*k)/tk; roi hard clip [-1,1] // (clip giong render_project sau apply_mastering). // // Audio thread an toan: chi setTrack/setLimiter tu UI thread truoc khi // AudioStart; processInPlace doc state da set, khong lock, khong cap phat. #pragma once #include #include namespace sonicforge { using int32 = int32_t; struct TrackGainPan { float gainLin = 1.0f; // 10^(dB/20) float panL = 1.0f; // cos(theta) float panR = 1.0f; // sin(theta) static TrackGainPan fromDbPan (float gainDb, float pan); }; class NativeMixer { public: // gainDb: -inf..+inf dB; pan: -1..+1 (clamp). Mirrors render_engine.py. void setTrack (const TrackGainPan& t) { m_track = t; } // thresholdDb clamp -24..0, NaN -> -1 (mirror _clamp trong mastering_engine). void setLimiter (bool active, float thresholdDb); // Ap track gain/pan vao buffer roi (neu active) limiter + hard clip [-1,1] // ngay tai buffer (in-place). frames > 0. void processInPlace (float* outL, float* outR, int32 frames) const; bool limiterActive () const { return m_limActive; } private: TrackGainPan m_track; bool m_limActive = false; float m_limK = 1.0f; // 1/max(0.02, t_lin) float m_limTk = 1.0f; // tanh(k) }; } // namespace sonicforge