音频基础:声音的物理特性、采样率与位深度、PCM数据格式、音频编解码原理

大家好,我是你们的老朋友。今天咱们来聊聊音频基础。说实话,很多做Android开发的朋友,一开始接触音视频都会觉得有点懵。我当年也是这样,看着一堆术语——采样率、位深度、PCM、编解码——感觉像在看天书。但别怕,这些东西说白了,就是声音从物理世界走进数字世界的那几步路。走通了,后面就顺了。

一、声音的物理特性:从振动到波形

声音的本质是什么?就是振动。你说话,声带在振动;你敲桌子,桌面在振动。这些振动通过空气传播,传到我们耳朵里,我们就听到了声音。

声音有两个核心物理参数:频率振幅

  • 频率:单位是赫兹(Hz),表示每秒振动的次数。频率越高,声音越尖锐;频率越低,声音越低沉。人耳能听到的频率范围大概是20Hz到20kHz。低于20Hz的叫次声波,高于20kHz的叫超声波,咱们耳朵就无能为力了。
  • 振幅:表示振动的幅度。振幅越大,声音越响;振幅越小,声音越轻。我们平时说的“音量”,本质上就是振幅的大小。

你想想看,声音在空气中传播,其实就是一种波——声波。声波有周期、有波长,这些概念在后续的音频处理中会反复出现。我个人习惯把声波想象成水面的涟漪,一圈一圈往外扩散,这样理解起来就直观多了。

核心要点:声音是模拟信号,连续且平滑。而计算机只能处理离散的数字信号。所以,我们需要把模拟的声音“数字化”。这就是采样和量化的由来。

二、采样率与位深度:数字化的两个关键参数

把模拟信号变成数字信号,需要两步:采样量化

1. 采样率

采样率,说白了就是“每秒采多少个点”。单位是Hz(或kHz)。比如44.1kHz,意思就是每秒钟采集44100个样本点。

这里有个著名的定理——奈奎斯特采样定理。它告诉我们:采样率必须大于信号最高频率的两倍,才能无失真地还原信号。举个例子,人耳能听到的最高频率是20kHz,那么采样率至少要40kHz以上。CD音质的44.1kHz就是这么来的。

我在项目中遇到过一个问题:有个同事录了一段语音,采样率设成了8kHz,结果回放时声音闷闷的,高频细节全丢了。为什么?因为8kHz的采样率,理论上只能还原4kHz以下的频率,而人声的很多辅音(比如“s”、“f”)频率都在4kHz以上。嗯,这就是采样率不够的后果。

避坑指南:我曾经在做一个语音识别项目时,为了省存储空间把采样率从16kHz降到了8kHz。结果识别率直接掉了20%。后来我才意识到,语音识别对高频信息很敏感。所以,采样率的选择一定要结合应用场景,不能盲目压缩。

2. 位深度

位深度,也叫采样精度,表示每个样本点用多少位(bit)来表示。常见的位深度有8位、16位、24位、32位。

位深度决定了动态范围——也就是能记录的最轻声音和最响声音之间的差距。16位能提供96dB的动态范围,24位能提供144dB。CD音质用的是16位,而专业录音棚通常用24位甚至32位浮点。

你想想看,位深度越大,能记录的细节就越丰富。但代价也很明显:数据量成倍增加。16位每个样本占2字节,24位占3字节,32位占4字节。在移动设备上,存储和带宽都是稀缺资源,所以需要权衡。

位深度 动态范围 每个样本大小 常见应用
8位 48 dB 1 字节 低质量语音、老式游戏
16位 96 dB 2 字节 CD音质、MP3
24位 144 dB 3 字节 专业录音、高解析音频
32位浮点 理论无限 4 字节 音频处理、DAW内部

三、PCM数据格式:最原始的音频数字表示

PCM,全称是脉冲编码调制(Pulse Code Modulation)。说白了,它就是采样和量化之后得到的原始数字音频数据。没有压缩,没有编码,就是最纯粹的“裸数据”。

PCM数据在内存或文件中的排列方式,有几个关键参数:

  • 声道数:单声道(Mono)、双声道(Stereo)、多声道(5.1、7.1等)。
  • 采样率:前面讲过了。
  • 位深度:前面讲过了。
  • 字节序:大端(Big Endian)还是小端(Little Endian)。Android上通常是小端。
  • 数据格式:有符号整型(signed int)还是无符号整型(unsigned int)。16位PCM通常是有符号的。

举个例子,一段CD音质的立体声PCM数据:采样率44.1kHz,位深度16位,双声道。那么每秒的数据量就是:44100 × 2字节 × 2声道 = 176,400字节,约172KB。一首3分钟的歌,光PCM数据就要30MB左右。这就是为什么我们需要压缩编码。

