You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用NAudio的BiQuadFilter为WAV音频添加低通滤波器并完成处理

音频处理流程实现与NAudio低通滤波器使用问题

需求说明

我需要完成以下音频处理步骤:

  • 提取一个参考音频样本的最大音量峰值,以此为基准对另一个音频文件进行归一化
  • 用截止频率1500Hz的低通滤波器消除音频中的静态噪声
  • 将最终处理后的音频转换为MP3格式

我了解NAudio库中的BiQuadFilter类可实现低通滤波,已经创建了低通滤波器实例,也知道它有一个接收float参数并返回处理后float值的Transform方法,但不确定是否应该直接对从音频文件读取的float样本数据使用该方法。以下是我已经实现的音频归一化和MP3转换方法,希望能得到滤波部分的实现指导。

现有代码

音频归一化方法

void audioNormalizer(string validFile, string inPath, string outPath)
{
    float max = 0;

    using (var reader = new AudioFileReader(validFile))
    {
        // 查找参考音频的最大峰值
        float[] buffer = new float[reader.WaveFormat.SampleRate];
        int read;
        do
        {
            read = reader.Read(buffer, 0, buffer.Length);
            for (int n = 0; n < read; n++)
            {
                var abs = Math.Abs(buffer[n]);
                if (abs > max) max = abs;
            }
        } while (read > 0);
        Console.WriteLine($"Max sample value: {max}");

        if (max == 0 || max > 1.0f)
            throw new InvalidOperationException("File cannot be normalized");
            
        using (var reader2 = new AudioFileReader(inPath))
        {
            reader2.Volume = 1.0f / max;
            string wavOutPath = outPath.Substring(0, outPath.IndexOf(".")) + ".wav";

            //********** 此处需要添加低通滤波逻辑 
            var filter = BiQuadFilter.LowPassFilter(44100, 1500, 1);
            //********** 如何用这个滤波器处理float样本?

            WaveFileWriter.CreateWaveFile(wavOutPath, reader2);
            File.WriteAllBytes(outPath, ConvertToMp3(wavOutPath));
            if (File.Exists(wavOutPath))
            {
                File.Delete(wavOutPath);
            }
        }
    }
}

MP3转换方法

byte[] ConvertToMp3(string path)
{
    byte[] file = File.ReadAllBytes(path);
    var target = new WaveFormat(44100, 16, 1);
    using (var outPutStream = new MemoryStream())
    using (var waveStream = new WaveFileReader(new MemoryStream(file)))
    using (var conversionStream = new WaveFormatConversionStream(target, waveStream))
    using (var writer = new LameMP3FileWriter(outPutStream, conversionStream.WaveFormat, 32, null))
    {
        conversionStream.CopyTo(writer);
        return outPutStream.ToArray();
    }
}

低通滤波实现方案

要正确应用BiQuadFilter,不能直接使用WaveFileWriter.CreateWaveFile读取原始流,需要手动读取音频样本、逐个处理后再写入文件。关键要点和修改后的代码如下:

核心注意事项

  1. 采样率匹配:创建滤波器时必须使用输入音频的实际采样率,不要硬编码44100,可通过reader2.WaveFormat.SampleRate获取。
  2. 多声道处理:如果音频是立体声,每个声道需要单独创建滤波器实例,分别处理左右声道的样本。
  3. 结合音量调整:AudioFileReader的Volume属性会在读取样本时自动应用音量归一化,所以读取到的buffer已经是调整后的样本,可直接进行滤波处理。

修改后的完整归一化方法

void audioNormalizer(string validFile, string inPath, string outPath)
{
    float max = 0;

    using (var reader = new AudioFileReader(validFile))
    {
        // 查找参考音频的最大峰值
        float[] buffer = new float[reader.WaveFormat.SampleRate];
        int read;
        do
        {
            read = reader.Read(buffer, 0, buffer.Length);
            for (int n = 0; n < read; n++)
            {
                var abs = Math.Abs(buffer[n]);
                if (abs > max) max = abs;
            }
        } while (read > 0);
        Console.WriteLine($"Max sample value: {max}");

        if (max == 0 || max > 1.0f)
            throw new InvalidOperationException("File cannot be normalized");
            
        using (var reader2 = new AudioFileReader(inPath))
        {
            reader2.Volume = 1.0f / max;
            string wavOutPath = outPath.Substring(0, outPath.IndexOf(".")) + ".wav";

            // 创建匹配采样率的低通滤波器(立体声需每个声道一个滤波器)
            var filters = new BiQuadFilter[reader2.WaveFormat.Channels];
            for (int i = 0; i < filters.Length; i++)
            {
                filters[i] = BiQuadFilter.LowPassFilter(reader2.WaveFormat.SampleRate, 1500, 1);
            }

            // 手动读取、处理并写入音频
            using (var writer = new WaveFileWriter(wavOutPath, reader2.WaveFormat))
            {
                float[] processingBuffer = new float[4096];
                int bytesRead;
                while ((bytesRead = reader2.Read(processingBuffer, 0, processingBuffer.Length)) > 0)
                {
                    // 逐个样本应用滤波
                    for (int n = 0; n < bytesRead; n++)
                    {
                        // 根据声道索引选择对应的滤波器
                        int channel = n % reader2.WaveFormat.Channels;
                        processingBuffer[n] = filters[channel].Transform(processingBuffer[n]);
                    }
                    // 将处理后的样本写入文件
                    writer.WriteSamples(processingBuffer, 0, bytesRead);
                }
            }

            File.WriteAllBytes(outPath, ConvertToMp3(wavOutPath));
            if (File.Exists(wavOutPath))
            {
                File.Delete(wavOutPath);
            }
        }
    }
}

代码说明

  • 多声道处理:通过n % reader2.WaveFormat.Channels判断当前样本所属声道,使用对应声道的滤波器处理,确保立体声音频的每个声道都得到正确滤波。
  • 缓冲区大小:使用4096大小的缓冲区平衡处理效率和内存占用,可根据实际情况调整。
  • 滤波顺序:先应用音量归一化(由AudioFileReader自动处理),再进行低通滤波,符合你的处理流程。

内容的提问来源于stack exchange,提问作者Pablo Ferrer Lopez

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 04:55:58