Problemas de tiempo en Metronome Script en Python (usando Pygame)
Estoy tratando de escribir un guión de metrónomo que me proporcione comentarios de audio y envíe mensajes MIDI a un sintetizador. yo sueloPython 2.7.5+
yPygame 1.9.1.release
en Linux Mint 16. Estoy de acuerdo con la parte MIDI. Lo que me preocupa es el momento.
En primer lugar, esto es básicamente lo que hago:
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()
Sin embargo, esto es bastante inestable e imposible tocar un instrumento.
También miré entime.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()
...tanto comopygame.time.Clock()
específicamentepygame.time.Clock.tick_busy_loop()
, que supuestamente proporciona una mayor precisión al comer más en el procesador:
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
Todo lo cual arrojó los mismos problemas. Aunque, tengo que, dmit, cuando probé estos ejemplos mínimos, elpygame.time
La solución fue muy estable. El problema aquí es que en mi script real hago algunos cálculos (como incrementar los contadores y enviar mensajes MIDI) dentro delwhile
bucle que parece influir en el tiempo que tarda el bucle y el clic comienza a tartamudear y tropezar.
Miréesta respuesta, pero no entendí bien la idea de los archivos midi. ¿Eso podría ayudar aquí? Alguna explicación sería de gran ayuda.
Además, traté de poner
import os
os.nice(-19)
Al principio, para obtener una mayor prioridad del proceso, pero no se notó ninguna mejora.
Me pregunto cómo puedo lograr un metrónomo estable como los DAW comunes como Cubase, Ableton y Logic. Leí sobre el enfoque para generar o pregrabar muestras de audio del tempo en cuestión y encadenar esas muestras para lograr una mayor precisión, pero realmente me gustaría evitar este enfoque, ya que parece muy laborioso.
¿Hay alguna manera inteligente de usar el establo?pygame.time
variante y hacer el procesamiento en otro lugar?
Si es de alguna utilidad: aquí está el actualwhile
Loop que estoy ejecutando:
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
El problema es que el estándar MIDI exige 24 mensajes por cuarto de nota, lo que aumenta significativamente la demanda de precisión.