Python: неточная синхронизация воспроизведения звука с установленным интервалом BPM (<1 с) - PullRequest
0 голосов
/ 17 января 2019

Я пытаюсь создать очень простой метроном на Raspberry Pi, который воспроизводит файл .wav с заданным интервалом, но время звучит неточно. Я действительно не могу понять, почему модуль времени Python является неточным?

Я не думаю, что код, который обрабатывает воспроизведение звука, является узким местом, поскольку, если я помещу его в цикл без таймера, он будет постоянно греметь. С помощью простого кода, приведенного ниже, звук будет проигрываться несколько раз, а затем один удар будет случайным образом выключаться снова и снова.

import pygame
from time import sleep

pygame.mixer.pre_init(44100, -16, 2, 2048)
pygame.mixer.init()
pygame.init()

BPM = 160
sound = pygame.mixer.Sound('sounds/hihat1.wav')


while True:
    sound.play()
    sleep(60/BPM)

Я ожидаю, что звук будет повторяться каждые X миллисекунд с точностью не менее +/- 10 мс или около того. Это нереально? Если это так, пожалуйста, предложите альтернативу.

Ответы [ 2 ]

0 голосов
/ 17 января 2019

проблема заключалась в использовании слишком больших размеров чанков, что, вероятно, приводило к тому, что pygame проигрывал звуки поздно, так как более ранние чанки уже были поставлены в очередь.Мое первое предложение заключалось в том, что я ожидал, что код OP будет медленно сдвигаться со временем, предполагая, что что-то вроде этого будет лучше:

import pygame
from time import time, sleep
import gc

pygame.mixer.pre_init(44100, -16, 2, 256)
pygame.mixer.init()
pygame.init()

BPM = 160
DELTA = 60/BPM

sound = pygame.mixer.Sound('sounds/hihat1.wav')
goal = time()

while True:
    print(time() - goal)
    sound.play()
    goal += DELTA
    gc.collect()
    sleep(goal - time())

, то есть отслеживайте «текущее время» и корректируйте sleepв зависимости от того, сколько времени прошло.Я явно выполняю «сборку мусора» (т.е. gc.collect()) перед каждым сном, чтобы сохранить вещи более детерминированными.

0 голосов
/ 17 января 2019

Когда я тестировал ваш код на моей локальной машине, кажется, что сон не заботится о потоке pygame, поэтому вы получите звук, перекрывающий себя.

Кроме того, я думаю, что вы должны использовать собственный таймер Pygames для отложенных действий.

Можете ли вы попробовать следующий код на вашем py?

import pygame

pygame.mixer.pre_init(44100, -16, 2, 2048)
pygame.mixer.init()
pygame.init()

BPM = 160
sound = pygame.mixer.Sound('sounds/hihat1.wav')

while True:
    sound.play()
    pygame.time.delay(int(sound.get_length()*1000))
    pygame.time.delay(int(60/BPM*1000))
...