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.