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的主要内容,如果未能解决你的问题,请参考以下文章

Python Scrapy的QQ音乐爬虫 音乐下载爬取歌曲信息歌词精彩评论

python网易云音乐文件爬取

pycharm游戏头像,音乐设置

网易云音乐文件,怎么转换成mp3格式?

使用 FFT Python 从音频信号中去除背景噪声

Python:使用不同的文件在后台播放音乐播放列表