22、音频处理与音效:音频重采样、音频混音、均衡器、降噪算法

各位同学,欢迎来到第二十二讲。今天我们要聊的,是音频处理里最“出活”的几个模块——重采样、混音、均衡器和降噪。说实话,这些技术你在手机里天天都在用,只是你没意识到而已。比如你打电话时背景安静了许多,那就是降噪在干活;你听歌时调了个“摇滚”模式,均衡器就上场了。

我个人习惯把音频处理比作“声音的厨房”。原始音频是食材,重采样是切菜,混音是炒菜,均衡器是调味,降噪则是把坏掉的部分挑出去。嗯,这个比喻虽然糙了点,但道理不差。

核心知识点速览:

  • 音频重采样:改变采样率,解决不同设备间的采样率不匹配
  • 音频混音:将多路音频叠加成一路,注意溢出和归一化
  • 均衡器:调整不同频段的增益,改变音色
  • 降噪算法:去除背景噪声,提升信噪比
音频处理与音效核心知识体系 音频处理引擎 音频重采样 音频混音 均衡器 降噪算法 线性插值 / 样条插值 重采样滤波器 采样率转换(SRC) 加法混音 / 归一化 溢出处理 音量平衡 图形均衡器 参数均衡器 IIR/FIR滤波器 谱减法 维纳滤波 深度学习降噪 应用场景:VoIP通话、音乐播放器、直播、录音、语音识别前处理

22.1 音频重采样:让不同采样率的音频“对齐”

音频重采样,说白了就是把一段音频从一个采样率转换成另一个采样率。比如你有一个48kHz的录音,但播放设备只支持44.1kHz,这时候就得重采样。

为什么会需要重采样?我遇到过这样一个项目:手机录制的视频是48kHz音频,但上传到某个短视频平台后,平台要求统一用44.1kHz。如果不做重采样,播放时就会出现音调变化或者卡顿。你想想看,用户录了一段歌,结果放出来变调了,那体验得多糟糕。

重采样的核心原理其实不复杂:

  • 降采样(Downsampling):从高采样率到低采样率。比如48kHz→44.1kHz。需要先做低通滤波,防止混叠失真。
  • 升采样(Upsampling):从低采样率到高采样率。比如44.1kHz→48kHz。需要插值,然后做低通滤波去除镜像。

常用的重采样算法有几种:

算法 质量 性能 适用场景
最近邻插值 极高 实时预览、低功耗设备
线性插值 一般通话场景
样条插值 音乐播放、录音
基于FIR滤波器的SRC 极高 专业音频处理

我的经验:在Android上做重采样,我建议直接用AudioRecordAudioTrack的采样率转换功能,或者用MediaCodec的格式转换。自己手写重采样算法虽然很酷,但容易踩坑——尤其是边界处理和滤波器设计。我曾经在低端机上用线性插值做48kHz到16kHz的降采样,结果高频混叠得一塌糊涂,后来加了抗混叠滤波器才搞定。

22.2 音频混音:把多路声音“叠”在一起

混音,就是把两路或多路音频信号叠加成一路。最常见的场景就是视频通话——你把麦克风采集的声音和系统播放的远端声音混在一起,然后一起发送出去。

混音看起来简单,不就是加法吗?嗯,确实就是加法。但问题在于:

  • 溢出问题:两个16位的PCM样本相加,结果可能超过16位的范围(-32768到32767)。直接截断会产生严重的削波失真。
  • 音量平衡:两路声音音量差异过大,混在一起后小的那路可能被淹没。

我常用的混音策略有几种:

  1. 直接相加后截断:最简单,但失真大。适合音量很小的信号。
  2. 归一化混音:相加后除以路数。比如两路相加除以2,这样不会溢出,但整体音量会下降。
  3. 自适应混音:根据信号峰值动态调整增益。这是工业级方案。

来看一段简单的混音代码示例(C语言风格,Android NDK中常用):

// 两路16位PCM混音,自适应防溢出
void mix_audio(short *out, short *in1, short *in2, int len) {
    for (int i = 0; i < len; i++) {
        int sum = (int)in1[i] + (int)in2[i];
        // 防溢出处理
        if (sum > 32767) sum = 32767;
        else if (sum < -32768) sum = -32768;
        out[i] = (short)sum;
    }
}

