【问题标题】:How can I do a precise metronome?我怎样才能做一个精确的节拍器?
【发布时间】:2018-12-25 15:30:32
【问题描述】:

我试着做一个非常简单的节拍器,它以 30 bpm 的速度工作:

While True:
    winsound.Beep(1000, 200)
    time.sleep(2 - 0.2)

然后,我打开手机上的节拍器应用,同时电脑里发出哔哔声,随着时间的推移,它变得越来越不精确。 还有另一种方法来做“time.sleep()”吗?甚至是“time.sleep()”的内疚吗?

【问题讨论】:

  • 如果你需要一个真正的计时器,不要依赖睡眠间隔。运行您的间隔轮询,然后检查时钟时间。前几天我在 Nodejs 中遇到了这个问题,我确信该解决方案可以轻松适应 Python。 stackoverflow.com/questions/49540098/… - 实际上:您知道计时器开始时的时钟时间,您知道节拍器应该“滴答”的时钟时间,因此运行轮询器的速度要快于节拍器滴答声,并在 BPM 值表明您应该滴答时滴答作响。

标签: python python-3.x time metronome


【解决方案1】:

这在多任务操作系统上很难做到:系统很难为您提供您所要求的确切sleep 延迟。有关详细信息,请参阅How accurate is python's time.sleep()?。

但是我们可以通过测量时间跨度和调整睡眠延迟来相当接近。 Python 3.3+ 提供了time.perf_counter,它应该非常擅长测量时间间隔,尽管确切的精度取决于您的操作系统和硬件。

这是一个简单的演示,它仅打印每个滴答的请求时间延迟和测量的时间延迟之间的差异。最初的输出有点草率,但它很快就会稳定下来,给出在请求间隔的 10 微秒内的滴答声。但是,播放声音比打印到终端需要更多的系统资源,这可能会影响此技术的精度。为获得最佳结果,请尽量减少计算机上的任务负载,尤其是单核计算机。

我在这里将延迟设置为 0.2 秒 = 300 bpm。较慢的节拍率可能会提供更少的精度,因为在每个睡眠周期中有更多时间让 CPU 执行其他可能导致睡眠时间比请求长一点的任务。

from time import sleep, perf_counter

delay = d = 0.2
print(60 / delay, 'bpm')
prev = perf_counter()
for i in range(20):
    sleep(d)
    t = perf_counter()
    delta = t - prev - delay
    print('{:+.9f}'.format(delta))
    d -= delta
    prev = t

典型输出

300.0 bpm
+0.000262488
+0.000151862
-0.000019085
-0.000011358
+0.000023078
-0.000015817
-0.000004357
+0.000009283
-0.000012252
+0.000020515
-0.000009061
+0.000003249
-0.000011482
+0.000029230
+0.000001554
-0.000023614
-0.000003286
+0.000000127
-0.000003732
+0.000016311

这些结果来自运行 Linux YMMV 的旧单核 32 位 2GHz 机器。

【讨论】:

  • 那么对于节拍器的所有速度没有真正的解决方案吗?我不能克服这个吗?
  • @Python 您可以使用 delay = d = 60 / bpm 将 BPM 设置为您想要的任何内容。错误通常很小,大多小于一毫秒,通常小于那。例如,我刚刚在 30 BPM 上对其进行了测试,错误大多在 5 微秒左右。而且由于它们往往会定期在正负之间交替,因此长期漂移应该非常小。但是你必须在你的系统上以不同的速度运行它才能看到你得到的结果。
猜你喜欢
  • 2019-09-01
  • 1970-01-01
  • 2021-08-17
  • 1970-01-01
  • 2012-08-02
  • 2021-04-13
  • 1970-01-01
  • 2021-10-25
  • 2014-01-03
相关资源
最近更新 更多