音频系统基础入门:采样率、位宽、声道数与 PCM 到底怎么理解

前言:为什么很多人学音视频时,视频那边越看越热闹,音频这边却一直像一团雾

做音视频的人,通常都会有一种很常见的体验:

  • 视频那边的东西很容易“看见”
  • 音频这边的东西却总有点“听说过,但脑子里没画面”

比如很多人对视频会比较容易形成直觉:

  • 分辨率就是 1920x1080
  • 帧率就是 25fps、30fps
  • H.264/H.265 是视频编码
  • I 帧、P 帧、B 帧是预测结构

这些东西相对容易建立图像感。

但一到音频,很多人就开始有点飘:

  • 44.1kHz 和 48kHz 到底差在哪
  • 16bit、24bit 到底在描述什么
  • 单声道、双声道、5.1 声道到底是“几路数据”还是“几个喇叭”
  • PCM 为什么总被当成音频世界的地基
  • AAC、Opus、MP3 到底是怎么从 PCM 变出来的

最常见的问题不是完全没听过,而是:

这些词你都见过,但它们在系统里到底怎么串起来,脑子里并没有一个稳定的模型。

所以这篇文章的目标,就是把音频最底层那几块地基先打牢。

重点讲清:

  • 什么是音频采样
  • 采样率到底在描述什么
  • 位宽到底在描述什么
  • 声道数到底在描述什么
  • PCM 为什么几乎是理解音频系统的起点
  • 这些参数在程序里和数据流里到底怎么体现

而且这篇继续按你强调的方式来,我会放上:

  • 核心关键代码示例
  • 结构图
  • 流程图
  • 时序图

我希望这篇读完之后,你不只是能背“采样率、位宽、声道数”几个定义,而是真能把它们看成一套有结构的数据表达方式。这样后面再去看 AAC、音频播放、音画同步、WebRTC 音频链路,就会顺很多。


一、先给一句最重要的话:音频系统的核心,不是在处理“声音”这个抽象概念,而是在处理“随时间变化的一串采样数据”

如果让我先给一句最重要的话,我会这样说:

音频系统真正处理的,不是“声音”这个抽象东西,而是把声音离散化之后得到的一串按时间排列的采样数据。

这句话特别重要。

因为它直接把“耳朵里的连续声音”翻译成了“程序里的数据对象”。

也就是说,从系统视角看,声音不是一团玄学空气震动,而是:

  • 在某些时刻取一个样
  • 每个样本有一个数值大小
  • 如果有多个声道,就有多路并行样本
  • 这些样本按时间顺序排起来
  • 然后再送去存储、播放、编码、传输

这就是音频工程的地基。


二、先看总图:现实声音是怎么一步步变成程序里的 PCM 数据的

先上总图。

flowchart LR
    A[现实中的连续声音波形] --> B[模数转换 ADC]
    B --> C[按固定时间间隔采样]
    C --> D[每个采样点量化成整数幅值]
    D --> E[得到PCM样本序列]
    E --> F[播放/编码/传输/处理]

这张图其实已经把音频系统最核心的主线说出来了:

  • 现实声音是连续变化的
  • 计算机不直接处理“连续”
  • 所以要把它离散化
  • 离散化之后形成 PCM 数据

也就是说,PCM 不是某种“高级格式”,而更像:

数字音频世界里最基础的原始表达。


三、什么是采样,为什么音频必须先采样

3.1 采样的本质

采样你可以先理解成:

每隔固定一小段时间,去测一次当前声音波形的瞬时幅值。

比如想象你在看一条连续变化的曲线,如果你不可能把整条连续曲线完整搬进计算机,那你最自然的办法就是:

  • 每隔一小段时间取一个点
  • 把这些点记下来
  • 用这些点近似表示整条曲线

音频采样本质上就是这件事。

3.2 为什么必须采样

因为数字系统天然擅长处理的是:

  • 离散的数据
  • 有限精度的数值
  • 一条一条排列的样本序列

而现实声音本质上是连续时间、连续幅值变化的。

所以中间一定需要一个翻译过程。

这个翻译过程的第一步,就是采样。


四、采样率到底是什么,它为什么这么重要

4.1 采样率的定义

采样率(sample rate)说白了就是:

每秒钟采多少个样本。

