树莓派开发日记——在树莓派上部署听歌识曲功能

1.前言

由于最近要做舞蹈机器人,想做一个韵律识别的功能,在网上整合了一下资料,如有侵权请联系我删除。

2.参考资料

https://github.com/LXG-Shadow/SongRecogn

shazam听歌识曲算法的解析+python实现-1 读取歌曲 - 哔哩哔哩 (bilibili.com)

shazam听歌识曲算法解析+python实现-2 生成指纹 - 哔哩哔哩 (bilibili.com)

Shazam听歌识曲算法解析+python实现-3 检索歌曲 - 哔哩哔哩 (bilibili.com)

www.ee.columbia.edu

《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上自行修改

  • 13
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值