Python聲音處理入門
- 2020 年 1 月 10 日
- 筆記
Python聲音處理入門
註:本文加入了譯者的理解,並非嚴謹的譯作,僅供參考。
原文Basic Sound Processing with Python描述了怎樣在Python中通過pylab介面對聲音進行基本的處理。
準備工作
安裝庫
確保庫numpy、matplotlib和scipy已正確安裝。
導入包
from pylab import* from scipy.io import wavfile
讀取wav文件
讀取wav文件 下載文件440_sine.wav,文件中加入了基頻(F0)為440Hz的雜訊。
sampFreq, snd = wavfile.read('440_sine.wav')函數scipy.io.wavefile.read以int16或int32(32位wav)格式讀入wav文件。16位.wav文件對應int16,32位.wav文件對應int32,不支援24位.wav。
查看wav文件類型
>>>snd.dtype dtype('int16')這表示原始聲壓值在wav文件中一一映射到區間[-2^15, 2^15 -1]。我們把聲壓值歸一化,即映射到區間[-1, 1):
snd = snd / (2.**15)
查看wav文件的通道數和取樣點數
>>> snd.shape (5060, 2)
表示文件包含2個通道,5060個取樣點。結合取樣率(sampFreq = 44110),可得訊號持續時長為114ms:
>>> 5060.0 / sampFreq 0.11473922902494331
下文我們只處理其中一個通道
s1 = snd[:, 0]
python自身不支援播放聲音,假如你想在python中回放聲音,參考pyalsaaudio(Linux)或PyAudio。
2 繪製音調圖
以時間(單位ms)為x軸,聲壓值為y軸,繪製音調圖。先創建時間點數組
timeArray = arange(0, 5060.0, 1) #[0s, 1s], 5060個點 timeArray = timeArray / sampFreq #[0s, 0.114s] timeArray = timeArray * 1000 #[0ms, 114ms]
然後繪圖
plot(timeArray, s1, color='k') ylabel('Amplitude') xlabel('Time (ms)')3 繪製頻譜圖
頻譜圖也是一種很有用的圖形表示方式。用函數fft對聲音進行快速傅立葉變換(FFT),得到聲音的頻譜。讓我們緊跟技術文檔的步伐,得到聲音文件的功率譜:
n = len(s1) p = fft(s1) #執行傅立葉變換
技術文檔中指定了執行fft用到的抽樣點數目,我們這裡則不指定,默認使用訊號n的取樣點數。不採用2的指數會使計算比較慢,不過我們處理的訊號持續時間之短,這點影響微不足道。
nUniquePts = ceil((n+1)/2.0) p = p[0:nUniquePts] p = abs[p]
fft變換的返回結果為複合形式,比如複數,包含幅度和相位資訊。我們獲取傅立葉變換的絕對值,得到頻率分量的幅度資訊。
p = p / float(n) #除以取樣點數,去除幅度對訊號長度或取樣頻率的依賴 p = p**2 #求平方得到能量 #乘2(詳見技術手冊) #奇nfft排除奈奎斯特點 if n % 2 > 0: #fft點數為奇 p[1:len(p)] = p[1:len(p)]*2 else: #fft點數為偶 p[1:len(p)-1] = p[1:len(p)-1] * 2 freqArray = arange(0, nUniquePts, 1.0) * (sampFreq / n) plot(freqArray/1000, 10*log10(p), color='k') xlabel('Freqency (kHz)') ylabel('Power (dB)')繪製的頻譜圖如下所示。注意圖中y軸是能量的對數10*log10(p),單位分貝;x軸是頻率/1000,單位kHz。

為了檢驗計算結果是否等於訊號的能量,我們計算出訊號的均方根rms。廣義來說,可以用rms衡量波形的幅度。如果直接對偏移量為零的正弦波求幅度的均值,它的正負部分相互抵消,結果為零。那我們先對幅度求平方,再開方(注意:開方加大了幅度極值的權重?)
rms_val = sqrt(mean(s1**2)) rms_val 0.0615000626299
訊號的rms等於總能量的平方根,那麼把fft在所有頻率上的能量值相加然後求平方根,應該等於rms。
>>> sqrt(sum(p)) 0.0615000626299