比如:

  • 8000 Hz:每秒采 8000 次
  • 16000 Hz:每秒采 16000 次
  • 44100 Hz:每秒采 44100 次
  • 48000 Hz:每秒采 48000 次

所以采样率回答的是:

时间维度上,采样点有多密。

4.2 采样率高意味着什么

采样率越高,通常意味着:

  • 时间分辨率更细
  • 能表示的频率范围更高
  • 数据量也会更大

也就是说,它不是单纯“越高越高级”,而是:

更细的时间刻度,换来更多数据量和更强表示能力。

4.3 常见采样率为什么总是这些值

最常见你会见到:

  • 8kHz,电话语音等低带宽场景
  • 16kHz,很多语音识别 / 实时语音场景
  • 44.1kHz,传统音乐音频常见
  • 48kHz,音视频工程、专业音频、视频系统里很常见

所以采样率不只是一个“音质参数”,它还常常和:

  • 业务场景
  • 带宽预算
  • 处理链兼容性

绑在一起。


五、位宽到底是什么,它为什么不是“文件大小位数”那么简单

5.1 位宽的定义

位宽(bit depth)描述的是:

每个采样点用多少比特来表示幅值大小。

比如:

  • 8bit
  • 16bit
  • 24bit
  • 32bit

注意,它不是“每秒多少 bit”,那是码率语境。

它说的是:

单个样本本身有多精细。

5.2 位宽高意味着什么

位宽越高,通常意味着:

  • 每个样本可表示的幅值级别更多
  • 动态范围更大
  • 小信号和大信号之间的刻画更细
  • 数据量也会增加

也就是说,采样率决定“时间上采得多密”,位宽决定“每个点量得多细”。

这两个维度千万别混。

5.3 一个很实用的直觉

你可以先把它理解成:

  • 采样率:横轴切多密
  • 位宽:纵轴量多细

这句话特别值钱。


六、声道数到底是什么,它为什么不是“几个喇叭”这么简单

6.1 声道数的本质

声道数(channels)描述的是:

同一时刻并行存在的音频数据路数。

最常见的是:

  • 1 声道,单声道(mono)
  • 2 声道,双声道(stereo)

所以从数据角度看,声道数更像:

每个采样时刻,是一组值,还是多组并行值。

6.2 为什么不能简单理解成“几个喇叭”

因为扬声器数量是播放系统的物理实现,而声道数是音频数据的组织方式。

两者相关,但不是同一层概念。

比如双声道的本质是:

  • 左声道一条采样序列
  • 右声道一条采样序列

系统里更像是:

1
L0 R0 L1 R1 L2 R2 ...

或者以 planar 方式存放成:

1
2
L: L0 L1 L2 ...
R: R0 R1 R2 ...

这就已经是程序和内存布局问题了,不再只是“两个喇叭”那么简单。


七、PCM 到底是什么,为什么它是音频世界的地基

7.1 PCM 的本质

PCM(Pulse Code Modulation)你可以先把它理解成:

经过采样和量化之后得到的一串原始数字音频样本。

对工程师来说,更直白一点就是:

没有再做压缩编码的原始数字音频数据。

比如常见 PCM 数据可能就是:

  • 16-bit little-endian signed integer
  • 48kHz
  • stereo

这三个条件一起,基本就把一个 PCM 流的核心形态描述得差不多了。

7.2 为什么 PCM 是地基

因为后面很多音频处理,都是围绕 PCM 展开的:

  • 播放器最终通常要喂设备 PCM
  • AAC / MP3 / Opus 编码器通常吃 PCM
  • 音频算法处理常常也在 PCM 层做
  • 混音、重采样、增益调整,本质上也是在样本层处理

所以你可以把 PCM 理解成:

数字音频系统里最基础的“原始工作形态”。


八、一张图看懂采样率、位宽、声道数分别在描述哪一维

flowchart TD
    A[音频数据] --> B[采样率]
    A --> C[位宽]
    A --> D[声道数]

    B --> B1[每秒采多少次]
    C --> C1[每个样本有多精细]
    D --> D1[同一时刻有几路并行数据]

这张图其实就是音频参数最核心的“三板斧”。

以后你看到任何 PCM 格式描述,几乎都可以先从这三项去拆。