// Android中,AudioRecord读取PCM数据的典型代码
int bufferSize = AudioRecord.getMinBufferSize(44100, 
    AudioFormat.CHANNEL_IN_STEREO, 
    AudioFormat.ENCODING_PCM_16BIT);
byte[] audioData = new byte[bufferSize];
audioRecord.read(audioData, 0, bufferSize);

注意:PCM数据是“裸”的,没有文件头,没有元数据。如果你把PCM数据直接保存成文件,播放器是不知道采样率、位深度、声道数的。所以通常我们会把它封装成WAV、AIFF等格式,或者直接压缩成MP3、AAC。

四、音频编解码原理:压缩的艺术

为什么要编解码?说白了就是为了省空间、省带宽。PCM数据太大了,不压缩根本没法在网络上传输,也没法在手机上存太多歌。

音频压缩分为两类:无损压缩有损压缩

1. 无损压缩

无损压缩,就是压缩后还能完全还原成原始的PCM数据。常见的格式有FLAC、ALAC、APE。它的原理是利用音频数据中的冗余信息——比如一段静音、重复的波形——用更高效的方式重新编码。

无损压缩的压缩比通常在2:1到3:1之间。也就是说,一首30MB的PCM歌曲,压缩成FLAC大概10-15MB。对于追求音质的发烧友来说,无损是必须的。但在移动端,无损的代价是解码时需要更多的计算资源。

2. 有损压缩

有损压缩,就是丢掉一些人耳不敏感的信息,换来更高的压缩比。常见的格式有MP3、AAC、OGG、Opus。

有损压缩的核心原理是心理声学模型。人耳有一些“听觉掩蔽”特性——比如一个响的声音会盖住旁边一个轻的声音;再比如人耳对某些频率不敏感。有损编码器就是利用这些特性,把那些“听不到”或“不重要”的信息丢掉。

举个例子,MP3的典型压缩比是10:1到12:1。一首30MB的PCM歌曲,压成320kbps的MP3大概只有3-4MB。而128kbps的MP3更是只有1-2MB。当然,码率越低,音质损失越大。

我的经验:在Android开发中,我建议优先使用AAC而不是MP3。为什么?因为AAC在同等码率下音质更好,而且Android系统对AAC的硬件解码支持更完善。我做过一个测试,96kbps的AAC听起来和128kbps的MP3差不多,但文件小了25%。

3. 编解码流程

编码和解码是一对逆过程。编码器把PCM数据压缩成压缩格式(比如AAC),解码器再把压缩格式还原成PCM数据(用于播放)。

在Android中,MediaCodec是处理音视频编解码的核心API。它支持硬件加速,效率很高。我习惯用MediaCodec来做AAC编码和解码,配合AudioTrack播放PCM数据,整个链路非常流畅。

// Android中,使用MediaCodec解码AAC的简化流程
MediaCodec decoder = MediaCodec.createDecoderByType("audio/mp4a-latm");
decoder.configure(format, null, null, 0);
decoder.start();

// 循环:从输入缓冲区喂数据,从输出缓冲区取PCM数据
// 然后喂给AudioTrack播放

五、知识体系总览

说了这么多,咱们来一张图总结一下。这张图展示了音频从物理世界到数字世界的完整链路,以及各个核心概念之间的关系。

音频基础:知识体系总览 物理世界 声音(振动) 频率 · 振幅 · 声波 采样 数字化 PCM数据 采样率 · 位深度 · 声道 编码 压缩编码 MP3 / AAC / FLAC 有损 · 无损 解码 播放 AudioTrack 关键参数与公式 • 数据速率 = 采样率 × 位深度 × 声道数 • 奈奎斯特定理:采样率 ≥ 2 × 最高频率 • 动态范围 ≈ 6.02 × 位深度 + 1.76 (dB) • 常见采样率:8kHz(语音) · 44.1kHz(CD) · 48kHz(视频) • 常见位深度:16bit(消费级) · 24bit(专业级) · 32bit(处理级)

这张图把整个音频数字化的流程串起来了。从物理世界的声音振动,到采样量化变成PCM数据,再到压缩编码成MP3/AAC等格式,最后解码播放。每一步都有它的意义和权衡。

好了,今天的内容就到这里。音频基础是音视频开发的基石,把这些概念吃透了,后面学音频处理、音频录制、音频播放就会轻松很多。记住,采样率、位深度、PCM、编解码——这四个词会贯穿你整个音视频开发生涯。好好消化,咱们下节课见。

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