Timing-Probleme im Metronom-Skript in Python (mit Pygame)

Ich versuche, ein Metronom-Skript zu schreiben, das mir Audio-Feedback gibt und MIDI-Meldungen an einen Synthesizer sendet. Ich benutzePython 2.7.5+ undPygame 1.9.1.release unter Linux Mint 16. Ich bin mit dem MIDI-Part einverstanden. Was mich stört, ist das Timing.

Zuallererst ist hier im Grunde, was ich tue:

import time
import pygame.mixer

pygame.mixer.init()
sound = pygame.mixer.Sound('click.wav')

interval = 0.5 #should be equivalent to 120 bpm

t0 = time.time()

while True: #infinite loop, use keyboard interrupt Ctrl-C
    if time.time() - t0 >= interval:
        sound.play()
        t0 = time.time()

Dies ist jedoch ziemlich instabil und es ist unmöglich, ein Instrument zu spielen.

Ich sah auch intime.clock():

import time
import pygame.mixer

pygame.mixer.init()
sound = pygame.mixer.Sound('click.wav')

interval = 0.5 #should be equivalent to 120 bpm

t0 = time.clock()

while True:
    if time.clock() - t0 >= interval:
        sound.play()
        t0 = time.clock()

...ebenso gut wiepygame.time.Clock(), speziellpygame.time.Clock.tick_busy_loop(), das angeblich eine bessere Präzision bietet, indem es mehr in den Prozessor hineinfrisst:

import pygame.time
import pygame.mixer

pygame.mixer.init()
#pygame.time has no init function

sound = pygame.mixer.Sound('click.wav')
clock = pygame.time.Clock()

interval = 0.5 #should be equivalent to 120 bpm

time_passed = 0
clock.tick_busy_loop()

while True: #infinite loop, use keyboard interrupt Ctrl-C
    time_passed += clock.tick_busy_loop()
    if time_passed >= interval:
        sound.play()
        time_passed = 0

Alle davon ergaben die gleichen Probleme. Obwohl, ich muss ein, dmit, als ich diese minimalen Beispiele ausprobiert habe, diepygame.time lösung war sehr stabil. Das Problem hierbei ist, dass ich in meinem aktuellen Skript einige Berechnungen (wie das Inkrementieren von Zählern und das Senden von MIDI-Nachrichten) innerhalb des @ -Zählers durchführwhile Schleife, die scheinbar die Zeit beeinflusst, die die Schleife benötigt, und der Klick beginnt zu stottern und zu stolpern.

Ich sahdiese Antwort, aber ich hatte keine Ahnung von den MIDI-Dateien. Darf das hier helfen? Einige Erklärungen wären am hilfreichsten.

Darüber hinaus habe ich versucht, @ setz

import os
os.nice(-19)

Am Anfang, um eine höhere Prozesspriorität zu erreichen, war jedoch keine Verbesserung festzustellen.

Ich frage mich, wie ich ein stabiles Metronom wie bei herkömmlichen DAWs wie Cubase, Ableton und Logic erreichen kann. Ich habe über den Ansatz gelesen, Audio-Samples des fraglichen Tempos zu generieren oder aufzunehmen und diese Samples zu verketten, um eine höhere Präzision zu erzielen, aber ich möchte diesen Ansatz wirklich vermeiden, da er sehr mühsam erscheint.

ibt es eine clevere Möglichkeit, den Stall zu benutzepygame.time Variante und die Verarbeitung woanders machen?

Wenn es von Nutzen ist: Hier ist das aktuellewhile loop ich laufe:

bpm = 80.0
beats_in_one_second = bpm/60.0
midi_send_interval = beats_in_one_second/24.0 #MIDI convention

playing = True
player.write_short(250) #start
frame_count = 0
quarter_count = 0
time_0 = time.time()

while playing:
    if time.time() - time_0 >= midi_send_interval:
        player.write_short(248) #clock tick
        time_0 = time.time()
        frame_count += 1
        if frame_count == 24:
            sound.play()
            quarter_count += 1
            frame_count = 0
            if quarter_count == 16:
                playing = False

player.write_short(252) #stop

Das Problem ist, dass der MIDI-Standard 24 Meldungen pro Viertelnote verlangt, was den Präzisionsbedarf erheblich erhöht.