ALSA音频驱动开发入门指南 - 第2节
一、声音的物理特性:频率与振幅
聊音频驱动,得先从声音本身说起。
声音是什么?说白了就是空气的振动。这种振动有两个关键参数:频率和振幅。
频率:决定音高
频率就是每秒振动的次数,单位是赫兹(Hz)。频率越高,声音越尖;频率越低,声音越沉。
人耳能听到的范围大概是20Hz到20kHz。低于20Hz的叫次声波,高于20kHz的叫超声波。我刚开始做音频驱动时,有个坑——麦克风采集到的数据里经常有50Hz的工频噪声。嗯,那是市电干扰,不是真正的音频信号。
关键点:音频驱动开发中,我们最关心20Hz-20kHz这个范围。采样率的设计就是围绕这个来的。
振幅:决定音量
振幅就是振动的幅度,决定了声音的大小。振幅越大,声音越响。
在数字音频里,振幅被量化成一个个数值。数值范围取决于位深。这个后面会细说。
二、数字音频的核心概念
模拟声音要变成数字信号,得经过三个步骤:采样、量化、编码。这三个步骤对应三个核心参数:采样率、位深、声道。
采样率:每秒采多少个点
采样率就是每秒对模拟信号采样的次数,单位是Hz。比如44.1kHz,就是一秒采44100个点。
为什么是44.1kHz?因为根据奈奎斯特定理,采样率至少要是信号最高频率的两倍。人耳上限20kHz,两倍就是40kHz。CD标准选了44.1kHz,留了点余量。
| 采样率 | 常见用途 |
|---|---|
| 8kHz | 电话语音 |
| 44.1kHz | CD音质 |
| 48kHz | DVD、专业音频 |
| 96kHz | 高解析音频 |
个人经验:我在调试一个USB音频设备时,发现播放声音变调。查了半天,原来是驱动里采样率设成了48kHz,但硬件实际跑的是44.1kHz。这种不匹配会导致音调偏移,听起来像快进或慢放。
位深:每个点用多少位表示
位深决定了每个采样点的精度。16位就是每个点用16个二进制位表示,能表示65536个不同的振幅值。
位深越高,动态范围越大,声音细节越丰富。常见的位深有:
- 8位:早期游戏音效,噪声大
- 16位:CD标准,够用
- 24位:专业录音,动态范围144dB
- 32位:浮点处理,内部计算用
避坑指南:我曾经在移植一个音频驱动时,发现播放出来的声音有爆音。排查了很久,最后发现是位深配置错了。硬件支持24位,但驱动里配成了16位,高位数据被截断,导致波形削顶。嗯,这种问题用耳朵听就能发现,但定位起来挺费劲。
声道:声音的空间感
声道数决定了声音的空间维度。
- 单声道(Mono):一个声道,所有声音混在一起
- 立体声(Stereo):左右两个声道,有空间感
- 多声道:5.1、7.1等,环绕声
在驱动层面,声道数决定了数据排列方式。立体声通常是左右交错排列:L R L R L R ...
三、PCM数据格式
PCM(脉冲编码调制)是最基础的数字音频格式。说白了,就是把模拟信号的振幅值,按时间顺序一个个记录下来。
PCM数据的存储方式
假设我们有一个16位立体声的PCM流,数据排列是这样的:
采样点1: 左声道(16位) | 右声道(16位)
采样点2: 左声道(16位) | 右声道(16位)
采样点3: 左声道(16位) | 右声道(16位)
...
每个采样点占2字节(16位),左右声道交错排列。一秒钟的数据量 = 采样率 × 位深/8 × 声道数。
举个例子:44.1kHz、16位、立体声,一秒钟的数据量是:
44100 × 2 × 2 = 176400 字节 ≈ 172KB
这个计算很重要。我在做音频驱动时,经常要算这个值,用来配置DMA缓冲区大小。缓冲区太小会断流,太大又浪费内存。
PCM的常见变体
- 有符号/无符号:16位PCM通常用有符号数,8位用无符号
- 大端/小端:字节序问题,ARM平台通常是小端
- 交错/非交错:立体声数据是左右交错还是分开存放
个人习惯:我一般默认用小端、有符号、交错格式。这是Linux ALSA最常用的配置,兼容性最好。
四、音频编解码器简介
编解码器(Codec)是音频通路的核心芯片。它负责数模转换(DAC)和模数转换(ADC)。
Codec的主要功能
- DAC:数字信号转模拟信号,驱动耳机或喇叭
- ADC:模拟信号转数字信号,采集麦克风输入
- 混音:多路音频混合
- 音量控制:硬件增益调节
常见的Codec芯片
| 芯片型号 | 特点 |
|---|---|
| WM8960 | 低功耗,常用于嵌入式 |
| ALC5621 | 集成度高,常用于平板 |
| TLV320AIC3x | TI的经典系列,性能稳定 |
我曾经踩过的坑:有一次调试WM8960,播放声音一直没输出。查了三天,最后发现是Codec的电源时序不对。DAC需要先上电,再配置寄存器,最后解除静音。顺序错了,芯片就不工作。嗯,这种问题看数据手册就能避免,但新手容易忽略。
Codec与SoC的连接
Codec通常通过I2S接口与SoC通信。I2S有三条主要信号线:
- BCLK:位时钟,每个bit一个脉冲
- LRCK:左右声道时钟,切换左右声道
- SDATA:串行数据线
驱动开发时,需要配置好这些时钟的频率和极性。配错了,声音就会失真或者完全没声。
小结
这一章我们聊了声音的物理特性、数字音频的三个核心参数、PCM数据格式,还有Codec的基本概念。这些都是音频驱动开发的基础,后面写驱动时会反复用到。
下一章,我们会深入Linux ALSA框架,看看驱动是怎么组织起来的。到时候你会看到,这些基础知识是怎么落实到代码里的。
记住一句话:音频驱动开发,本质上就是配置好采样率、位深、声道数,然后让数据在SoC和Codec之间正确流动。搞懂了这些参数的含义,你就已经迈出了第一步。