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

Convert Audio data in IeeeFloat buffer to PCM in buffer

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

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

我已经想出了如何从 IeeeFloat 转换为 PCM,以及如何在单声道和立体声之间转换。转换采样率是个难题。

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

如果您想在接收数据时重新采样,则需要执行输入驱动的重新采样。前阵子写了an article on this

NAudio 有一些助手 classes 可以从单声道变为立体声,并浮动到 PCM,但它们倾向于在 IWaveProviderISampleProvider 输入上运行。通常,如果我只是将样本作为原始字节块,我会通过自己的简单代码编写从浮点数到 PCM 并将样本加倍。这并不难做到,WaveBuffer class 将允许您直接从 byte[].

读取浮点样本

我最近不得不这样做,但找不到内置的方法来做到这一点,所以我做了马克所说的,手动转换原始数据。下面是对 IeeeFloat(32 位浮点样本)进行下采样的代码,48000 samples/second,2 个通道到 16 位短,16000 samples/second,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);
                    }

                }
            }

        }