九、第一段核心代码:怎么根据采样率、位宽、声道数算 PCM 数据量

这一段特别实用,因为它能一下把抽象参数落回工程量级。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
struct PcmFormat {
int sample_rate; // e.g. 48000
int bits_per_sample; // e.g. 16
int channels; // e.g. 2
};

int BytesPerSample(const PcmFormat& fmt) {
return fmt.bits_per_sample / 8;
}

int BytesPerFrame(const PcmFormat& fmt) {
return BytesPerSample(fmt) * fmt.channels;
}

double BytesPerSecond(const PcmFormat& fmt) {
return static_cast<double>(fmt.sample_rate) * BytesPerFrame(fmt);
}

比如:

1
2
PcmFormat fmt{48000, 16, 2};
printf("bytes/sec = %.0f\n", BytesPerSecond(fmt));

输出大约就是:

1
192000

也就是:

  • 48kHz
  • 16bit
  • 双声道

每秒大约需要 192000 字节。

这段代码最值钱的地方

它让你一下子看到:

采样率、位宽、声道数不是抽象参数,它们直接决定:

数据吞吐量。

这对:

  • 缓冲区设计
  • 音频采集
  • 播放回调
  • 网络带宽预估
  • 编码前数据量分析

都非常关键。


十、第二段核心代码:PCM 缓冲区里的“一个 frame”到底是什么

音频里常说一个 frame,很多人容易跟视频的一帧画面搞混。

这里给个最小代码例子。

1
2
3
4
5
6
7
8
9
10
struct Stereo16Sample {
int16_t left;
int16_t right;
};

void PrintFirstFrames(const Stereo16Sample* data, int frame_count) {
for (int i = 0; i < frame_count; ++i) {
printf("frame %d: L=%d R=%d\n", i, data[i].left, data[i].right);
}
}

这里的 frame 是什么意思

在音频 PCM 语境里,一个 frame 常常表示:

同一采样时刻下所有声道样本的集合。

比如双声道 16bit 下:

  • 一个音频 frame = 一个 left 样本 + 一个 right 样本

所以:

  • sample 往往更强调单个声道上的一个采样值
  • frame 往往更强调同一时刻所有声道的组合

这个概念非常实用,后面看音频 API 时经常会碰到。


十一、第三段核心代码:交错存储和分离存储为什么是音频工程里的高频问题

这块很工程。

11.1 interleaved(交错)

双声道交错存储通常像这样:

1
L0 R0 L1 R1 L2 R2 ...

代码里可以这样访问:

1
2
3
4
5
6
7
void PrintInterleavedStereo(const int16_t* data, int frame_count) {
for (int i = 0; i < frame_count; ++i) {
int16_t left = data[i * 2 + 0];
int16_t right = data[i * 2 + 1];
printf("frame %d: L=%d R=%d\n", i, left, right);
}
}

11.2 planar(分离)

planar 存储更像:

1
2
L: L0 L1 L2 ...
R: R0 R1 R2 ...

代码里可能像这样:

1
2
3
4
5
6
7
void PrintPlanarStereo(const int16_t* left,
const int16_t* right,
int frame_count) {
for (int i = 0; i < frame_count; ++i) {
printf("frame %d: L=%d R=%d\n", i, left[i], right[i]);
}
}

这段代码说明什么

它说明“声道数”这个概念一旦进了程序,不只是一个数字,而会直接影响:

  • 内存布局
  • API 调用方式
  • 算法处理方式
  • 缓冲区拷贝逻辑

这就是为什么音频工程里,数据格式描述必须写完整。


十二、第四段核心代码:一个最小 PCM 生成示例,帮你真正看见“音频样本序列”是什么

我们可以直接生成一个最小正弦波 PCM 数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <cmath>
#include <cstdint>
#include <vector>

std::vector<int16_t> GenerateSineWave(int sample_rate,
double frequency,
double duration_sec,
double amplitude = 0.8) {
int total_samples = static_cast<int>(sample_rate * duration_sec);
std::vector<int16_t> pcm(total_samples);

const double two_pi = 6.283185307179586;
for (int n = 0; n < total_samples; ++n) {
double t = static_cast<double>(n) / sample_rate;
double value = amplitude * std::sin(two_pi * frequency * t);
pcm[n] = static_cast<int16_t>(value * 32767.0);
}
return pcm;
}

