Android原生AudioEffect框架分析与改进

2019-10-11 07:292
福建工程学院学报 2019年4期
关键词:均衡器位数移位

2

(1.福建工程学院 信息科学与工程学院,福建 福州 350118;2.福建工程学院 微电子技术研究中心,福建 福州 350118)

音频系统是Android多媒体功能中重要的组成部分。已公开的关于音效处理的研究文献大多是单独研究音效算法[1-2]或是结合DSP芯片开发[3-5],Android系统音频相关的文献目前多数集中在编解码方面,音效处理方面的较为欠缺[6-7]。Android系统源代码体系庞大,现有分析Android系统源代码以及底层开发类的书籍资料多是从整个系统的宏观角度出发,具体功能实现分析方面的书籍资料较少。本研究分析Android音频系统的源码发现,Android对于音效处理的支持还存在仅支持16 bit音频数据处理的问题。其数字音频系统分辨率取决于音频数据采样的量化位深,对于有限的量化技术而言,将连续的模拟信号完整表示出来几乎不可能,故量化值与实际值之间便会产生误差,称为量化误差[8]。理想情况下,16 bit音源量化下,1 个量化间隔存在的误差大约存在 0.001 53% 的失真,24 bit 下大约为 0.000 03%,而32 bit存在的量化误差则更小[9]。许多音乐发烧友更倾心于32 bit音源,仅支持16 bit音频数据的处理已经无法满足大众对音质的追求,所以需对Android音频系统进一步完善,使其对32 bit的音源提供支持[10]。

音频数据采用PCM编码,一般采用自然二进制码或格雷码[11]。一般的二进制码的编码规则在将32 bit数据进行强制位数转换为16 bit数据时,保留下来的为低位的数据,但高位的数据较之更为重要。本文采取先对输入数据进行移位操作,将高位数据移至低位后,再进行强制位数转换,保留高位数据,丢弃低位数据。另外,对于音频数据来说,输入为32 bit的音频数据,输出时也应为32 bit的数据,否则输出的音频数据会存在一定的误差[8]。当数据处理完成后还原为32 bit进行输出可将量化位深转换带来的误差控制在约为0.000 76%左右[9]。

1 Android原生Audio Effect框架分析

在Android源代码中,打开日志输出功能的方法为#define LOG_TAG "XX"以及#define LOG_NDEBUG 0这两条语句,打开后在适当的地方调用ALOGV()函数即可将指定的内容在运行日志中输出。由于Android的音频系统较为复杂庞大,故改进Android原生Audio Effect框架必需对原生Audio Effect框架进行深入分析。通过日志输出文件可得知,Android原生Audio Effect框架主要分为三个部分,即音效创建、命令执行及音效处理。

1.1 音效创建

Android系统中,使用原生Audio Effect框架必须先进行初始化,定义必要的参数,音效创建便是做此用途。在框架中,音效创建为EffectCreate部分。其主要调用框架中的两个初始化操作,分别为LvmGlobalBundle_init以及LvmBundle_init两部分。具体是先调用LvmGlobalBundle_init进行全局初始化,这部分主要是初始化全局内存,再通过LvmBundle_init进行框架初始化,这部分主要是使用默认配置初始化引擎,创建禁用所有效果的初始化实例。从此部分代码的默认配置中能够看出,原生框架仅支持16 bit音频数据的处理,如表1中第5以及第13行加粗代码所示,inputCfg.format以及outputCfg.format都为AUDIO_FORMAT_PCM_16_BIT。当然,EffectCreate部分还有其他如匹配音效模式(重低音、环绕声、均衡器等)来开启对应的音效功能。

表1 LvmBundle_init部分代码Tab.1 Part of the LvmBundle_init code

1.2 命令执行

在原生Audio Effect框架中,命令执行部分为Effect_command,它包含框架中除了数据处理部分之外其他调用。Effect_command部分中包括了音效的生效、各类参数的获取和设置、以及音效的释放等等部分,其中各类参数的获取和设置是通过在Effect_command中调用框架里的Equalizer_getParameter以及Equalizer_setParameter部分,可获取框架中所需的中心频率、频段、增益以及预设值等参数。从输出日志可见,这部分一直处于线程中,均衡器每改变一次的频段增益,都会重新执行一次Equalizer_getParameter以及Equalizer_setParameter来使用户设置的均衡器增益生效。图1为Effect_command部分主要的跳转过程。

