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

改进用Python编写的节拍器的方法有哪些?,python,audio,metronome,Python,Audio,Metronome,我试图用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: whil

我试图用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,则不会产生声音。在较慢的节奏中,我可以听到metronme与点击之间的间隔不太一致。我已经运行过,与这个答案的作者相比,我的结果非常差(在运行6核3.9GHz 64位windows时,我使用了“旧单核32位2GHz机器”):

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

在mac上运行代码时,时间上的不一致是显而易见的,但节奏也与设定的bpm有相当大的偏差

这主要是因为
sleep()
没有那么准确,但也因为您必须说明自上次事件以来经过的时间。e、 g.调用
sd.play()

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

lastTime=perf_计数器()
尽管如此:
currentTime=性能计数器()
增量=绝对值(上次时间-当前时间)
睡眠(延迟/2.0)
尽管如此:
currentTime=性能计数器()
如果(currentTime-lastTime>=延迟):
sd.播放(音调,22050)
lastTime=当前时间
打破
这不是一个完美的解决方案,但它会让你离得更近


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

您应该创建一个回调函数,并使用传入的值
time.outputBufferDacTime
来计算何时将“咔哒”声写入输出缓冲区。这样,计时将非常准确。
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