这段代码特别值钱

因为它会让你一下看到:

所谓 PCM,本质上真的就是:

一串按时间顺序排列的数字样本。

后面 AAC、Opus、MP3 这些编码器,吃进去的很多时候就是这类样本数据。


十三、一张流程图看懂 PCM 在音频系统里的位置

flowchart TD
    A[Mic / 文件 / 网络输入] --> B[得到PCM样本]
    B --> C1[直接播放]
    B --> C2[做增益/混音/重采样]
    B --> C3[送AAC/Opus编码器]
    B --> C4[做音频分析/算法处理]

这张图想表达的是:

PCM 不是终点,而是数字音频处理的起点。

很多系统动作都建立在 PCM 之上。


十四、一张时序图看懂音频采集回调里系统到底在交付什么

sequenceDiagram
    participant Mic as Audio Device
    participant Driver as Driver/OS
    participant App as Audio App

    Mic->>Driver: 连续采集模拟声音
    Driver->>Driver: ADC + 形成PCM缓冲
    loop periodic callback
        Driver->>App: 一段PCM samples
        App->>App: 播放 / 编码 / 处理
    end

这张图特别适合理解:

音频系统通常不是“一次给你一整首歌”,而是:

周期性地交付一小段 PCM 缓冲。

这点对理解:

  • 低延迟音频
  • 回调大小
  • 缓冲设计
  • 音视频同步

都很重要。


十五、工程里最容易混掉的 4 个问题

问题 1:采样率是不是越高越好

不一定。

更高采样率意味着:

  • 更多数据量
  • 更高处理成本
  • 还要看业务是否真的需要

所以它永远是 trade-off,不是越大越神。

问题 2:位宽和码率是不是一回事

不是。

  • 位宽:单个样本用多少 bit 表示
  • 码率:单位时间总共有多少 bit 流过

两者完全不是一个维度。

问题 3:双声道是不是就等于两个喇叭

不完全是。

双声道本质是两路并行音频数据,至于最后怎么映射到扬声器,是播放系统的事。

问题 4:PCM 是不是编码格式

更准确说,它不是“压缩编码格式”,而是原始数字音频表示方式。

它通常更接近音频世界里的“原材料”。


十六、最后给一句更像工程师的话:别把音频参数当成抽象名词,它们本质上是在定义你的样本数据结构

写到这里,最想落下的一句话其实是:

采样率、位宽、声道数,本质上不是几个需要死记硬背的音频术语,而是在定义你的 PCM 数据到底长什么样。

这句话特别值钱。

因为很多人学音频时最大的问题,就是把这些词学成了标签,而不是结构。

但如果你把它们看成:

  • 时间维度怎么取样
  • 幅值维度怎么量化
  • 并行通道怎么组织

那你对音频数据的理解就会一下变得很工程、很稳定。

后面再去看:

  • AAC
  • Opus
  • 重采样
  • 音频设备回调
  • 音视频同步
  • WebRTC 音频处理

就会顺得多。


十七、总结

最后把这篇收成几句话。

1. 音频系统处理的核心对象,是按时间排列的采样数据

这是数字音频世界最根本的视角。

2. 采样率决定时间上采得多密,位宽决定每个样本量得多细,声道数决定同一时刻有几路并行数据

这三件事构成了 PCM 结构的核心描述。

3. PCM 是数字音频处理的基础工作形态

播放、算法处理、压缩编码,很多都建立在 PCM 之上。

4. 真正需要记住的不是名词,而是数据结构感

也就是:

  • 每秒多少样本
  • 每个样本多少 bit
  • 每个时刻有几路样本

5. 一旦这层地基稳了,后面再看 AAC、音频编码、音频同步、WebRTC 音频链路就会顺很多

如果你愿意,我下一篇建议直接接:

《AAC 在音视频工程中的位置:从 PCM 到压缩音频的主线理解》

这篇会刚好把今天这篇 PCM 地基接上去,而且我也会继续按这个规格放代码和图。


音频系统基础入门:采样率、位宽、声道数与 PCM 到底怎么理解
https://breaker505.github.io/2026/03/13/audio-basics-sample-rate-bit-depth-channels-pcm/
作者
爱发呆的鱼
发布于
2026年3月13日
许可协议