namespace ytLive.Services.Audio; /// /// Computes the smoothed mic level (0..1) from captured samples. Pure — /// unit-tested; the only feeds it and forwards the /// result. RMS-based so it tracks perceived loudness, smoothed so the meter /// does not flicker. /// public sealed class AudioLevelMeter { private const float Smoothing = 0.2f; private float _level; public float Level => _level; /// /// Maps a linear level (0..1) onto the meter's display scale: -60 dBFS..0 dBFS /// spread linearly across 0..1. Linear RMS of real speech or game audio is /// ~0.01..0.1 (-40..-20 dBFS), which leaves a flat (linear) meter looking /// dead; the log scale makes typical levels occupy the bar. /// public static float ToDisplay(float linear) { if (linear <= 0.001f) return 0f; var db = 20f * MathF.Log10(linear); return Math.Clamp(1f + db / 60f, 0f, 1f); } public float Push(AudioSample sample) { if (sample.Samples.Length == 0) return _level; double sumSquares = 0; var count = 0; foreach (var value in sample.Samples) { sumSquares += value * value; count++; } var rms = (float)Math.Sqrt(sumSquares / count); _level = _level * (1 - Smoothing) + rms * Smoothing; return _level; } public void Reset() => _level = 0; }