通过Python从音频文件提取音频谱
抱歉如果我提交了重复的问题,但我想知道有没有什么Python库可以用来从音频文件中提取声音频谱。我想要能够处理一个音频文件,并写一个算法,返回一组数据 {文件中的时间戳; 频率-幅度}。
我听说这通常被称为节拍检测,但据我所知,节拍检测并不是一种精确的方法,它只适合可视化,而我想要对提取的数据进行处理,然后再把它转换回音频文件。我不需要实时处理。
我会非常感激任何建议和推荐。
2 个回答
我觉得你的问题可以分成三个部分:
- 如何在Python中加载音频文件?
- 如何在Python中计算频谱?
- 频谱计算出来后该怎么处理?
1. 如何在Python中加载音频文件?
你可以使用 scipy
,因为它提供了很多信号处理的功能。加载音频文件的方法如下:
import scipy.io.wavfile
samplerate, data = scipy.io.wavfile.read("mywav.wav")
现在你有了采样率(样本/秒)在 samplerate
中,数据以 numpy.array
的形式存储在 data
中。根据你的需求,你可能需要将数据转换为浮点数格式。
还有一个标准的Python模块 wave
可以用来加载wav文件,但 numpy
/scipy
提供了更简单的接口和更多的信号处理选项。
2. 如何计算频谱
简单来说:使用快速傅里叶变换(FFT)。如果想了解更多,可以查看:
更详细的答案比较复杂。窗口处理非常重要,否则你会得到奇怪的频谱。
3. 频谱计算出来后该怎么处理
这个问题稍微复杂一些。对于较长的信号,通常在时间域进行滤波。如果你能告诉我们你想实现什么目标,可能会得到更好的答案。计算频率频谱是一回事,但在信号处理中如何用它得到有意义的结果就复杂多了。
(我知道你没有问这个,但我觉得这个问题很可能会出现。当然,你可能对音频信号处理有很好的了解,那样的话这个问题就不相关了。)
你可以使用scipy来计算和可视化音频的频谱和声谱图。为了这个测试,我使用了这个音频文件:vignesh.wav
from scipy.io import wavfile # scipy library to read wav files
import numpy as np
AudioName = "vignesh.wav" # Audio File
fs, Audiodata = wavfile.read(AudioName)
# Plot the audio signal in time
import matplotlib.pyplot as plt
plt.plot(Audiodata)
plt.title('Audio signal in time',size=16)
# spectrum
from scipy.fftpack import fft # fourier transform
n = len(Audiodata)
AudioFreq = fft(Audiodata)
AudioFreq = AudioFreq[0:int(np.ceil((n+1)/2.0))] #Half of the spectrum
MagFreq = np.abs(AudioFreq) # Magnitude
MagFreq = MagFreq / float(n)
# power spectrum
MagFreq = MagFreq**2
if n % 2 > 0: # ffte odd
MagFreq[1:len(MagFreq)] = MagFreq[1:len(MagFreq)] * 2
else:# fft even
MagFreq[1:len(MagFreq) -1] = MagFreq[1:len(MagFreq) - 1] * 2
plt.figure()
freqAxis = np.arange(0,int(np.ceil((n+1)/2.0)), 1.0) * (fs / n);
plt.plot(freqAxis/1000.0, 10*np.log10(MagFreq)) #Power spectrum
plt.xlabel('Frequency (kHz)'); plt.ylabel('Power spectrum (dB)');
#Spectrogram
from scipy import signal
N = 512 #Number of point in the fft
f, t, Sxx = signal.spectrogram(Audiodata, fs,window = signal.blackman(N),nfft=N)
plt.figure()
plt.pcolormesh(t, f,10*np.log10(Sxx)) # dB spectrogram
#plt.pcolormesh(t, f,Sxx) # Lineal spectrogram
plt.ylabel('Frequency [Hz]')
plt.xlabel('Time [seg]')
plt.title('Spectrogram with scipy.signal',size=16);
plt.show()
我测试了所有的代码,运行得很好。你需要安装numpy、matplotlib和scipy这几个库。
祝好!