图1 Effect_command主要跳转流程Fig.1 Major jump flow of Effect_command

1.3 音效处理

当框架初始化以及各类参数配置完成后,系统便会根据用户选择的模式对音频数据进行相应的处理了。原生Audio Effect框架中音效处理部分是在Effect_process中,这部分主要是对输入的音频数据根据用户需要进行相应计算,即对音频数据进行处理并输出。通过阅读相关代码可知,Effect_process部分会调用框架里的LvmBundle_process部分,这个部分也可以看出Audio Effect框架仅支持16 bit数据的处理,如表2中第1以及第2行代码所示。在LvmBundle_process中继续调用外部的LVM_process,一层层往下调用进行,直到获取到对应的数据处理的具体实现方法,并对输入的音频数据进行处理。这也是Android系统代码结构的一大特点,封装成多层,这样有助于减少耦合,便于后期的代码维护。图2为音效处理部分的主要代码跳转情况示意图。

表2 LvmBundle_process部分代码Tab.2 Part of the LvmBundle_process code

图2 音效处理部分主要代码跳转情况Fig.2 Major code jumps in the audio processing section

2 Android原生Audio Effect框架改进方案设计

2.1 改进Audio Effect框架代码实现

由于32 bit音频数据在精度上对于16 bit音频数据会高出许多,故将32 bit转换为16 bit处理完成后,还应将处理结果还原为32 bit音频数据进行输出。在音频数据编码中,每一个二进制数对应一个量化电平,将它们依序排列,得到由二进制脉冲串组成的数字信息流[2]。图3为二进制数示意图,其中d只能为1或0,且每一位取值可相同。根据二进制与十进制的转换公式(1)可知,显然高位的数据在输出时相对于低位的数据来说更为重要,若不加处理直接进行强制的数据位数转换,易造成处理所得音频数据出现严重的失真现象。

图3 二进制数示意图Fig.3 Binary number diagram

(N)10=dn*2n-1+dn-1*2n-2+…+d2*21+d1*20

(1)

式中,N为二进制转换为十进制的结果,dn、dn-1、…、d2、d1为二进制各位的系数,n即为位数,位数从右至左依次为1、2、…、(n-1)、n。

为保留音频数据大部分信息,减轻音频数据由于位数转换造成的失真现象,采取先将音频数据进行移位操作,保留音频数据的高位数据,丢弃低位数据,移位操作完成后再进行位数的强制位数转换操作。经过强制位数转换操作后,32 bit音频数据便转换为16 bit音频数据,此时数据即可通过Android原生Audio Effect框架处理。该移位操作关键的代码如表3所示。

表3 移位操作关键代码Tab.3 Key code of the shift operation

上述代码中,temp为临时数据,src为原始数据,dst为转换后的数据。32 bit音频数据转换为16 bit音频数据,保留高位数据,故需进行右移操作,由于是将32 bit音频数据转换为16 bit音频数据,故右移位数为16位,保留高16位数据,且16位int型的数据可表示范围为-32 768~32 767,故移位后还需注意该数值是否超出16位的数据范围,如若超出,应在保留尽可能多的数据的前提下,将其取值为16位int型数据可表示范围内的数值,上述代码中的两个if语句其功能便是判断移位后数据是否超出16位可表示的范围,若超出则根据保留尽可能多的数据的前提进行取值;若未超出,便直接强制位数转换。

音频数据在位数转换完成后,经过Audio Effect框架处理,处理结束后还需将其转换为32 bit的音频数据再进行输出,否则所听到的音乐将会存在极大程度的失真。具体的实现方法与上述将32 bit数据转换为16 bit数据方法类似,也可通过移位操作实现。将16 bit的音频数据转换为32 bit的音频数据采用的移位方向为左移,先将处理后的数据强制转换为32位int型,再将此时低位的16位数据通过左移操作移至32位中的高位。将移位后的数据输出便完成32 bit音频数据音效处理过程。

2.2 改进Audio Effect框架Android底层实现

由前面对Android原生Audio Effect框架的分析可知,在原生Audio Effect框架中,音频数据输入后,对其进行相应处理的是在框架中的Effect_process部分,且该部分的核心处理入口为LvmBundle_Process,因为原生Audio Effect框架中通过LvmBundle_Process关联到外部数据处理的实现方法。而该处理部分要求待处理的音频数据必须为16 bit音频数据,故32 bit音频数据转换为16 bit音频数据的操作应在Effect_process部分中的LvmBundle_Process之前,而输出时还原为32 bit音频数据的操作应在LvmBundle_Process之后。

