0、简要介绍
处理器要处理外界的声音需要将外界的声音(模拟信号)转换成二进制数据(数字信号),这个过程涉及到了一个模拟信号到数字信号的转换过程,完成这个功能的就是ADC芯片,
同样,如果处理器需要对外输出声音,那就就需要将数字信号装换成模拟信号,完成这个功能的就是DAC芯片。
将这两者合起来我们就称之为音频编解码芯片,也就是Audio Codec。其工作流程是:外界的声音(模拟信号)通过麦克风进入Audio Codec中,经由ADC模块将模拟信号转换成数字信号后通过IIS接口送给SOC,SOC对这些数字信号加工后再通过IIS接口传输给Audio Codec,由SOC传来的数字信号中经过DAC模块转换成模拟信号送到耳机或者喇叭放出声音。(另外Audio Codec的控制器是通过IIC进行配置的)
采样:数字音频系统需要将声波波形信号通过adc转换成计算机支持的二进制,这一过程叫做音频采样,采样就是把连续的模拟信号转换成离散的数字信号 。
量化:采样后的值还需要通过量化,也就是将连续的值近似未某个范围内有限多个离散值的处理过程。
编码:计算机的世界里,所有数值都是用二进制表示的,因而我们还需要把量化值进行二进制编码并进行编码压缩。
PCM:俗称脉冲编码调制,是将模拟信号数字化的一种经典方式,得到了非常广泛的应用,比如数字音频在计算机、DVD以及数字电话等系统中的标准格式采用的就是PCM,它的基本原理就是我们上面的几个流程。即对原始模拟信号进行抽样、量化和编码,从而产生PCM流 。
采样率:奈奎斯特定律,采样频率如果是声音频率最高值的两倍,则可以还原出原始声音。(是否可以根据声音频率改变采样率?)人耳所能辨识的声音范围是20-20KHz,所以人们一般都是选用44.1KHz、48KHz或者更高的频率作为采样速率,采样率越高,声音还原越真实,相应产生的文件也就越大。
采样深度:量化是将连续值近似为某个范围内有限多个离散值的处理过程,那么这个范围的宽度以及可用离散值的数量会直接影响到音频采样的准确性,这就是采样深度的意义。
如上图是一个采用4位深度进行量化得到的PCM,因为4bit最多只能表达16个数值(0-15),所以图中最终量化后的数值依次为7、9、11、12、13、14、15等,这样的结果是相对粗糙的,存在一定程度的失真,当位深越大,所能表达的数值范围越广,上图中纵坐标的划分也就越细致,从而使得量化的值越接近原始数据。
声道:一个声道,简单来说就代表了一种独立的音频信号,所以双声道理论上就是两种独立音频信号的混合。具体而言,如果我们在录制声音时在不同空间位置放置两套采集设备,那就可以录制两个声音的音频数据了。后期对采集到的声音进行回放时,通过与录制时相同数量的外放扬声器来分别播放各声道的音频,就可以尽可能的还原出录制现场的真实声音了。
数字音频格式
不压缩的格式:PCM数据就是采样后得到的未经压缩的数据,PCM数据在Windows和Mac系统上通常分别以wav和aiff后缀进行存储,可想而知,这样的文件大小是比较客观的。
无损压缩格式:这种压缩的前提是不破坏音频信息,也就是说后期可以完整还原出原始数据。同时它一定程度上可以减小文件体积。比如FLAC、APE、WV、m4a等
有损压缩格式:无损压缩技术能减小的文件体积相对有限,因而在满足一定音质要求下,可以进行有损压缩。其中最为人熟知的就是mp3格式,另外还有iTunes上使用的AAC,这些格式通常可以指定压缩的比率,比率越大,文件体积越小,但效果也越差。
常见音频格式
WAV格式,是微软公司开发的一种声音文件格式,也叫波形声音文件,是最早的数字音频格式,被Windows平台及其应用程序广泛支持,压缩率低(无压缩)。
MP3格式, 全称是MPEG-1 Audio Layes 3 。在1992年合并到MPEG规范中,Mp3能够以高音质,低采样率对数字音频文件进行压缩,应用最普遍。
WMA格式,Windows Media Audio 是微软在互联网音频,视频领域的力作,WMA格式是以减少数据流量但保持音质的方法来达到更高的压缩率目的的,其压缩率一般可以达到1:18.此外,WMA还可以通过DRM 保护版权。
1、采样频率
采样的过程就是将通常的模拟音频信号的电信号转换成二进制码0和1的过程,这些0 和 1便构成了数字音频文件。下图中正弦曲线代表了原始音频曲线,方格代表采样后得到的结果。二者越吻合说明采样结果越好。
采样频率就是每秒钟采样的次数,我们通常说的44.1kHz采样频率就是每秒钟采样44100次,如上图,当采样频率越高的时候,数字信号越能反应模拟信号的曲线图,转换的精度越高。
2、Linux 下的音频框架
linux平台下提供了两种主要的音频驱动框架:OSS以及ALA。
OSS(open sound system)
早期linux版本采用的是oss框架,它也是unix即类unix系统中广泛使用的一种音频体系,oss既可以指oss接口本身,也可以用来表示接口的实现,但是oss框架的源码不是开源的,这也是linux内核最终放弃oss的一个原因。另外,oss的某些方面也遭到人们的质疑,比如:对新音频特性的支持不足,缺乏对最新内核的支持等。但是,oss作为unix下统一音频操作的早期实现,本身算的上是很成功的,它符合一切皆是文件的设计理念。而且作为一种体系框架,其更多的只是规定了应用程序与操作系统音频驱动间的交互,因而各个系统可以根据实际需求进行定制开发,其用到了如下所示的设备节点:
ALSA(Advanced Linux Sound Architecture)
ALSA是linux社区为了取代OSS而提出的一种框架,是一个源代码完全开放的系统,ALSA在kernel 2.5版本中被正式引入后,OSS就逐步被排除在内核之外了,当然OSS本身还是在不断维护的,只是不再为内核所采用而已。
ALSA相对于OSS提供了更多,也更为复杂的API接口,因而开发难度相对来说也加大了一些,为此,ALSA专门提供了一个供开发者使用的工具库,以帮助它们更好的使用ALSA的API,根据官方文档的介绍,ALSA具有如下特性:
1、高效支持大多数类型的Audio interface
2、高度模块化的声音驱动
3、SMP及线程安全设计
4、在用户空间提供了alsa-lib 来简化应用程序的编写
5、与OSS API保持兼容,这样可以保证老的OSS程序在系统中正确的运行
2.1 ALSA 在linux内核的目录框架:
core ALSA驱动的中间层,它是整个ALSA驱动的核心部分
oss 包含模拟旧的OSS架构的PCM和Mixer模块(RK代码中未编译)
seq 有关音时序器的驱动代码(RK代码中未编译)
sound.c ALSA驱动的入口 (完成了snd_fops的注册,其中只有一个成员.open = snd_open(这个snd_open是个引子,会调用到snd_minors[]去调用新的file_oprations.另外在sound.c的入口函数中还完成了register_chrdev,对应的class_create在sound_core.c中完成)
control.c 通过snd_ctl_dev_register注册了一个sound contorl逻辑单元,其设备的名字是controlC%i,并完成了一个opration填充到了snd_minors[]中,给sound.c的入口函数中的snd_open调用。
pcm.c 通过snd_pcm_dev_register创建了一个sound pcm逻辑单元,其设备的名字是pcmC%iD%i(p/c),并完成了一个opration填充到了snd_minors[]中,给sound.c的入口函数中的snd_open调用。
drivers 与CPU、BUS架构无关的公用代码
aloop.c
soc 针对system-on-chip体系的中间层代码
generic simple card framework 通用方式创建声卡
simple-card.c rk的代码在这里完成了struct snd_soc_card snd_card的创建(asoc架构)
rockchip
rockchip_i2s.c CPU的i2s接口驱动
codecs
rk817_codec.c codec驱动
last.c
sound_core.c
完成了class_create,跟sound.c中的register_chrdev对应。
soun_firmware.c
2.2 ALSA 的代码框架:
主要的实现分成三个部分:mahine、platform、codec
mahine:单板相关、表明platform是哪个、cpu DAI接口是哪个、表明codec是哪个、codec的DAI接口是哪个、dma是哪个
platform:CPU DAI(初始化iis模块)、DMA(数据传输)
codec:Codec DAI 、 控制接口
2.2.1 Machine
核心是注册一个 struct snd_soc_card结构体。指定了platform、CPU DAI、codec、codec DAI、dma等。
这部分实现在soc_core.c中完成。
代码调用路径:
snd_soc_init--->
platform_driver_register(&soc_driver)--->
.probe = soc_probe,--->
struct snd_soc_card *card = platform_get_drvdata(pdev); --->
snd_soc_register_card(card);
注意:在rk1808这个单板中上述过程没有被调用到。这一过程在simple-card.c中完成,路径如下:
module_platform_driver(asoc_simple_card)--------->
.probe = asoc_simple_card_probe ---------->
ret = devm_snd_soc_register_card(&pdev->dev, &priv->snd_card)---------->
ret = snd_soc_register_card(card);
2.2.2 platform
这部分包括两个部分cpu dai 以及dma,这个驱动在上面的machine部分被struct snd_soc_card指定(name),通过这个name可以找到cpu dai 以及 dma的具体实现。
simple-audio-card,cpu {
sound-dai = <&i2s1>;
};
simple-audio-card,codec {
sound-dai = <&rk809_codec>;
};
通过DTS的信息可以看出,cpu dai 用的是i2s1接口:
i2s1: i2s@ff7f0000 {
compatible = "rockchip,rk1808-i2s", "rockchip,rk3066-i2s";
reg = <0x0 0xff7f0000 0x0 0x1000>;
interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cru SCLK_I2S1_2CH>, <&cru HCLK_I2S1_2CH>;
clock-names = "i2s_clk", "i2s_hcl