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.