我想要檢測用吉他彈奏的B3音符的音高。音頻可以找到here。單吉他音符Python的諧波產品譜
正如你所看到的,它是可見的根本間距大約對應於B3注爲250Hz。
它還含有大量的諧波,這就是爲什麼我選擇使用here的HPS。我使用此代碼檢測間距:
def freq_from_hps(signal, fs):
"""Estimate frequency using harmonic product spectrum
Low frequency noise piles up and overwhelms the desired peaks
"""
N = len(signal)
signal -= mean(signal) # Remove DC offset
# Compute Fourier transform of windowed signal
windowed = signal * kaiser(N, 100)
# Get spectrum
X = log(abs(rfft(windowed)))
# Downsample sum logs of spectra instead of multiplying
hps = copy(X)
for h in arange(2, 9): # TODO: choose a smarter upper limit
dec = decimate(X, h)
hps[:len(dec)] += dec
# Find the peak and interpolate to get a more accurate peak
i_peak = argmax(hps[:len(dec)])
i_interp = parabolic(hps, i_peak)[0]
# Convert to equivalent frequency
return fs * i_interp/N # Hz
我的採樣速率爲40000然而,而不是越來越接近250Hz的(B3注)的結果,我得到0.66Hz。這怎麼可能?
我也嘗試過使用自相關方法從相同的回購,但我也得到像10000Hz的不好的結果。
感謝一個答案我明白我必須應用濾波器來消除信號中的低頻。我怎麼做?有多種方法可以做到這一點,並推薦哪一種?
狀態更新:
通過回答提出的高通濾波器的工作。如果我在音頻信號的答案中應用該功能,則它會正確顯示約245Hz。但是,我想過濾整個信號,而不僅僅是它的一部分。一個音符可能位於信號的中間,或者一個信號包含多個音符(我知道一個解決方案是開始檢測,但我很想知道爲什麼這不起作用)。這就是爲什麼我編輯代碼返回filtered_audio
。
問題是,如果我這樣做,即使噪音已被正確刪除(見截圖)。結果我得到了0.05。
你做了一個回送與你的聲卡/音頻接口或有其它已知的頻率源? - 其他人報告難以根據操作系統獲得所需的採樣率,驅動程序 – f5r5e5d
當您嘗試計算整個剪輯的音高時,由於音高算法看不到頻譜圖,您會得到無意義的結果。頻譜圖顯示了隨時間變化的功率譜,但該算法僅適用於整個信號的平均功率譜。看看我的意思,看看整個信號的頻譜,並將它與音符的頻譜(0-1秒)進行比較。爲了解決剪輯中多個音符的可能性,我認爲你應該提出一個新問題。 – Michael
謝謝,你是對的。我想我應該把信號分成多個信號(每播放一個音符,一個10-15幀的片段),然後爲每一個音符做HPS。你認爲這是一個合乎邏輯的方法嗎? – pk1914