【问题标题】:Converting WasapiLoopbackCapture buffer to PCM将 WasapiLoopbackCapture 缓冲区转换为 PCM
【发布时间】:2021-04-04 15:15:46
【问题描述】:

我目前正在使用 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#+ 非常具体地要求 16 位立体声 PCM 的采样率为 48000 Hz,这与 Wasapi Capture Buffer 产生的 IEEE 浮点格式不太一样,正如我通过一些发现的那样读。所以我现在知道我必须先将缓冲区转换为上述 PCM 格式,然后才能将其写入传输流。

经过一番研究,我发现了一些像this one 这样的文章和像this one 这样的问题,这些似乎都朝着我想要实现的正确方向发展,但不是完全,或者至少我对音频处理太不熟练,无法正确应用它并使其工作。

所以我的问题本质上是,我怎样才能不断地将我从 WasapiLoopbackCapture 缓冲区获取的数据转换为具有所述 PCM 格式的新缓冲区?非常感谢任何帮助!

【问题讨论】:

  • 你试过var sp = Capture.ToBufferedWaveProvider().ToSampleProvider(); sp.Read(buffer, ...)吗?一旦你有了ISampleProvider,你也可以像this一样重新采样。
  • BTW this lib/tool 确实将 WasapiLoopbackCapture 转换为 PCM 流。也许你会在那里找到解决方案。
  • @GoodNightNerdPride 你提到的方法似乎专门来自这个DTMF​​音调检测库,我不得不说我也不太明白它是如何将WasapiLoopbackCapture转换为PCM的,看起来它只是改变了采样率,并可选择将音频减少到单个通道。那不仍然是IEEE格式吗? (抱歉,这感觉像是一个完全的菜鸟问题,我对 C# 中的音频处理非常陌生!)
  • 我想你已经看过this了?我对使用 NAudio 实现的复杂程度感到惊讶......
  • @GoodNightNerdPride 你知道吗,我已经看到了,但是因为代码似乎到处都是,所以我在看到 @GoodNightNerdPride 后有点忽略了它987654330@ 显然是解决此问题的类在当前版本的 NAudio 中无法访问。但是我回到了他们之前的步骤,并且实际上编写了一个进行转换的工作方法!非常感谢您再次将我指向这个方向,我会在一分钟内发布代码。

标签: c# naudio dsharp+


【解决方案1】:

感谢 @GoodNightNerdPride 在 NAudio GitHub 页面上将我指向 this issue。通过上面贴的代码 sn-ps,我可以编写这个方法,它可以将缓冲区从 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));
};

【讨论】:

    猜你喜欢
    • 2017-07-21
    • 2012-12-03
    • 2021-01-14
    • 2022-08-05
    • 2020-04-26
    • 2018-06-29
    • 2023-03-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多