2
(1.福建工程學院 信息科學與工程學院,福建 福州 350118;2.福建工程學院 微電子技術(shù)研究中心,福建 福州 350118)
音頻系統(tǒng)是Android多媒體功能中重要的組成部分。已公開的關(guān)于音效處理的研究文獻大多是單獨研究音效算法[1-2]或是結(jié)合DSP芯片開發(fā)[3-5],Android系統(tǒng)音頻相關(guān)的文獻目前多數(shù)集中在編解碼方面,音效處理方面的較為欠缺[6-7]。Android系統(tǒng)源代碼體系龐大,現(xiàn)有分析Android系統(tǒng)源代碼以及底層開發(fā)類的書籍資料多是從整個系統(tǒng)的宏觀角度出發(fā),具體功能實現(xiàn)分析方面的書籍資料較少。本研究分析Android音頻系統(tǒng)的源碼發(fā)現(xiàn),Android對于音效處理的支持還存在僅支持16 bit音頻數(shù)據(jù)處理的問題。其數(shù)字音頻系統(tǒng)分辨率取決于音頻數(shù)據(jù)采樣的量化位深,對于有限的量化技術(shù)而言,將連續(xù)的模擬信號完整表示出來幾乎不可能,故量化值與實際值之間便會產(chǎn)生誤差,稱為量化誤差[8]。理想情況下,16 bit音源量化下,1 個量化間隔存在的誤差大約存在 0.001 53% 的失真,24 bit 下大約為 0.000 03%,而32 bit存在的量化誤差則更小[9]。許多音樂發(fā)燒友更傾心于32 bit音源,僅支持16 bit音頻數(shù)據(jù)的處理已經(jīng)無法滿足大眾對音質(zhì)的追求,所以需對Android音頻系統(tǒng)進一步完善,使其對32 bit的音源提供支持[10]。
音頻數(shù)據(jù)采用PCM編碼,一般采用自然二進制碼或格雷碼[11]。一般的二進制碼的編碼規(guī)則在將32 bit數(shù)據(jù)進行強制位數(shù)轉(zhuǎn)換為16 bit數(shù)據(jù)時,保留下來的為低位的數(shù)據(jù),但高位的數(shù)據(jù)較之更為重要。本文采取先對輸入數(shù)據(jù)進行移位操作,將高位數(shù)據(jù)移至低位后,再進行強制位數(shù)轉(zhuǎn)換,保留高位數(shù)據(jù),丟棄低位數(shù)據(jù)。另外,對于音頻數(shù)據(jù)來說,輸入為32 bit的音頻數(shù)據(jù),輸出時也應為32 bit的數(shù)據(jù),否則輸出的音頻數(shù)據(jù)會存在一定的誤差[8]。當數(shù)據(jù)處理完成后還原為32 bit進行輸出可將量化位深轉(zhuǎn)換帶來的誤差控制在約為0.000 76%左右[9]。
在Android源代碼中,打開日志輸出功能的方法為#define LOG_TAG "XX"以及#define LOG_NDEBUG 0這兩條語句,打開后在適當?shù)牡胤秸{(diào)用ALOGV()函數(shù)即可將指定的內(nèi)容在運行日志中輸出。由于Android的音頻系統(tǒng)較為復雜龐大,故改進Android原生Audio Effect框架必需對原生Audio Effect框架進行深入分析。通過日志輸出文件可得知,Android原生Audio Effect框架主要分為三個部分,即音效創(chuàng)建、命令執(zhí)行及音效處理。
Android系統(tǒng)中,使用原生Audio Effect框架必須先進行初始化,定義必要的參數(shù),音效創(chuàng)建便是做此用途。在框架中,音效創(chuàng)建為EffectCreate部分。其主要調(diào)用框架中的兩個初始化操作,分別為LvmGlobalBundle_init以及LvmBundle_init兩部分。具體是先調(diào)用LvmGlobalBundle_init進行全局初始化,這部分主要是初始化全局內(nèi)存,再通過LvmBundle_init進行框架初始化,這部分主要是使用默認配置初始化引擎,創(chuàng)建禁用所有效果的初始化實例。從此部分代碼的默認配置中能夠看出,原生框架僅支持16 bit音頻數(shù)據(jù)的處理,如表1中第5以及第13行加粗代碼所示,inputCfg.format以及outputCfg.format都為AUDIO_FORMAT_PCM_16_BIT。當然,EffectCreate部分還有其他如匹配音效模式(重低音、環(huán)繞聲、均衡器等)來開啟對應的音效功能。
表1 LvmBundle_init部分代碼Tab.1 Part of the LvmBundle_init code
在原生Audio Effect框架中,命令執(zhí)行部分為Effect_command,它包含框架中除了數(shù)據(jù)處理部分之外其他調(diào)用。Effect_command部分中包括了音效的生效、各類參數(shù)的獲取和設(shè)置、以及音效的釋放等等部分,其中各類參數(shù)的獲取和設(shè)置是通過在Effect_command中調(diào)用框架里的Equalizer_getParameter以及Equalizer_setParameter部分,可獲取框架中所需的中心頻率、頻段、增益以及預設(shè)值等參數(shù)。從輸出日志可見,這部分一直處于線程中,均衡器每改變一次的頻段增益,都會重新執(zhí)行一次Equalizer_getParameter以及Equalizer_setParameter來使用戶設(shè)置的均衡器增益生效。圖1為Effect_command部分主要的跳轉(zhuǎn)過程。
圖1 Effect_command主要跳轉(zhuǎn)流程Fig.1 Major jump flow of Effect_command
當框架初始化以及各類參數(shù)配置完成后,系統(tǒng)便會根據(jù)用戶選擇的模式對音頻數(shù)據(jù)進行相應的處理了。原生Audio Effect框架中音效處理部分是在Effect_process中,這部分主要是對輸入的音頻數(shù)據(jù)根據(jù)用戶需要進行相應計算,即對音頻數(shù)據(jù)進行處理并輸出。通過閱讀相關(guān)代碼可知,Effect_process部分會調(diào)用框架里的LvmBundle_process部分,這個部分也可以看出Audio Effect框架僅支持16 bit數(shù)據(jù)的處理,如表2中第1以及第2行代碼所示。在LvmBundle_process中繼續(xù)調(diào)用外部的LVM_process,一層層往下調(diào)用進行,直到獲取到對應的數(shù)據(jù)處理的具體實現(xiàn)方法,并對輸入的音頻數(shù)據(jù)進行處理。這也是Android系統(tǒng)代碼結(jié)構(gòu)的一大特點,封裝成多層,這樣有助于減少耦合,便于后期的代碼維護。圖2為音效處理部分的主要代碼跳轉(zhuǎn)情況示意圖。
表2 LvmBundle_process部分代碼Tab.2 Part of the LvmBundle_process code
圖2 音效處理部分主要代碼跳轉(zhuǎn)情況Fig.2 Major code jumps in the audio processing section
由于32 bit音頻數(shù)據(jù)在精度上對于16 bit音頻數(shù)據(jù)會高出許多,故將32 bit轉(zhuǎn)換為16 bit處理完成后,還應將處理結(jié)果還原為32 bit音頻數(shù)據(jù)進行輸出。在音頻數(shù)據(jù)編碼中,每一個二進制數(shù)對應一個量化電平,將它們依序排列,得到由二進制脈沖串組成的數(shù)字信息流[2]。圖3為二進制數(shù)示意圖,其中d只能為1或0,且每一位取值可相同。根據(jù)二進制與十進制的轉(zhuǎn)換公式(1)可知,顯然高位的數(shù)據(jù)在輸出時相對于低位的數(shù)據(jù)來說更為重要,若不加處理直接進行強制的數(shù)據(jù)位數(shù)轉(zhuǎn)換,易造成處理所得音頻數(shù)據(jù)出現(xiàn)嚴重的失真現(xiàn)象。
圖3 二進制數(shù)示意圖Fig.3 Binary number diagram
(N)10=dn*2n-1+dn-1*2n-2+…+d2*21+d1*20
(1)
式中,N為二進制轉(zhuǎn)換為十進制的結(jié)果,dn、dn-1、…、d2、d1為二進制各位的系數(shù),n即為位數(shù),位數(shù)從右至左依次為1、2、…、(n-1)、n。
為保留音頻數(shù)據(jù)大部分信息,減輕音頻數(shù)據(jù)由于位數(shù)轉(zhuǎn)換造成的失真現(xiàn)象,采取先將音頻數(shù)據(jù)進行移位操作,保留音頻數(shù)據(jù)的高位數(shù)據(jù),丟棄低位數(shù)據(jù),移位操作完成后再進行位數(shù)的強制位數(shù)轉(zhuǎn)換操作。經(jīng)過強制位數(shù)轉(zhuǎn)換操作后,32 bit音頻數(shù)據(jù)便轉(zhuǎn)換為16 bit音頻數(shù)據(jù),此時數(shù)據(jù)即可通過Android原生Audio Effect框架處理。該移位操作關(guān)鍵的代碼如表3所示。
表3 移位操作關(guān)鍵代碼Tab.3 Key code of the shift operation
上述代碼中,temp為臨時數(shù)據(jù),src為原始數(shù)據(jù),dst為轉(zhuǎn)換后的數(shù)據(jù)。32 bit音頻數(shù)據(jù)轉(zhuǎn)換為16 bit音頻數(shù)據(jù),保留高位數(shù)據(jù),故需進行右移操作,由于是將32 bit音頻數(shù)據(jù)轉(zhuǎn)換為16 bit音頻數(shù)據(jù),故右移位數(shù)為16位,保留高16位數(shù)據(jù),且16位int型的數(shù)據(jù)可表示范圍為-32 768~32 767,故移位后還需注意該數(shù)值是否超出16位的數(shù)據(jù)范圍,如若超出,應在保留盡可能多的數(shù)據(jù)的前提下,將其取值為16位int型數(shù)據(jù)可表示范圍內(nèi)的數(shù)值,上述代碼中的兩個if語句其功能便是判斷移位后數(shù)據(jù)是否超出16位可表示的范圍,若超出則根據(jù)保留盡可能多的數(shù)據(jù)的前提進行取值;若未超出,便直接強制位數(shù)轉(zhuǎn)換。
音頻數(shù)據(jù)在位數(shù)轉(zhuǎn)換完成后,經(jīng)過Audio Effect框架處理,處理結(jié)束后還需將其轉(zhuǎn)換為32 bit的音頻數(shù)據(jù)再進行輸出,否則所聽到的音樂將會存在極大程度的失真。具體的實現(xiàn)方法與上述將32 bit數(shù)據(jù)轉(zhuǎn)換為16 bit數(shù)據(jù)方法類似,也可通過移位操作實現(xiàn)。將16 bit的音頻數(shù)據(jù)轉(zhuǎn)換為32 bit的音頻數(shù)據(jù)采用的移位方向為左移,先將處理后的數(shù)據(jù)強制轉(zhuǎn)換為32位int型,再將此時低位的16位數(shù)據(jù)通過左移操作移至32位中的高位。將移位后的數(shù)據(jù)輸出便完成32 bit音頻數(shù)據(jù)音效處理過程。
由前面對Android原生Audio Effect框架的分析可知,在原生Audio Effect框架中,音頻數(shù)據(jù)輸入后,對其進行相應處理的是在框架中的Effect_process部分,且該部分的核心處理入口為LvmBundle_Process,因為原生Audio Effect框架中通過LvmBundle_Process關(guān)聯(lián)到外部數(shù)據(jù)處理的實現(xiàn)方法。而該處理部分要求待處理的音頻數(shù)據(jù)必須為16 bit音頻數(shù)據(jù),故32 bit音頻數(shù)據(jù)轉(zhuǎn)換為16 bit音頻數(shù)據(jù)的操作應在Effect_process部分中的LvmBundle_Process之前,而輸出時還原為32 bit音頻數(shù)據(jù)的操作應在LvmBundle_Process之后。
在前面代碼實現(xiàn)完成后,將兩個移位代碼實現(xiàn)用C語言編寫好相關(guān)代碼后,分別存儲為兩個.c文件,并將其在Android源代碼中引入。引入方法為將16 bit音頻數(shù)據(jù)轉(zhuǎn)為32 bit音頻數(shù)據(jù)的代碼文件以及 32 bit音頻數(shù)據(jù)轉(zhuǎn)為16 bit音頻數(shù)據(jù)的代碼文件放入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中添加兩個函數(shù)的聲明,否則在編譯時會出錯。而在使用時,僅需在原生Audio Effect框架中調(diào)用這兩個函數(shù)即可,調(diào)用時需注意對應的輸入輸出數(shù)據(jù)需配置正確。
之所以將本文所提兩個實現(xiàn)方法單獨存儲為兩個代碼文件而不在原生Audio Effect框架中將這兩個具體實現(xiàn)方法直接寫入,是學習Android源代碼中的編程思想,即將該具體的實現(xiàn)方法放在框架之外,使用時只需在相應位置調(diào)用該實現(xiàn)方法即可,減少了每一部分的代碼量,也便于后期對代碼進行維護。
在完成相應的代碼編寫工作并編譯通過后,將編譯生成的.so文件通過adb工具push到機器中的相應位置,并重啟機器使其生效。在將編譯生成的.so文件push到機器時,需要使用到四條adb命令,分別為adb root、adb remount、adb push以及adb reboot。其中adb root 為獲取機器的開發(fā)權(quán)限,只有獲取了開發(fā)權(quán)限才可對機器內(nèi)文件進行修改;adb remount為將機器重新掛載;adb push為將指定文件push到機器中的指定位置;adb reboot即為重啟機器命令,重啟后才會將本次所做更改生效。圖4為使用adb將其中一個.so文件push到機器中并使其生效的過程圖。
圖4 改進方案實現(xiàn)Fig.4 Implementation of the improved solution
本設(shè)計是在搭載有Android5.1系統(tǒng)的音樂播放器中進行測試,完成相應開發(fā)工作后,使用該播放器播放32 bit的音頻數(shù)據(jù),并打開均衡器設(shè)置均衡器增益,從日志輸出中可以看出系統(tǒng)在播放音樂時使用的為原生Audio Effect框架處理,即為圖5中的Bundle輸出。其次從頻率分析圖、頻率分析數(shù)據(jù)以及波形圖中可以明顯看出,均衡器的設(shè)置顯然已經(jīng)產(chǎn)生相應的效果,說明原生Audio Effect框架已可處理32 bit音頻數(shù)據(jù)。
圖5 日志輸出Fig.5 Log output
圖6為系統(tǒng)處理前后的頻率分析圖,其中橫坐標f為頻率,縱坐標m為振幅強度的量級大小。從圖6可以看出設(shè)置均衡器增益前的頻率分析圖于設(shè)置均衡器增益后的頻率分析圖已有所差異,由于整段頻率分析圖較大,本文僅截取其中一部分。從表4的頻率分析數(shù)據(jù)也可看出,音頻數(shù)據(jù)已根據(jù)用戶操作發(fā)生相應的變化,說明系統(tǒng)已能夠?qū)τ脩羲蟮奶幚碜龀鱿鄳膭幼鳌?/p>
圖6 處理前后頻率分析圖Fig.6 Frequency analysis chart before and after processing
表4 處理前后部分頻率分析數(shù)據(jù)Tab.4 Partial frequency analysis data before and after processing
本文通過對Android原生Audio Effect框架部分源碼進行詳細分析,針對Android原生Audio Effect框架僅支持16 bit音頻數(shù)據(jù)處理的問題,采用對輸入數(shù)據(jù)先進行移位操作再進行強制位數(shù)轉(zhuǎn)換的方法,達到使Android原生Audio Effect框架在支持16 bit音頻數(shù)據(jù)以及32 bit音頻數(shù)據(jù)的處理的同時盡可能控制音頻系統(tǒng)失真程度,豐富Android系統(tǒng)對于不同品質(zhì)音樂的支持。且本文采用底層開發(fā)方案,改動Android原生Audio Effect框架部分源碼,雖在實現(xiàn)過程中較為繁瑣,但對于后期移植開發(fā)來說,在很大程度減小了開發(fā)工作量,且在實現(xiàn)上,基本達到預期目標,具有一定的應用前景。