楊岱錦,帥子恒,羅文博
(電子科技大學電子科學與工程學院 成都 610054)
音樂是構建人類文明、傳承文化、表達思想情感的藝術和重要途徑,人類社會發展離不開音樂。隨著網絡的發展,數字音樂用戶逐漸普及。僅2015 年,中國數字音樂市場規模就達近500 億[1],音樂創作步入了數字時代。在音樂創作中,通過哼唱形成曲譜是音樂創作過程中必不可少的重要過程與方法[2]。哼唱曲調人工寫作曲譜難度大,一般只有專業音樂人才能完成,且目前沒有成熟的通用輔助軟件。如果可以通過手機APP 軟件完成哼唱直接轉換為樂譜,無疑將會幫助更多人進入音樂創作行業。因此,設計一種快速精準識別哼唱曲調的算法與軟件,實現自動記譜具有廣闊的應用前景和市場。
對哼唱的曲調的識別,通常的方法是采用尋找音頻頻率的突變點,并對音符音長進行切分,然后提取切分段的頻率。頻率的提取主要有時域、頻域以及統計3 種方法[3]。當前應用較多的是頻域分析方法,主要有離散小波變換(DWT)和加窗傅里葉變換(WFT)2 種。離散小波變換主要的特征是靈活性、快速性、雙域性和深刻性[4],但是對音高頻率相差只有幾赫茲的人聲低頻部分,提取誤差較大。而加窗傅里葉變換通過簡單調整窗長,可以較好地滿足需求。
在使用加窗傅里葉變換提取基頻的方法中,國內外已經做了較多的報導。文獻[5]提出了自適應的短時傅里葉變換(ASTFT),利用自適應關系調整窗長;但自適應調整需要提前知道目標參數,與哼唱基頻提取的目標相悖。文獻[6]提出了多分辨率快速傅里葉變換(FFT)的正弦提取;雖然提高了和弦音頻的提取能力,但準確度只有71.4%,并且與哼唱記譜的基頻提取要求仍有差距。文獻[7]采用了加窗傅里葉變化提取人聲哼唱音高,通過對諧波分組來確定基頻;但其固定窗長的提取方法無法同時滿足高頻和低頻提取的精確度。文獻[8]采用多分辨率短時離散傅里葉變換(STDFT)對音頻的主旋律進行提取,并指出應在局部區域對頻率不斷變化的音頻進行頻率測量;但該工作追求對諧波的提取,適合對一般音樂信號的處理,含有大量的樂器噪聲,與哼唱記譜中的基頻提取背景不符。人聲哼唱的能量很難固定,波動較大,因此,對哼唱的音符度量(頻率、音高、音長)的精確識別,成為解決輔助作曲軟件的技術關鍵點,也是難點。不同人的發音標準、聲音大小、節奏情況相對不同,再加上哼唱環境影響導致音頻組成更加復雜,節奏變化模糊,隨機性更大,因此在對人聲哼唱的音頻的精確提取方面,更具挑戰性。
綜上所述,對于人聲哼唱的自動識別記譜方面,當前并沒有成熟且完美的解決方案。本文在基于加窗傅里葉變換基礎上,提出了一種新的符合哼唱特征的加窗傅里葉變換改進算法,較好地解決了對哼唱作曲過程中音頻的分析與提取,為開發精準的哼唱作曲軟件,提供了一種關鍵技術和解決方案。
哼唱的基頻頻率一般為80~1 600 Hz,基頻是哼唱中的重要特征,基頻的頻率決定了哼唱的音高。當前通常采用諧波分析法提取哼唱基頻[7-10],即通過找出部分諧波,再通過諧波頻率推測基頻頻率,但是諧波頻率并不一定恰好出現在基頻的整數倍上,尤其體現在含諧波頻率較多的哼唱低頻部分[7],還容易將基頻誤判為實際值的一半或一倍。因此使用諧波分析的誤差較大。本文對多種大量實際的哼唱音頻進行采樣分析,發現基頻的峰值通常出現在振幅第一次達到最大振幅的1/10 左右處。為了進一步得到更精確的基頻,采用式(1)對得出的基頻進行修正。這種利用最大振幅直接提取基頻的方法明顯克服了諧波分析方法的不足。
式中, f′是 修正后的頻率; [f1/10]是第一次出現的不超過最大振幅1/10 對應的頻率值; Fs是離散數字哼唱音頻對原始連續聲音信號的采樣率; N是離散數字哼唱音頻信號的采樣點數。
利用最大振幅直接提取基頻的方法必須盡可能地降低噪聲能量,突出基頻峰峰值,并防止頻譜泄漏。加窗傅里葉變化為此提供了一種解決方案,常用的窗函數有固定矩形(Rectangular)窗、漢寧(Hanning)窗、布萊克曼(Blackman)窗和海明(Hamming)窗[7,11]。由于海明窗對音頻頻譜泄漏與噪聲處理的效果最好[12],因此本文采用了海明窗函數減少噪聲對音頻數字信號基頻提取的影響,表達式為:
圖1 顯示了一段0.1 s、147 HZ 的哼唱音頻的幅頻關系,以及其對應的 f′和 [f1/10]。
由基頻可以推算出音高,一般采用國際標準音高(standard pitch)度量,按照高度順序分別為A、Bb、B、C、C#、D、Eb、E、F、F#、G、G#,越靠后表示半音高度越高。2 個半音高度之間的頻率關系為[7]:
式中,f1和f2分別是2 個音高對應的頻率,且f1比f2低一個半音高度。這樣就可以計算出所有頻率和音高的對應關系。
整個哼唱的識別記譜,就是對音頻信號進行合理切分、精確提取哼唱特征信息的過程。基本流程如圖2 所示。初始化參數后,通過分幀來獲取基頻-時間關系;通過構建可識別頻率矩陣、節拍規律矩陣來實現對音符音長識別區域的切分;通過提出并實現基于加窗傅里葉變化迭代算法來對基頻進行精確識別和對音符音長識別區域切分的修正;最后應用國際標準音高度量換算式(3)輸出數字樂譜。
按上述流程,對離散數字哼唱音頻信號進行分幀,再逐幀進行哼唱基頻提取,就可以得到頻率-時間信息[13]。由于在哼唱基頻的范圍內(80~1 600 Hz),2 個最低音頻率E2(82.406 Hz)與F2(87.308 Hz)僅相差4.902 Hz,對于采樣率為44.1 kHz的離散數字哼唱音頻,幀長至少應為8 997 個采樣點以保證足夠的分辨率。但由于人哼唱的音符音長最短為0.1 s,若取8 997 個采樣點作為幀長,則會嚴重丟失音符音長為0.1 s 的唱音信息,故本文取5 000 個采樣點作為幀長,以提高獲取頻率-時間信息的分辨率。
獲取頻率-時間信息后,需要快速尋找音頻的突變,從而實現對音符音長區域切分[14]。在切分算法實現過程中,構建了頻率矩陣F 和節拍矩陣R。頻率矩陣F 用于記錄唱音的出現頻率和其連續出現的次數。
式中, fk是第k 個連續出現最多次的唱音頻率,簡稱第k 個頻率; xk是該唱音頻率復現的幀數。矩陣R 用于記錄音長區域的切分值,即形成哼唱識別的節奏,表達如下:
式中, rk是第k 個頻率的唱音拍數。 xmin是F 矩陣中 xk的最小值,k、n 均為整數。
節奏是多個單音持續時間的關系,即音符音長關系,它是哼唱音符切分的重要依據,可認為是哼唱單音的持續時間。其值可由分幀時產生的幀長和幀移2 個參數計算,通常兩幀之間會有重疊部分。對一定幀數的時長計算有:
式中,T 為時長;len 為幀長;k 為幀數;inc 為幀移;Fs為采樣率。為了準確提取哼唱節奏,本文取最短音符音長為一拍,并將所有節奏修正為一拍的整數或半整倍。修正公式為:
對音頻信號的切分為:
式中, Lenk是第k 個區域所含的音頻信號采樣點數;N 為離散數字哼唱音頻信號采樣點的總數。有效哼唱音符音長區域切分算法如圖3 所示。
雖然海明窗函數能夠較好地處理音頻頻譜泄漏和噪聲,由于人聲哼唱音頻普遍復雜,且受日常環境等多種因素影響,單一采樣這種方法識別,往往出現漏、錯、變調現象,難以達到更加精準地識別音符音長和音高。為此,本文在上述識別區域基礎上,進一步改進算法,并統一進行了修正。
改進算法的基本原理是:假定一個唱音在已經切分區域內頻率近似不變,通過不斷迭代更改區域的大小,計算一個頻率變化率 ?fk的最小點來確定哼唱基頻,并以該點出現時的區域所含采樣點個數來計算該音的音符音長。首先判斷哼唱頻率變化方向,確定邊界改變的初始方向。選擇或者定義一個可變識別區域 Lenk,k 值為[a,b]。向右擴大區域(增大b 值),令初始區域對應的基頻為 f0,向右擴展2 次區域的基頻對應值為 fk、 fk+1。對這3 個數據求出變化阻尼 Pk+1, 若 Pk+1<0,則應該沿增大b 的方向繼續迭代;若 Pk+1>0,則初始化b 值后應該沿減小b 的方向迭代。
定義基頻變化率和變化阻尼分別為:
式中, ?fk為第k 次邊界改變時對應的基頻變化率; fk為第k 次邊界改變后區域對應的基頻;Pk+1為第k+1 次邊界改變的阻尼大小。在迭代過程中,若 Pk+1<0,則繼續沿當前邊界改變的方向迭代;若Pk+1>0,則停止當前邊界改變,迭代結束。
算法流程見圖4,具體步驟如下。
1)取2.2 節中描述的有效音符音長區域 Lenk,定義[a,b]區間對應音頻相應的振幅范圍,a 為振幅矩陣F 中的一個起始序號,相當于一個起始采樣點,b 為振幅矩陣中一個終止的序號,由a、b 的值決定所選擇區域的長度。
2)逐次改變右邊界,即b 的值。在[a,b]區域內進行哼唱基頻提取通過迭代判斷頻率的變化,計算頻率變化最小值,記錄對應的b 值。
3)改變左邊界,即a 的值,同樣進行哼唱基頻提取并計算頻率變化最小值對應的a 值,迭代完畢后記錄a、b 的值,確定最終區域。
4)對最終區域[a,b]進行處理,對應的基頻視為該音頻率,根據式(6)計算其時長,記錄為該哼唱的音符音長。
每處理完一個區域后,按照步驟1)~步驟4)進行下一個區域的精確識別,直到整個哼唱音頻結束。通過變化阻尼 Pk判定頻率變化方向后,再計算基頻變化率 ?fk,這樣可以顯著減少整個哼唱音頻的迭代計算次數,提高效率。
當精度在誤差允許范圍內,迭代步長應該盡量取長,但是這樣會嚴重影響算法效率。對典型的人聲哼唱曲調按照精確步長分別取5、10、15、20、25 進行測試,輸出不同的迭代終點對應區域基頻的精度,發現迭代的步長將影響 ?fk和 Pk+1的大小,迭代步長越大, ?fk普遍越大, Pk+1普遍越小,到達迭代終點所需的迭代次數越少,由此所確定的區域對應基頻的精確度越低。根據效率和精確度綜合判斷,在對大量音頻進行分析后發現,當迭代步長增大到20 時,偶爾會出現超過一個半音的誤差,因此迭代步長應取15 比較合適。
本文使用Python 3.6 作為編程語言[15],應用Python 提供的wave 軟件開發包,編程提取了哼唱錄音成WAV 文件格式音頻信號,實現了對音頻的通道數、量化位數、采樣率(Fs)、采樣點數(N)的矩陣計算與存儲;采用了numpy 軟件開發包實現了快速傅里葉變換(FFT)[16]及相應的矩陣換算。
根據10 個以確定的譜曲,分別進行人聲哼唱錄音,錄音設備為普通智能手機,錄音地點為校園宿舍,10 個哼唱音頻數據見表1,其中包含2 個低音音階、2 個高音音階、2 個短時隨意哼唱、2 個長時隨意哼唱、2 個合成聲。

