将 WasapiLoopbackCapture 缓冲区转换为 PCM
Converting WasapiLoopbackCapture buffer to PCM
我目前正在使用 D#+ 编写一个 Discord 机器人,它应该将通过输出声音设备传来的所有音频发送到语音通道。
使用 NAudio,我可以成功地从设备中捕获音频,我当前的代码看起来有点像这样:
Capture.StartRecording(); // 'Capture' is a WasapiLoopbackCapture object
Capture.DataAvailable += async (s, a) =>
{
await stream.WriteAsync(a.Buffer); // 'stream' is the transmit stream for the Discord connection
};
不幸的是,D#+ 非常具体地要求采样率为 48000 Hz 的 16 位立体声 PCM,这与我发现的 Wasapi Capture Buffer 产生的 IEEE 浮点格式不太一样通过一些阅读。所以我现在知道我必须先将缓冲区转换为所述 PCM 格式,然后才能将其写入传输流。
经过一些研究,我发现了一些像 this one and questions on here like 这样的文章,它们通常似乎都朝着我想要实现的目标的正确方向发展,但不是 相当 ,或者至少我对音频处理太不熟练,无法正确应用它并使其工作。
所以我的问题本质上是,我如何不断地将我从 WasapiLoopbackCapture 缓冲区获取的数据转换为具有所述 PCM 格式的新缓冲区?非常感谢任何帮助!
感谢@GoodNightNerdPride 将我指向 NAudio GitHub 页面上的 this issue。通过那里发布的代码片段,我能够编写这个方法,它可以将缓冲区从 WasapiLoopbackCapture 对象转换为 16 位 PCM 格式。
/// <summary>
/// Converts an IEEE Floating Point audio buffer into a 16bit PCM compatible buffer.
/// </summary>
/// <param name="inputBuffer">The buffer in IEEE Floating Point format.</param>
/// <param name="length">The number of bytes in the buffer.</param>
/// <param name="format">The WaveFormat of the buffer.</param>
/// <returns>A byte array that represents the given buffer converted into PCM format.</returns>
public byte[] ToPCM16(byte[] inputBuffer, int length, WaveFormat format)
{
if (length == 0)
return new byte[0]; // No bytes recorded, return empty array.
// Create a WaveStream from the input buffer.
using var memStream = new MemoryStream(inputBuffer, 0, length);
using var inputStream = new RawSourceWaveStream(memStream, format);
// Convert the input stream to a WaveProvider in 16bit PCM format with sample rate of 48000 Hz.
var convertedPCM = new SampleToWaveProvider16(
new WdlResamplingSampleProvider(
new WaveToSampleProvider(inputStream),
48000)
);
byte[] convertedBuffer = new byte[length];
using var stream = new MemoryStream();
int read;
// Read the converted WaveProvider into a buffer and turn it into a Stream.
while ((read = convertedPCM.Read(convertedBuffer, 0, length)) > 0)
stream.Write(convertedBuffer, 0, read);
// Return the converted Stream as a byte array.
return stream.ToArray();
}
有了这个,使用 D#+ 将通过 WasapiLoopbackCapture
捕获的音频流式传输到 Discord 就这么简单:
var stream = connection.GetTransmitSink();
Capture.StartRecording();
Capture.DataAvailable += async (s, a) =>
{
await stream.WriteAsync(ToPCM16(a.Buffer, a.BytesRecorded, Capture.WaveFormat));
};
我目前正在使用 D#+ 编写一个 Discord 机器人,它应该将通过输出声音设备传来的所有音频发送到语音通道。
使用 NAudio,我可以成功地从设备中捕获音频,我当前的代码看起来有点像这样:
Capture.StartRecording(); // 'Capture' is a WasapiLoopbackCapture object
Capture.DataAvailable += async (s, a) =>
{
await stream.WriteAsync(a.Buffer); // 'stream' is the transmit stream for the Discord connection
};
不幸的是,D#+ 非常具体地要求采样率为 48000 Hz 的 16 位立体声 PCM,这与我发现的 Wasapi Capture Buffer 产生的 IEEE 浮点格式不太一样通过一些阅读。所以我现在知道我必须先将缓冲区转换为所述 PCM 格式,然后才能将其写入传输流。
经过一些研究,我发现了一些像 this one and questions on here like
所以我的问题本质上是,我如何不断地将我从 WasapiLoopbackCapture 缓冲区获取的数据转换为具有所述 PCM 格式的新缓冲区?非常感谢任何帮助!
感谢@GoodNightNerdPride 将我指向 NAudio GitHub 页面上的 this issue。通过那里发布的代码片段,我能够编写这个方法,它可以将缓冲区从 WasapiLoopbackCapture 对象转换为 16 位 PCM 格式。
/// <summary>
/// Converts an IEEE Floating Point audio buffer into a 16bit PCM compatible buffer.
/// </summary>
/// <param name="inputBuffer">The buffer in IEEE Floating Point format.</param>
/// <param name="length">The number of bytes in the buffer.</param>
/// <param name="format">The WaveFormat of the buffer.</param>
/// <returns>A byte array that represents the given buffer converted into PCM format.</returns>
public byte[] ToPCM16(byte[] inputBuffer, int length, WaveFormat format)
{
if (length == 0)
return new byte[0]; // No bytes recorded, return empty array.
// Create a WaveStream from the input buffer.
using var memStream = new MemoryStream(inputBuffer, 0, length);
using var inputStream = new RawSourceWaveStream(memStream, format);
// Convert the input stream to a WaveProvider in 16bit PCM format with sample rate of 48000 Hz.
var convertedPCM = new SampleToWaveProvider16(
new WdlResamplingSampleProvider(
new WaveToSampleProvider(inputStream),
48000)
);
byte[] convertedBuffer = new byte[length];
using var stream = new MemoryStream();
int read;
// Read the converted WaveProvider into a buffer and turn it into a Stream.
while ((read = convertedPCM.Read(convertedBuffer, 0, length)) > 0)
stream.Write(convertedBuffer, 0, read);
// Return the converted Stream as a byte array.
return stream.ToArray();
}
有了这个,使用 D#+ 将通过 WasapiLoopbackCapture
捕获的音频流式传输到 Discord 就这么简单:
var stream = connection.GetTransmitSink();
Capture.StartRecording();
Capture.DataAvailable += async (s, a) =>
{
await stream.WriteAsync(ToPCM16(a.Buffer, a.BytesRecorded, Capture.WaveFormat));
};