python 2.7 - usar - Problemas de sincronización en Metronome Script en Python(usando Pygame)
que version de python usar (0)
Estoy tratando de crear un guión de metrónomo que me brinde retroalimentación de audio y envíe mensajes MIDI a un sintetizador. Uso Python 2.7.5+
y Pygame 1.9.1.release
en Linux Mint 16. Estoy de acuerdo con la parte MIDI. Lo que me preocupa es el tiempo.
En primer lugar, aquí está 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 de tocar un instrumento para.
También busqué en time.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()
... así como pygame.time.Clock()
, específicamente pygame.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 produjo los mismos problemas. Aunque, debo admitir, cuando probé estos ejemplos mínimos, la solución de pygame.time
fue muy estable. El problema aquí es que en mi guión actual hago algunos cálculos (como incrementar contadores y enviar mensajes MIDI) dentro del ciclo while que parecen influir en el tiempo que toma el bucle y el clic comienza a tartamudear y tropezar.
Miré esta respuesta , pero no entendí la idea de los archivos midi. ¿Puede eso 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 de proceso, pero no se notó ninguna mejora.
Me pregunto cómo puedo lograr un metrónomo estable como 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 forma inteligente de usar la variante estable de pygame.time
y hacer el procesamiento en otro lugar?
Si es de alguna utilidad: aquí está el bucle while
actual 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 negra, lo que aumenta significativamente la demanda de precisión.