2010年10月份开始到11年一月期间,也就是保研的事定下来以后,根据老师安排,我就在实验室用TI公司的DM642(用的是SSD的开发板)改编了一段用ITU的G.723.1标准的采集和编码、解码和播放程序。主要功能是实现麦克风采集和编码同时进行,解码和话筒播放同时进行。
上图为本实验需要实现的最终原理图:左侧是发送端,用话筒采集话音并实时根据G.723.1编码,编码后的码流通过网络传输给接收端,接收端解码接收到的码流并实时地播放输出给耳机。
但是由于本实验不涉及数据的传输,所以,期望获得的程序只包含发送端的采集和编码程序,以及接收端的解码和播放程序,前者的输出用写入硬盘的PCM文件模拟,后者的输入用从硬盘中读取的PCM文件模拟。
为了确保采集与编码、解码与播放能同时进行,需要满足以下条件:发送端的编码速率V2大于采集速度V1,接收端解码速率V4大于播放速度V3。
1、 用AD芯片TLV320AIC23配合DM642完成音频的采集与播放
音频的采集与播放的原理:TLV320AIC23对输入的模拟信号进行采样、量化和编码,数据自动传给多信道缓冲串行端口McBsp。若要采集声音信息,需用与AIC23采样频率相同的频率从McBsp中取数到DM642的内存中;播放与采集类似:以一定频率将数写入McBsp,McBsp自动将数据传给AIC23,输出到耳机播放。
程序的实现过程:
首先通过I2C总线设置AIC23,通过修改寄存器的值控制用AIC23进行AD和DA转换时的相应功能,包括AD转换的采样率(44.1khz)、麦克风输出的音量等。
在配置McBsp的相关寄存器,控制McBsp的相关功能。
程序采用中断方式采集和播放,属计数器0中断(中断源、中断标志、中断返回标志不明,初步推断中断与AIC23的采样频率有关,中断频率与采样频率相同,另外,试验证明,对McBsp的写操作是中断返回的前提),中断服务子程序实现一次采集和播放。
2、 以G.723.1为标准,在DM642上对音频文件进行编解码。
编码原理,解码原理(略,主要是这都是ITU提供的现成的程序Coder和Decoder,弄清楚函数的输入和输出的是什么数据及其类型之后,拿来用就行了)。
编码程序的接口:编码函数Coder的输入为一帧数据,short Databuff[240],共480字节,输出为char Line[24],共24字节。但是G.723.1编码后的帧格式,总共有三种:24字节的数据率为6.3kbps的帧,20字节的数据率为5.3kbps的帧,4字节的静音插入描述帧SID,这三种帧格式都是以首字的前两个比特来确定的。所以在对编码后的帧进行保存时要注意:先根据Coder()输出Line[24]的前两个比特来确定其帧格式,在按具体的帧格式保存,否则会在解码时出现“所选数据率不匹配”导致的无法解码的问题。编码程序的接口与解码程序的类似,也需要注意上述问题。
3、 优化G.723.1编解码代码,使得采集与编码,解码与播放能同时进行。
为了满足原理图中提出的条件,对发送端与接收端的程序作以下修改:
1、只调用一次fwrite或者fread。这是因为:fwrite和fread函数都是涉及读写硬盘操作的函数,调用周期过长,如果把fwrite或fread放在负责编码或解码的中断子程序中,将会导致没编码或每解码一帧都会调用一次fwrite或fread,大大减缓了编码和解码的速度。所以在本实验中采用一次性调用fwrite或fread,在编码之后将数据从芯片内存一次性写入硬盘,或在解码之前将数据从硬盘一次性读入芯片内存。
2、优化编码函数Coder与解码函数Decod。这是因为:
本实验将G.723.1采集代码与编码代码相结合,试图实现采集和编码同时完成。将程序执行后录得的已编码文件经独立的解码程序解码:发现解码后的文件普遍存在“时间短”——(几分钟的录音播放时只有几秒的时间),“有较长时间的静音间隔”的特点。推断这是由于采样时间设定不合适引起的。
为验证这一推断:试验比较了带Coder的录音和不带Coder的录音,发现带Coder的录音回放的声音断断续续,且时间远小于录音的时间,而不带Coder的录音却不存在这样的现象。此外,还在CCS的软件仿真环境中用Profile选项测定了Coder的执行时间,具体操作(载入.out文件后,选择profile>clock>enable,Profile>setup,enable时钟并将Coder函数使能,Profile>viewer查看全部时间,count是执行次数),得Coder的执行时间是0.007s左右,即每处理240个比特需要0.007s时间,每秒处理20408比特,但是采样率是44.1Khz,设每个采样点用8比特来表示,1s采样352800比特,采样速度比处理速度快十倍以上,说明Coder 程序执行时间过长,导致获得的录音文件断断续续。
为了加快Coder的速度,我们考虑采用C代码优化的方法来优化代码,改善实时录音并播放的情况,采用的具体优化方法如下:
1、 将频繁调用的函数改为宏定义函数,即在头文件中使用#define定义函数,此外,还根据现成的优化代码修改了这些函数,做了简化和删减,在不改变编码效果的前提下提高代码执行效率,效果是,Coder的执行时间从原本的0.007s减少到0.001s。
2、在CCS的Project选项的Build Options选择对编译器进行优化——效果是,Coder的执行时间从0.001s减少到0.0008s。
3、对Coder 中大量出现的循环体进行修改。1)增加循环体内容来减少循环次数,提高执行速度;2)将数组元素用指针表示而不是用下标表示;3)把#pragma MUST_ITERATE( , , )放在循环体之前,告知开发板循环次数,改善软件流水,效果略有改善,Coder的执行时间在0.0007s左右。
3、修改CMD文件,将绝大多数段都放在片内存储器IRAM上,以保证调用周期尽量短。
执行优化代码,达到了实时录音并压缩的功能。解码并播放程序的优化过程与之相似。