Python 中编写的节拍器有哪些改进方法?

What are the ways to improve my metronome written in Python?

我正在尝试使用 librosa 和 sounddevice 编写一个基于 python 的节拍器,但我遇到了一些准确性方面的问题。这是代码:

from time import sleep, perf_counter
import librosa
import sounddevice as sd

    bpm = 200
    delay = 60/bpm
    tone = librosa.tone(440, sr=22050, length=1000)
    
    try:
        while True:
            sd.play(tone, 22050)
            sleep(delay)
    except KeyboardInterrupt:
        pass

首先,正常运行的节拍器的上限似乎在 180bpm 左右 - 如果您将 bpm 设置为高于 200bpm,则不会发出声音。在较慢的速度下,我可以听到节拍器与点击之间的间距不一致。我已经运行 the script from this topic,与这个答案的作者相比,我的结果很差(使用“旧的单核 32 位 2GHz 机器”对我的六核 3.9GHz 64 位 windows 运行):

150.0 bpm
+0.007575200
+0.006221200
-0.012907700
+0.001935400
+0.002982700
+0.006840000
-0.009625400
+0.003260200
+0.005553100
+0.000668100
-0.010895100
+0.017142500
-0.012933300
+0.001465200
+0.004203100
+0.004769100
-0.012183100
+0.002174500
+0.002301000
-0.001611100 

所以我想知道我的节拍器问题是否与这些糟糕的结果有某种关联,以及我可以做些什么来解决它。 我遇到的第二个问题是节拍器关闭的方式 - 我希望它是 运行 直到用户输入特定按钮的点,或者在我的情况下(无 GUI)特定值从键盘 - 让我们说 space 键。因此,正如您现在看到的,它仅适用于 ctrl + c,但我不知道如何使用指定键实现中断。

运行 您的代码在 mac 上,时间不一致很明显,但节奏与设定的 bpm 有很大偏差。

这主要是因为 sleep() 不够准确,而且还因为您必须考虑自上次事件以来经过的时间。例如调用 sd.play()

花了多少时间

我不知道你是在什么操作系统上做的运行,但大多数操作系统都有一个特殊的计时器来进行精确的回调(例如 Windows 上的多媒体计时器)。如果您不想要特定于平台的解决方案来改善时间,您可以在 sleep() 上进行“忙等待”。要做到这一点,您可以延迟睡眠,然后进入一个循环,不断检查经过的时间。

lastTime = perf_counter()
while True:
    currentTime = perf_counter()
    delta = abs(lastTime - currentTime)
    sleep(delay / 2.0)

    while True:
        currentTime = perf_counter()
        if (currentTime - lastTime >= delay):
            sd.play(tone, 22050)
            lastTime = currentTime
            break

这不是一个完美的解决方案,但它会让你更接近。

您可以进一步优化休眠以承担 CPU 负载的延迟部分。