TASK 4 ship step 4: WASAPI audio capture — NAudio loopback + mic behind an IAudioSource seam, AudioMixer driving AudioLevel while live, pure level meter + WaveToFloat, NAudio.Wasapi 2.2.1 (MIT, notices item 9) — 139 tests passing, 0 warnings

This commit is contained in:
2026-08-12 21:18:07 -07:00
parent ba427e85e1
commit 58c0f8e8c4
16 changed files with 814 additions and 34 deletions
+41
View File
@@ -0,0 +1,41 @@
using NAudio.Dmo;
using NAudio.Wave;
namespace ytLive.Services.Audio;
/// <summary>
/// Converts NAudio's raw WASAPI capture buffers (byte[], whatever bit depth the
/// device's mix format reports) into interleaved PCM float samples. Pure —
/// unit-tested; the two WASAPI sources share it.
/// </summary>
public static class WaveToFloat
{
public static float[] Convert(byte[] buffer, int bytesRecorded, WaveFormat format)
{
if (format.Encoding == WaveFormatEncoding.IeeeFloat && format.BitsPerSample == 32)
return ConvertIeeeFloat(buffer, bytesRecorded);
if (format.Encoding == WaveFormatEncoding.Pcm && format.BitsPerSample == 16)
return ConvertPcm16(buffer, bytesRecorded);
if (format is WaveFormatExtensible extensible
&& extensible.SubFormat == AudioMediaSubtypes.MEDIASUBTYPE_IEEE_FLOAT)
return ConvertIeeeFloat(buffer, bytesRecorded);
return ConvertPcm16(buffer, bytesRecorded);
}
private static float[] ConvertIeeeFloat(byte[] buffer, int bytesRecorded)
{
var count = bytesRecorded / 4;
var result = new float[count];
Buffer.BlockCopy(buffer, 0, result, 0, count * 4);
return result;
}
private static float[] ConvertPcm16(byte[] buffer, int bytesRecorded)
{
var count = bytesRecorded / 2;
var result = new float[count];
for (var i = 0; i < count; i++)
result[i] = BitConverter.ToInt16(buffer, i * 2) / 32768f;
return result;
}
}