在前面代码实现完成后,将两个移位代码实现用C语言编写好相关代码后,分别存储为两个.c文件,并将其在Android源代码中引入。引入方法为将16 bit音频数据转为32 bit音频数据的代码文件以及 32 bit音频数据转为16 bit音频数据的代码文件放入frameworks/av/media/libeffects/lvm/lib/common/src中,在frameworks/av/media/libeffects/lvm/lib中的Android.mk文件中的LOCAL_SRC_FILES这一项中添加两个代码文件索引,并在frameworks/av/media/libeffects/lvm/lib/Common/lib/VectorArithmetic.h中添加两个函数的声明,否则在编译时会出错。而在使用时,仅需在原生Audio Effect框架中调用这两个函数即可,调用时需注意对应的输入输出数据需配置正确。

之所以将本文所提两个实现方法单独存储为两个代码文件而不在原生Audio Effect框架中将这两个具体实现方法直接写入,是学习Android源代码中的编程思想,即将该具体的实现方法放在框架之外,使用时只需在相应位置调用该实现方法即可,减少了每一部分的代码量,也便于后期对代码进行维护。

3 实验测试及结果分析

在完成相应的代码编写工作并编译通过后,将编译生成的.so文件通过adb工具push到机器中的相应位置,并重启机器使其生效。在将编译生成的.so文件push到机器时,需要使用到四条adb命令,分别为adb root、adb remount、adb push以及adb reboot。其中adb root 为获取机器的开发权限,只有获取了开发权限才可对机器内文件进行修改;adb remount为将机器重新挂载;adb push为将指定文件push到机器中的指定位置;adb reboot即为重启机器命令,重启后才会将本次所做更改生效。图4为使用adb将其中一个.so文件push到机器中并使其生效的过程图。

图4 改进方案实现Fig.4 Implementation of the improved solution

本设计是在搭载有Android5.1系统的音乐播放器中进行测试,完成相应开发工作后,使用该播放器播放32 bit的音频数据,并打开均衡器设置均衡器增益,从日志输出中可以看出系统在播放音乐时使用的为原生Audio Effect框架处理,即为图5中的Bundle输出。其次从频率分析图、频率分析数据以及波形图中可以明显看出,均衡器的设置显然已经产生相应的效果,说明原生Audio Effect框架已可处理32 bit音频数据。

图5 日志输出Fig.5 Log output

图6为系统处理前后的频率分析图,其中横坐标f为频率,纵坐标m为振幅强度的量级大小。从图6可以看出设置均衡器增益前的频率分析图于设置均衡器增益后的频率分析图已有所差异,由于整段频率分析图较大,本文仅截取其中一部分。从表4的频率分析数据也可看出,音频数据已根据用户操作发生相应的变化,说明系统已能够对用户所要求的处理做出相应的动作。

图6 处理前后频率分析图Fig.6 Frequency analysis chart before and after processing

表4 处理前后部分频率分析数据Tab.4 Partial frequency analysis data before and after processing

4 结论

本文通过对Android原生Audio Effect框架部分源码进行详细分析,针对Android原生Audio Effect框架仅支持16 bit音频数据处理的问题,采用对输入数据先进行移位操作再进行强制位数转换的方法,达到使Android原生Audio Effect框架在支持16 bit音频数据以及32 bit音频数据的处理的同时尽可能控制音频系统失真程度,丰富Android系统对于不同品质音乐的支持。且本文采用底层开发方案,改动Android原生Audio Effect框架部分源码,虽在实现过程中较为繁琐,但对于后期移植开发来说,在很大程度减小了开发工作量,且在实现上,基本达到预期目标,具有一定的应用前景。

猜你喜欢
均衡器位数移位
基于Kalman滤波的水声混合双向迭代信道均衡算法
MDT诊疗模式在颞下颌关节盘不可复性盘前移位中的治疗效果
五次完全幂的少位数三进制展开
连续自然数及其乘积的位数分析
再生核移位勒让德基函数法求解分数阶微分方程
大型总段船坞建造、移位、定位工艺技术
微小移位的B型股骨假体周围骨折的保守治疗
无线传感网OFDM系统中信道均衡器的电路实现
一种基于LC振荡电路的串联蓄电池均衡器
遥感卫星CCD相机量化位数的选择