使用NAudio重新采样Wav音频数据并转换为原始PCM

时间:2018-05-13 04:39:21

标签: .net wav naudio

我的服务器程序从客户端软件输入音频数据,该软件采用PCM Wave格式,具有正确的RIFF标题(48000 Hz,16位,可以是1或2个通道)。之后,它需要将该数据重新采样为16000 Hz,16位且仅1个通道,但有一个例外:它必须是没有任何RIFF标头的原始PCM数据,以便数据可以传输到要播放的外部服务。此外,该服务将流回相同类型的原始PCM音频数据。因此,程序也需要反向(上采样到48000Hz和RIFF波形)。

目前,我正在使用NAudio完成大部分工作,因为我需要使用二进制数据动态执行该过程,而不是将其保存到文件并处理该文件。

以下是我用于下采样并转换为raw的代码:

var processingData = GetAudioData(); // This is the input audio data in Wav format
using (Stream stream = new MemoryStream(processingData))
{
    using (var wavFileReader = new WaveFileReader(stream))
    {
        var resampler = new WdlResamplingSampleProvider(wavFileReader.ToSampleProvider(), 16000);
        var monoSource = resampler.ToMono().ToWaveProvider16();
        using (var outputStream = new MemoryStream())
        {
            byte[] bytesOutput = new byte[monoSource.WaveFormat.AverageBytesPerSecond];
            while (true)
            {
                int bytesRead = monoSource.Read(bytesOutput, 0, bytesOutput.Length);
                if (bytesRead == 0)
                    break;
                outputStream.Write(bytesOutput, 0, bytesRead);
            }

            var outputData = outputStream.ToArray(); // This is raw PCM data
        }
    }
}

我想知道是否有更好更有效的方法从WavProvider获取原始PCM而不是逐字节读取到MemoryStream。例如,我尝试过ACM重采样器,它是一个WaveStream,因此很容易将流数据复制到内存流,但重采样器无法同时更改采样率和通道数。我希望这部分尽可能快,以便获得原始PCM,并以最小的延迟将其快速发送到外部服务。

同样,这是逆转过程逻辑代码:

var processingData = GetRawData(); // This is the raw PCM data
using (Stream stream = new MemoryStream(processingData))
{
    using (var rawStream = new RawSourceWaveStream(stream, new WaveFormat(16000, 16, 1)))
    using (var upsample = new WaveFormatConversionStream(new WaveFormat(48000, 16, 2), rawStream))
    using (var outputStream = new MemoryStream())
    {
        WaveFileWriter.WriteWavFileToStream(outputStream, upsample.ToSampleProvider().ToWaveProvider16());
        var outputData = outputStream.ToArray();
    }           
}

由于NAudio有一些用于生成Wave数据的实用方法,我使用WaveFileWriter.WriteWavFileToStream方法生成所有必需的RIFF标头,但不是将其保存到文件,而是将数据传输到MemoryStream。我仍然对兼容性有一些担忧,并且这种方式也很有效。我相信WaveFormatConversionStream使用ACM而不是Wdl,因此它可能会对较新的服务器软件/硬件产生一些问题。无论如何,还是像以前那样使用样本Wdl进行此步骤吗?

0 个答案:

没有答案