[英]Slicing audio signal to detect pitch
我正在使用Librosa轉錄單聲道吉他音頻信號。
我認為,這是一個很好的開始,可以根據發作時間對信號進行“切片”,以便在正確的時間檢測音符的變化。
Librosa提供了在發病時間之前檢測局部最小值的功能 。 我檢查了這些時間,它們是正確的。
這是原始信號的波形和最小值的時間。
[ 266240 552960 840704 1161728 1427968 1735680 1994752]
演奏的旋律是E4,F4,F#4 ...,B4。
因此,理想情況下,結果應為:330Hz,350Hz,...,493Hz(大約)。
如您所見, minima
數組中的時間表示剛演奏音符之前的時間。
但是,在切片的信號(10-12秒,每個切片只有一個音符)上,我的頻率檢測方法的結果確實很差。 我很困惑,因為我在代碼中看不到任何錯誤:
y, sr = librosa.load(filename, sr=40000)
onset_frames = librosa.onset.onset_detect(y=y, sr=sr)
oenv = librosa.onset.onset_strength(y=y, sr=sr)
onset_bt = librosa.onset.onset_backtrack(onset_frames, oenv)
# Converting those times from frames to samples.
new_onset_bt = librosa.frames_to_samples(onset_bt)
slices = np.split(y, new_onset_bt[1:])
for i in range(0, len(slices)):
print freq_from_hps(slices[i], 40000)
print freq_from_autocorr(slices[i], 40000)
print freq_from_fft(slices[i], 40000)
freq_from
函數直接從此處獲取 。
我認為這只是方法的精度差,但是我得到了一些瘋狂的結果。 具體來說, freq_from_hps
返回:
1.33818658287
1.2078047577
0.802142642257
0.531096911977
0.987532329094
0.559638134414
0.953497587952
0.628980979055
這些值應該是8個相應切片中的8個音高(以Hz為單位!)。
freq_from_fft
返回相似的值,而freq_from_autocorr
返回更多“正常”值,但也返回一些接近freq_from_autocorr
隨機值:
242.748000585
10650.0394232
275.25299319
145.552578747
154.725859019
7828.70876515
174.180627765
183.731497068
這是整個信號的頻譜圖:
如您所見,切片已正確完成。 但是,有幾個問題。 首先,頻譜圖中存在一個八度音階問題。 我期待與此有關的一些問題。 但是,我從上述3種方法獲得的結果非常奇怪。
這是我對信號處理的理解還是我的代碼有問題?
這是我對信號處理的理解還是我的代碼有問題?
您的代碼對我來說很好。
您要檢測的頻率是音調的基本頻率(該問題也稱為“ f0估計”)。
因此,在使用freq_from_fft
東西之前,我會對信號進行帶通濾波,以消除垃圾瞬態和低頻噪聲(信號中存在的東西,但與您的問題無關)。
考慮一下,您的基本頻率將在哪個范圍內。對於E2(82 Hz)到F6(1,397 Hz)的原聲吉他。 這意味着您可以擺脫〜80 Hz以下和〜1,400 Hz以上的任何東西(有關帶通示例,請參見此處 )。 濾波后,進行峰值檢測以找到音高(假設基波實際上具有最大的能量)。
另一種策略可能是,忽略每個切片的前X
樣本,因為它們往往是打擊樂的,本質上不是諧波,反正不會給您太多信息。 因此,在您的切片中,僅需查看樣本的最后90%。
綜上所述,f0或基頻估計工作量很大。 ISMIR論文是一個很好的起點。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.