Search code examples
pythontimetimer

Precise loop timing in Python


For this project I'm designing a sequencer/drummachine that should be able to send MIDI notes with a precise tempo. Example: 16 notes per 2 seconds (i.e. in music terminology sixteen 1/16-notes per bar at BPM 120), i.e. one note every 125 milliseconds.

I'm thinking about:

import time

def midi_note_send(...):
    ...

while True:
    midi_note_send(...)
    time.sleep(0.125)

If I do like this, how to be sure it will be exactly 125 milliseconds? Isn't there a risk that 1000 iterations of this loop will be using 126 seconds instead of 125 seconds? If so, how to have a more precise loop?

Final note: a good drummachine should be able to keep a 120 BPM rythm during 1 hour, with a precision error < 1 second.
Used platform: Linux + RaspberryPi but this question is valid in general.


Solution

  • As I showed here

    import time
    def drummer():
        counter = 0
        # time.sleep(time.time() * 8 % 1 / 8) # enable to sync clock for demo
        while counter < 60 * 8:
            counter += 1
            print time.time()
            time.sleep(.125 - time.time() * 8 % 1 / 8)
    

    This timer adjusts every beat and realigns.

    And the adjustment takes almost no time:

    timeit.timeit("time.time() * 8 % 1 / 8", number=1000000)
    0.2493131160736084
    

    which means every time it does that it takes about 0.25 microseconds

    and for accuracy:

    1488490895.000160
    1488490895.125177
    1488490895.250167
    1488490895.375151
    1488490895.500166
    1488490895.625179
    1488490895.750178
    1488490895.875153
    

    ~28 microseconds of drift between notes. Running it locally for a longer time yields ~130μs of total drift (+- 65μs), but, as it syncs to the clock every beat, it won't deviate over time.