namespace ytLive.Services.Audio; /// /// A tiny stateful linear-interpolation sample-rate converter (TASK 9). NAudio's /// WASAPI capture rate follows the device mix format; the stream needs a fixed /// 48 kHz, so each source normalizes through one of these. Purely a fallback — /// the mic requests 48 kHz float up front, and most loopback mix formats are /// already 48 kHz, in which case is false and the /// chunk passes through untouched. Pure — unit-tested. /// public sealed class TinyResampler { private readonly double _ratio; private double _pos; /// The source sample rate. /// The target sample rate (48 kHz for the stream). public TinyResampler(int inputRate, int outputRate) { if (inputRate <= 0 || outputRate <= 0) throw new ArgumentOutOfRangeException(); _ratio = (double)inputRate / outputRate; } public bool NeedsResampling => Math.Abs(_ratio - 1.0) > 1e-9; /// Converts one interleaved chunk, keeping the phase across calls. public float[] Process(float[] input) { if (!NeedsResampling) return input; var outLen = (int)((_pos + input.Length) / _ratio); var output = new float[outLen]; for (var i = 0; i < outLen; i++) { var inPos = _pos + i * _ratio; var idx = (int)inPos; if (idx >= input.Length) { output[i] = input[input.Length - 1]; continue; } var frac = (float)(inPos - idx); var a = input[idx]; var b = idx + 1 < input.Length ? input[idx + 1] : a; output[i] = a + (b - a) * frac; } _pos += outLen * _ratio - input.Length; return output; } public void Reset() => _pos = 0; }