Python:对音乐文件执行 FFT
Posted
技术标签:
【中文标题】Python:对音乐文件执行 FFT【英文标题】:Python: performing FFT on music file 【发布时间】:2018-06-07 13:03:31 【问题描述】:我正在尝试对我创建如下的歌曲(wav 格式的音频文件,大约 3 分钟长)执行 FFT,以防万一。
ffmpeg -i "$1" -vn -ab 128k -ar 44100 -y -ac 1 "$1%.webm.wav"
$1
是 webm 文件的名称。
这是应该显示给定文件的 FFT 的代码:
import numpy as np
import matplotlib.pyplot as plt
# presume file already converted to wav.
file = os.path.join(temp_folder, file_name)
rate, aud_data = scipy.io.wavfile.read(file)
# wav file is mono.
channel_1 = aud_data[:]
fourier = np.fft.fft(channel_1)
plt.figure(1)
plt.plot(fourier)
plt.xlabel('n')
plt.ylabel('amplitude')
plt.show()
问题是,它需要永远。花了这么长时间,我什至无法显示输出,因为我有足够的时间研究和写这篇文章,但它仍然没有完成。
我认为文件太长了,因为
print (aud_data.shape)
输出(9218368,)
,但这看起来像是一个现实世界的问题,所以我希望有办法以某种方式获取音频文件的 FFT。
我做错了什么?谢谢。
编辑
这个问题的更好表述是:FFT 对音乐处理有什么好处吗?例如 2 件的相似度。
正如 cmets 中所指出的,我的简单方法太慢了。
谢谢。
【问题讨论】:
plotting spectrogram in audio analysis的可能重复 好吧,FFT 在 O(nlogn) 时间内运行,并且您有大约 10^8 个样本,所以是的,您期望什么? 由于音乐的功率谱随时间变化,您通常会使用 STFT 对连续(通常重叠)短窗口进行 FFT,其中任何给定窗口都可以被认为是统计上静止的(10 ms 到 20 ms 是窗口大小的典型值)。生成的 3D 数据结构称为频谱图,具有广泛的应用范围。 @PaulR 谢谢你的回答。我会仔细看看光谱图。如果您发布答案,我会接受。但是,一堆重复的 FFT 怎么能比整个输入上的一个 FFT 快这么多呢?我不明白。 两个原因: (i) FFT 为 O(n log n) - 如果您进行数学运算,您会发现多个小 FFT 比一个大 FFT 更有效; (ii) 较小的 FFT 通常对缓存更友好 - FFT 使 log2(n) 以某种“随机”访问模式通过数据,因此如果您的 n 个数据点都适合缓存,它会产生巨大的差异. 【参考方案1】:要显着加快分析的 fft
部分,您可以将数据补零到 2 的幂:
import numpy as np
import matplotlib.pyplot as plt
# rate, aud_data = scipy.io.wavfile.read(file)
rate, aud_data = 44000, np.random.random((9218368,))
len_data = len(aud_data)
channel_1 = np.zeros(2**(int(np.ceil(np.log2(len_data)))))
channel_1[0:len_data] = aud_data
fourier = np.fft.fft(channel_1)
以下是使用上述方法绘制几个正弦波的傅立叶变换的实分量的示例:
import numpy as np
import matplotlib.pyplot as plt
# rate, aud_data = scipy.io.wavfile.read(file)
rate = 44000
ii = np.arange(0, 9218368)
t = ii / rate
aud_data = np.zeros(len(t))
for w in [1000, 5000, 10000, 15000]:
aud_data += np.cos(2 * np.pi * w * t)
# From here down, everything else can be the same
len_data = len(aud_data)
channel_1 = np.zeros(2**(int(np.ceil(np.log2(len_data)))))
channel_1[0:len_data] = aud_data
fourier = np.fft.fft(channel_1)
w = np.linspace(0, 44000, len(fourier))
# First half is the real component, second half is imaginary
fourier_to_plot = fourier[0:len(fourier)//2]
w = w[0:len(fourier)//2]
plt.figure(1)
plt.plot(w, fourier_to_plot)
plt.xlabel('frequency')
plt.ylabel('amplitude')
plt.show()
【讨论】:
以上是关于Python:对音乐文件执行 FFT的主要内容,如果未能解决你的问题,请参考以下文章