【问题标题】:Get PCM byte array from MediaFoundationResampler, Naudio从 MediaFoundationResampler、Naudio 获取 PCM 字节数组
【发布时间】:2021-12-20 20:30:17
【问题描述】:

我正在研究一种重新采样 wav 文件的方法,方法如下:

internal byte[] ResampleWav(byte[] rawPcmData, int frequency, int bits, int channels, int newFrequency)
{
    byte[] pcmData;
    using (MemoryStream AudioSample = new MemoryStream(rawPcmData))
    {
        RawSourceWaveStream Original = new RawSourceWaveStream(AudioSample, new WaveFormat(frequency, bits, channels));
        using (MediaFoundationResampler conversionStream = new MediaFoundationResampler(Original, new WaveFormat(newFrequency, bits, channels)))
        {
            //Here should go the code to get the array of bytes with the resampled PCM data
        }
    }
    return pcmData;
}

这里的问题是 MediaFoundationResampler 中没有任何属性可以返回缓冲区的大小。该方法应返回一个仅包含重新采样的 PCM 数据的字节数组。

提前致谢!

--编辑

经过一段时间的工作,我可以得到这个:

internal byte[] WavChangeFrequency(byte[] rawPcmData, int frequency, int bits, int channels, int newFrequency)
{
    byte[] pcmData;
    using (MemoryStream AudioSample = new MemoryStream(rawPcmData))
    {
        RawSourceWaveStream Original = new RawSourceWaveStream(AudioSample, new WaveFormat(frequency, bits, channels));
        using (MediaFoundationResampler conversionStream = new MediaFoundationResampler(Original, newFrequency))
        {

            //Start reading PCM data
            using (MemoryStream wavData = new MemoryStream())
            {
                byte[] readBuffer = new byte[1024];
                while ((conversionStream.Read(readBuffer, 0, readBuffer.Length)) != 0)
                {
                    wavData.Write(readBuffer, 0, readBuffer.Length);
                }
                pcmData = wavData.ToArray();
            }
        }
    }
    return pcmData;
}

“似乎”工作正常,但还有另一个问题,似乎 PCM 数据字节数组大于预期。这是我用该方法测试过的测试之一:

输入设置:

44100Hz
16 Bits
01 Channel 
1846324 Bytes of PCM data

预期(当我使用 Audition、Audacity 和 WaveFormatConversionStream 重新采样相同的 wav 文件时,我得到了这个):

22050Hz
16 Bits
01 Channel 
923162 Bytes

MediaFoundationResampler 结果:

22050Hz
16 Bits
01 Channel 
923648 Bytes

如果我改变 readBuffer 数组的大小,大小会发生巨大变化。

主要问题是 MediaFoundationResampler 没有属性 Lenght 来了解重新采样的 PCM 数据缓冲区的实际大小。使用 WaveFormatConversionStream 代码是这样的,但是质量不是很好:

internal byte[] WavChangeFrequency(byte[] rawPcmData, int frequency, int bits, int channels, int newFrequency)
{
    byte[] pcmData;
    using (MemoryStream AudioSample = new MemoryStream(rawPcmData))
    {
        RawSourceWaveStream Original = new RawSourceWaveStream(AudioSample, new WaveFormat(frequency, bits, channels));
        using (WaveFormatConversionStream wavResampler = new WaveFormatConversionStream(new WaveFormat(newFrequency, bits, channels), Original))
        {
            pcmData = new byte[wavResampler.Length];
            wavResampler.Read(pcmData, 0, pcmData.Length);
        }
    }
    return pcmData;
}

我应该怎么做才能使用 MediaFoundationResampler 获得预期的 PCM 数据数组?

【问题讨论】:

  • 您确定不能使用您方法的参数 frequency 和 newFrequency 计算新长度吗?
  • 嗯,可能是的,但我不确定该怎么做。公式是什么?
  • 如果唯一的变化是采样频率,类似: var NewLength = rawPcmData.Length * (newFrequency / frequency);很可能会有一些长度舍入问题。我不知道这个库,所以这可能是解决您问题的不好方法。
  • 已测试,但不起作用,不知道为什么但给出了零。无论如何,谢谢!
  • 奇怪,我做了一个快速测试,它似乎工作。今晚有时间我会再试一次。

标签: c# wav naudio


【解决方案1】:

免责声明

我不熟悉 NAudio 库,因此可能有更合适的方法。

编辑

仍然不是一个好的答案,似乎仍然偏离了几个字节...... 对代码进行了一些更正,使用 Mark Heath(NAudio 创建者)对此答案发表评论:https://stackoverflow.com/a/14481756/9658671

我暂时将答案保留在这里,因为它可能有助于找到真正的答案,但如有必要,我会编辑或删除它。

/编辑

Audition 生成的文件与您的代码之间的长度差异为 923648 - 923162 = 486 字节,小于您的 1024 缓冲区。

可以通过以下机制来解释:

在最后一次调用 Read 方法时,剩余字节数低于您的缓冲区大小。因此,您得到的不是 1024 字节,而是更少。

但是您的代码仍然添加了一个完整的 1024 字节组,而不是一个较小的数字。这就解释了 486 字节的差异,以及如果您选择其他缓冲区大小,这个数字将会改变。

解决这个问题应该很容易。

来自 NAudio 文档: https://github.com/naudio/NAudio/blob/fb35ce8367f30b8bc5ea84e7d2529e172cf4c381/Docs/WaveProviders.md

Read 方法返回已读取的字节数。这 永远不应超过 numBytes,并且只有在结束时才能小于 到达音频流。 NAudio 播放设备将停止播放 当 Read 返回 0。

所以不要在每次迭代时总是推送 1024 字节,只需推送 Read 方法返回的数字。

另外,来自 Mark Heath 的评论:

缓冲区大小应可配置为精确倍数 WaveStream的块对齐

因此,不要选择“随机”缓冲区大小,而是使用块对齐的倍数。

internal byte[] WavChangeFrequency(byte[] rawPcmData, int frequency, int bits, int channels, int newFrequency, int BlockAlign)
{
    byte[] pcmData;
    var BufferSize = BlockAlign * 1024;
    using (MemoryStream AudioSample = new MemoryStream(rawPcmData))
    {
        RawSourceWaveStream Original = new RawSourceWaveStream(AudioSample, new WaveFormat(frequency, bits, channels));
        using (MediaFoundationResampler conversionStream = new MediaFoundationResampler(Original, newFrequency))
        {

            //Start reading PCM data
            using (MemoryStream wavData = new MemoryStream())
            {
                var ByteCount = 0;
                var readBuffer = new byte[BufferSize];
                while ((ByteCount = conversionStream.Read(readBuffer, 0, readBuffer.Length)) != 0)
                {
                    wavData.Write(readBuffer, 0, ByteCount);
                }
                pcmData = wavData.ToArray();
            }
        }
    }
    return pcmData;
}

【讨论】:

  • 感谢您的回复!,我刚刚测试了它,但是发生了,数组长度是 923040 而不是 923162。:(
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多