表1 10 個哼唱音頻原始數據表
由于篇幅有限,本文以少音隨意哼唱1 為例展示實驗運行結果,所有實驗結果均由Python 3.6 語言編程運行后獲得。對少音隨意哼唱1 的信息首先進行離散傅里葉變化提取基頻,然后采用5 000 幀長對其進行分幀,對每幀進行快速傅里葉變換得到的基頻,結果如圖5 所示。少音隨意哼唱1 分幀為38 幀,由基頻和每幀的對應關系,計算出矩陣F 與矩陣R(見圖6),計算完成音符音長的切分。
對有效哼唱音符音長區域進行切分后,采用可變區域的加窗傅里葉精確識別迭代算法進一步進行最終時長劃分,效果圖見圖7。按照音頻識別流程(圖2)和2.2、2.3 節所述算法步驟運行,對表1中的錄音音頻依次處理,最后根據國際標準音高度量換算,輸出結果如表2 所示。
考慮人聲本身發音可能存在誤差,輸出的音高差距在一個半音內視為正確音,差距在一個半音以上視為錯音。對原有10 個曲譜的音符、音高、音長進行了對比,正確率達到84.3%。分析誤差來源有:1) 隨意哼唱的音符音長本來就不存在精確的節拍規律,本身存在1~2 拍的誤差;2) 由于錄音設備和錄音場地簡陋,多音隨意哼唱錄音效果較差;3) 該算法只統計了有效哼唱音符音長區域,這是一個頻率較為穩定的區域,而沒有統計2 個音之間頻率變化的非穩定區域,可能出現遺漏。但該方法總體正確率高,達到滿意結果,表明該算法具有一定的普適性,具有較好的應用價值。

表2 10 個哼唱音頻識別輸出記譜表
在對人聲哼唱特征進行分析的基礎上,通過對大量離散數字哼唱音頻進行分析,給出了以相對振幅為依據的直接提取基頻方法,并提出了基頻修正公式。結合哼唱特征和加窗傅里葉變換分幀處理技術,建立了頻率矩陣和節拍矩陣,實現了有效哼唱音符音長區域切分。設計并實現了一種可變識別區域的精確識別迭代算法,通過引入頻率變化率?fk和變化阻尼 Pk判定方法,顯著減少整個哼唱音頻的迭代次數,在Python 3.6 編程環境下,經過反復測試與應用,對人聲平常哼唱音高音長識別準確率達到了84.3%。