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;
}