将IeeeFloat缓冲区中的音频数据转换为缓冲区

时间:2017-03-02 05:30:20

标签: c# naudio pcm wasapi

我使用NAudio捕获声音输入,输入显示为包含IeeeFloat格式声音信息的缓冲区。

现在我在缓冲区中有这些数据,我想以不同的采样率将其转换为PCM。

我已经想出如何从IeeeFloat转换为PCM,还可以在单​​声道和立体声之间进行转换。转换采样率非常困难。

任何解决方案,最好使用NAudio,可以将IeeeFLoat缓冲区转换为选择PCM格式的缓冲区(包括更改采样率)?

2 个答案:

答案 0 :(得分:1)

如果要在接收数据时重新采样,则需要执行输入驱动的重采样。我刚才写了an article on this

NAudio有一些辅助类可以从单声道到立体声,并浮动到PCM,但它们往往在IWaveProviderISampleProvider输入上运行。通常情况下,如果我只是将样本作为原始字节块,我将使用自己的简单代码编写,从浮点数转换为PCM并将样本加倍。这并不难,WaveBuffer类允许您直接从byte[]读取浮动样本。

答案 1 :(得分:1)

我最近不得不这样做,却找不到内置的方法来做,所以我按照Mark所说的去做,手动转换原始数据。下面是对IeeeFloat(32位浮点采样),48000个采样/秒,2个通道到16位短,16000个采样/秒,1个通道进行降采样的代码。

我对某些事情进行了硬编码,因为我的格式是已知的并且是固定的,但是适用相同的原理。

private DownsampleFile()
        {
            var file = {your file}

            using (var reader = new NAudio.Wave.WaveFileReader(file.FullName))
            using (var writer = new NAudio.Wave.WaveFileWriter({your output file}, MyWaveFormat))
            {
                float[] floats;

                //a variable to flag the mod 3-ness of the current sample
                //we're mapping 48000 --> 16000, so we need to average 3 source
                //samples to make 1 output sample
                var arity = -1;

                var runningSamples = new short[3];
                while ((floats = reader.ReadNextSampleFrame()) != null)
                {
                    //simple average to collapse 2 channels into 1
                    float mono = (float)((double)floaters[0] + (double)floaters[1]) / 2;

                    //convert (-1, 1) range int to short
                    short sixteenbit = (short)(mono * 32767);

                    //the input is 48000Hz and the output is 16000Hz, so we need 1/3rd of the data points
                    //so save up 3 running samples and then mix and write to the file
                    arity = (arity + 1) % 3;

                    runningSamples[arity] = sixteenbit;

                    //on the third of 3 running samples
                    if (arity == 2)
                    {
                        //simple average of the 3 and put in the 0th position
                        runningSamples[0] = (short)(((int)runningSamples[0] + (int)runningSamples[1] + (int)runningSamples[2]) / 3);

                        //write the one 16 bit short to the output
                        writer.WriteData(runningSamples, 0, 1);
                    }

                }
            }

        }