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