注意:上面的代码只是最简单的防溢出。实际项目中,如果两路都是满音量信号,直接相加后截断会产生严重的非线性失真。我建议用“衰减混音”——先各自衰减再相加,比如乘以0.7再加。虽然音量会小一点,但音质好得多。

22.3 均衡器:给声音“调色”

均衡器(EQ)是调整音频不同频段增益的工具。说白了,就是你想让声音更“亮”一点,就提升高频;想让声音更“厚”一点,就提升中低频。

均衡器分两种常见类型:

  • 图形均衡器(Graphic EQ):固定频段,每个频段一个滑块。常见的有10段、31段。适合直观调整。
  • 参数均衡器(Parametric EQ):可以自由设置中心频率、Q值(带宽)和增益。更灵活,但需要专业知识。

实现均衡器的核心是数字滤波器。常用的有:

  • IIR滤波器(无限冲激响应):计算量小,适合实时处理。但相位特性不好。
  • FIR滤波器(有限冲激响应):线性相位,音质好。但延迟大,计算量大。

在Android上,如果你用Java层开发,可以直接用AudioEffect类的Equalizer。但如果你做底层开发(比如NDK),就得自己实现滤波器了。

我踩过的坑:有一次做音乐播放器的EQ功能,我用IIR滤波器实现了10段均衡器。结果在低端手机上,EQ一打开CPU占用率飙升,播放开始卡顿。后来发现是滤波器系数计算太频繁了。解决方案是:只在用户调整EQ时重新计算系数,播放过程中只做滤波运算。嗯,这个优化思路在很多音频处理场景都适用。

22.4 降噪算法:把“噪音”赶出去

降噪,是音频处理里最难也最实用的技术之一。你想想看,你在嘈杂的咖啡馆里打电话,对方却能听清你的声音——这就是降噪的功劳。

降噪算法的核心思路是:把噪声和语音区分开,然后只保留语音。常用的方法有:

  • 谱减法:估计噪声的频谱,然后从原始信号中减去。简单有效,但容易产生“音乐噪声”(一种刺耳的残留噪声)。
  • 维纳滤波:基于统计模型,效果比谱减法好,但计算量大。
  • 自适应滤波:比如LMS(最小均方)算法,适合有参考噪声的场景(比如双麦克风降噪)。
  • 深度学习降噪:用神经网络模型,效果最好,但需要模型推理能力。现在很多手机都内置了NPU来做这个。

在Android平台上,降噪的实现方式有:

方式 优点 缺点 推荐场景
系统自带降噪(硬件) 零延迟,低功耗 不可控,效果固定 通话场景
AudioEffect的NoiseSuppressor API简单,系统级优化 效果一般,延迟较大 录音、直播
NDK自实现(如WebRTC降噪) 可控,效果好 开发工作量大 专业音频App
深度学习模型(TFLite/ONNX) 效果最好 需要NPU,模型大小大 旗舰机、AI应用

我的建议:如果你做的是普通App,直接用NoiseSuppressor就够了。但如果你做的是VoIP或者专业录音软件,我强烈建议用WebRTC的降噪模块——它开源、成熟、效果稳定。我曾经在一个对讲机App里集成过WebRTC的降噪,处理16kHz采样率的音频,效果比系统自带的好一大截。

22.5 实战:把这些技术串起来

好了,理论讲完了。咱们来看一个实际场景:你正在开发一个K歌App,用户用手机麦克风唱歌,同时播放伴奏。你需要做的是:

  1. 采集麦克风音频(通常是48kHz或44.1kHz)
  2. 对采集的音频做降噪处理(去掉环境噪声)
  3. 用均衡器美化人声(比如提升中频,让声音更清晰)
  4. 将处理后人声与伴奏混音
  5. 如果播放设备只支持44.1kHz,而伴奏是48kHz,需要重采样
  6. 输出到扬声器或耳机

你看,这一讲的内容全用上了。每个环节都有坑,但掌握了原理,你就能从容应对。

最后说一句:音频处理这东西,理论重要,但耳朵更重要。多听、多调、多对比,你才能做出真正好听的声音。


公众号:蓝海资料掘金营,微信deep3321