namespace ytLive.Services.Audio; /// /// Master output limiter — the last stage before the live mix reaches the /// encoder pipe: a peak ceiling of -1 dBFS so mic + loopback (game + TRAX music) /// can never sum past 0 dBFS and clip in the AAC encode. Instant attack per frame /// (a hot frame is scaled exactly to the ceiling — no overshoot), smoothed release /// toward unity so loud passages don't pump. Pure — unit-tested. /// public sealed class MasterLimiter { /// -1 dBFS: standard streaming headroom for encoder overshoot. public const float Ceiling = 0.891f; private const float Release = 0.005f; private float _gain = 1f; /// The current gain multiplier (≤ 1, so the limiter never boosts). public float Gain => _gain; /// Scales the frame by the current gain. Gain drops instantly to /// ceiling/peak when the frame exceeds the ceiling and recovers /// toward unity slowly. public void Process(float[] samples) { var peak = 0f; foreach (var s in samples) { var abs = MathF.Abs(s); if (abs > peak) peak = abs; } var target = peak > Ceiling ? Ceiling / peak : 1f; if (target < _gain) _gain = target; else _gain += (target - _gain) * Release; for (var i = 0; i < samples.Length; i++) samples[i] *= _gain; } public void Reset() => _gain = 1f; }