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之间正确流动。搞懂了这些参数的含义,你就已经迈出了第一步。