car*_*mom 4 python linux audio mp3 signal-processing
我慢慢地致力于这哪里会是非常有用的,如果该计算机可以找到一个项目,其中在发生某种样本的MP3文件。我会将这个问题限制在一个相当精确的音频片段上,而不仅仅是例如同一乐队不同录音中的一首歌中的合唱,它会成为某种机器学习问题。我在想,如果它没有添加噪音并且来自同一个文件,那么应该可以在没有机器学习的情况下以某种方式定位它发生的时间,就像 grep 可以在文本文件中找到出现单词的行一样。
如果您身边没有 mp3,可以使用一些公共领域的网络上可用的音乐来设置问题,所以没有人抱怨:
curl https://web.archive.org/web/20041019004300/http://www.navyband.navy.mil/anthems/ANTHEMS/United%20Kingdom.mp3 --output godsavethequeen.mp3
Run Code Online (Sandbox Code Playgroud)
这是一分钟:
exiftool godsavethequeen.mp3 | grep Duration
Duration : 0:01:03 (approx)
Run Code Online (Sandbox Code Playgroud)
现在在 30 到 33 秒之间剪掉一点(那是 la la la la ..):
ffmpeg -ss 30 -to 33 -i godsavethequeen.mp3 gstq_sample.mp3
Run Code Online (Sandbox Code Playgroud)
文件夹中的两个文件:
$ ls -la
-rw-r--r-- 1 cardamom cardamom 48736 Jun 23 00:08 gstq_sample.mp3
-rw-r--r-- 1 cardamom cardamom 1007055 Jun 22 23:57 godsavethequeen.mp3
Run Code Online (Sandbox Code Playgroud)
出于某种原因,exiftool 似乎高估了样本的持续时间:
$ exiftool gstq_sample.mp3 | grep Duration
Duration : 6.09 s (approx)
Run Code Online (Sandbox Code Playgroud)
..但我想它只是像它告诉你的那样近似。
这是我所追求的:
$ findsoundsample gstq_sample.mp3 godsavethequeen.mp3
start 30 end 33
Run Code Online (Sandbox Code Playgroud)
如果它是 bash 脚本或 python 解决方案,即使使用某种 python 库,我也很高兴。有时,如果您使用错误的工具,解决方案可能有效但看起来很糟糕,因此选择哪个工具更合适。这是一个一分钟的mp3,还没有考虑过要完成它的性能,但想要一些可扩展性,例如在半小时内找到十秒。
当我尝试自己解决这个问题时,我一直在查看以下资源:
如何使用 Python 和 Gracenote 识别音乐样本?
https://github.com/craigfrancis/audio-detect
https://madmom.readthedocs.io/en/latest/introduction.html
https://github.com/aubio/aubio
aubionset 是个好人选
https://willdrevo.com/fingerprinting-and-audio-recognition-with-python/
MP3 是一种有趣的格式。底层数据存储在“帧”中,每帧长 0.026 秒。每帧都是声波的快速傅立叶变换,根据大小和比特率等以不同程度的质量编码。在您的情况下,您确定 mp3 具有匹配的比特率吗?如果他们这样做,考虑到您在 Frame 边界上进行选择,相对简单的 grep 风格的方法应该是可能的。然而,情况很可能并非如此。
对于真正的解决方案,您需要在某种程度上处理 mp3 文件,以抽象出编码。但是,即使对于匹配的声音,也不能保证生成的波形匹配,因为比特率和可能的帧对齐可能不同。这种很小的机会使它变得更加困难。
我会给你我解决这个问题的方法,但值得注意的是,这不是做事的完美方式,只是我最好的挥杆。即使它是同一个文件,也不能保证帧边界是对齐的,所以我认为你需要采取一种非常面向波浪的方法,而不是面向数据的方法。
首先,将 mp3 转换为波形。我知道让它压缩会很好,但我再次认为面向波浪是我们唯一的希望。然后,使用高通滤波器尝试去除样本之间不同的任何音频压缩伪影。一旦你有两个波形,在波形中找到小波应该是相对简单的。您可以遍历可能的起始位置并减去波浪。当您接近零时,您就知道您已经接近了。
正如Carson的回答中所建议的,一旦文件转换为 .wav 格式,处理音频就会变得容易得多。
您可以使用Wernight在 python 中读取 mp3 的答案来执行此操作:
ffmpeg -i godsavethequeen.mp3 -vn -acodec pcm_s16le -ac 1 -ar 44100 -f wav godsavethequeen.wav
ffmpeg -i gstq_sample.mp3 -vn -acodec pcm_s16le -ac 1 -ar 44100 -f wav gstq_sample.wav
Run Code Online (Sandbox Code Playgroud)
然后,找到样本的位置主要是获取源(在本例中)和要查找的样本( )之间的互相关函数的峰值。本质上,这将找到样本看起来最像源中相应部分的偏移。这可以通过 python 使用.godsavethequeen.wavgstq_sample.wavscipy.signal.correlate
抛出一个小的 python 脚本来完成此操作,如下所示:
import numpy as np
import sys
from scipy.io import wavfile
from scipy import signal
snippet = sys.argv[1]
source = sys.argv[2]
# read the sample to look for
rate_snippet, snippet = wavfile.read(snippet);
snippet = np.array(snippet, dtype='float')
# read the source
rate, source = wavfile.read(source);
source = np.array(source, dtype='float')
# resample such that both signals are at the same sampling rate (if required)
if rate != rate_snippet:
num = int(np.round(rate*len(snippet)/rate_snippet))
snippet = signal.resample(snippet, num)
# compute the cross-correlation
z = signal.correlate(source, snippet);
peak = np.argmax(np.abs(z))
start = (peak-len(snippet)+1)/rate
end = peak/rate
print("start {} end {}".format(start, end))
Run Code Online (Sandbox Code Playgroud)
请注意,为了采取良好措施,我添加了一项检查,以确保两个 .wav 文件具有相同的采样率(并根据需要重新采样),但您也可以使用以下命令从 .mp3 格式转换它们时确保它们始终相同-ar 44100的论点ffmpeg。