1.前言
由于最近要做舞蹈机器人,想做一个韵律识别的功能,在网上整合了一下资料,如有侵权请联系我删除。
2.参考资料
https://github.com/LXG-Shadow/SongRecogn
shazam听歌识曲算法的解析+python实现-1 读取歌曲 - 哔哩哔哩 (bilibili.com)
shazam听歌识曲算法解析+python实现-2 生成指纹 - 哔哩哔哩 (bilibili.com)
Shazam听歌识曲算法解析+python实现-3 检索歌曲 - 哔哩哔哩 (bilibili.com)
《An Industrial-Strength Audio Search Algorithm》译文_shazam 算法 译文-CSDN博客
3.原理
具体原理建议看原文,这里只做简单阐释:
数据库和录制的音频文件都需要提取可复现的哈希“令牌”,也即指纹。从未知音频中提取的指纹需要和音乐库中提取的海量指纹进行匹配。匹配上的指纹会用来衡量匹配的正确性。提取的指纹需要满足几个指导性原则:时间局部性(temporally localized),转换不变性(translation-invariant),鲁棒性(robust)和指纹信息量大(sufficiently entropic)。时间局部性表示指纹是由时间上接近的音频数据构造的,这样较远时刻的事件不会对该指纹产生影响(如果指纹是由时刻相距较远的音频数据构造的,则指纹会很不稳定,易受到外界噪音干扰)。转换不变性表示提取的指纹必须和位置无关,并且是可复现的。这是因为用户录音可以从任意位置开始。鲁棒性表示从“干净”音乐中提取的指纹也必须可以从含有各种噪音的音频中复现。此外,指纹也必须要包含足够的信息以便减少错误位置的无用匹配。指纹包含的信息量过少通常会导致冗余繁琐的匹配,从而浪费大量计算资源。但是,如果指纹包含的信息量过多又会导致指纹的脆弱性,使指纹在噪音和失真环境下不能复现。
4.代码实现
4.1录音部分
def record_audio():
c = "test.wav"
temp = 20 #
CHUNK = 512
FORMAT = pyaudio.paInt16
CHANNELS = 1
RATE = 44100
RECORD_SECONDS = 12
WAVE_OUTPUT_FILENAME = c
p = pyaudio.PyAudio()
stream = p.open(format=FORMAT,
channels=CHANNELS,
rate=RATE,
input=True,
frames_per_buffer=CHUNK)
print("recording...")
frames = []
for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)):
data = stream.read(CHUNK)
frames.append(data)
print("done")
stream.stop_stream()
stream.close()
p.terminate()
wf = wave.open(WAVE_OUTPUT_FILENAME, 'wb')
wf.setnchannels(CHANNELS)
wf.setsampwidth(p.get_sample_size(FORMAT))
wf.setframerate(RATE)
wf.writeframes(b''.join(frames))
wf.close()
需要的第三方库请自行下载,具体参数请根据需要调整
CHUNK:它表示每次从音频设备中读取的数据块的大小,以字节为单位。较小的块可以提供更低的延迟,但也可能增加 CPU 使用率。一般来说,512 是一个常用的值。
FORMAT:这是音频的采样格式。在这里,pyaudio.paInt16
表示每个采样点占用 16 位(即 2 字节),使用带符号整数表示。这是一种常见的音频格式。
CHANNELS:表示录制的声道数。CHANNELS = 1
表示单声道录制,即单声道音频;CHANNELS = 2
表示立体声录制,即左右两个声道。
RATE:表示采样率,即每秒钟从音频信号中提取并测量的数据点数。通常,44100 Hz 是 CD 音质的标准采样率。更高的采样率能够提供更高的音频质量,但也会占用更多的存储
RECORD_SECONDS:表示要录制的音频时长,以秒为单位。在示例中,RECORD_SECONDS = 12
表示录制 12 秒钟的音频。
WAVE_OUTPUT_FILENAME:是保存录制音频的文件名。在示例中,它被设置为 "test.wav",意味着录制的音频将保存为名为 "test.wav" 的 WAV 格式文件。
4.2听歌认曲部分
def recognize_song():
record_audio()
time.sleep(0.5)
Console.log("Check connection with the database......",end="")
status,code,msg = Database.checkDatabase()
if not status:
Console.log("Connect to database failed: %s" % msg)
Console.log("Please check config or database.")
sys.exit()
Console.log("Success!")
time.sleep(1)
os.system("cls")
Console.log("-" * 20)
Console.log(description)
Console.log("-" * 20)
Console.recognizeAudio("test.wav")
4.3 使用教程
先在你的mysql数据库里建一个表格用来存储歌曲和声纹
根据你自己的数据库,在config.py里配置
class srConfig(object):
audio_frame_rate = 44100
audio_extension = ".mp3"
sqlalchemy_address = 'mysql+mysqlconnector://root:xxxxx@localhost:3306/xxxx'
#连接本地的mySQL数据库
support_audio = [".mp3",".m4a"]
mysql_max_connection = 512
mysql_insert_number = 20000
max_audio_process_num = 8
max_process_num = 8
enable_console_msg = True
# if search subdirectories when using addAudioFromDir
search_subdirectories = False
def __init__(self):
pass
然后运行createDatabase.py
建立数据库
运行添加歌曲的代码:录入指纹和歌曲
def addAudio(filepath):
log("Check Song Hash")
song = Model.Audio.initFromFile(filepath)
log("-Adding audio %s to the database-" % song.filename)
if song.isFingerprinted():
log("Add song fail: song already been fingerprinted")
return
song.getId(new=True)
log("Get Song id success: song id", song.id)
log("Start read song data", end="......")
song.read()
log("Success")
log("Start get fingerprints", end="......")
t1 = time.time()
song.getFingerprints()
t2 = time.time()
log("Success! (Time cost: %d sec, total number: %s ) " % (t2 - t1, len(song.fingerprints)))
log("Start insert fingerprints", end="......")
t1 = time.time()
song.startInsertFingerprints()
t2 = time.time()
log("Insert fingerprints into database success (Time cost: %d sec)" % (t2 - t1))
log("Add Song Success!")
最后根据自己需要修改就好了!
5.注意
具体部分请前往原作者github上自行修改
标签:树莓,Console,log,song,听歌,识曲,指纹,time,音频 From: https://blog.csdn.net/qr0617/article/details/140477346