jack audio - sync application to master

183 views Asked by At

I'm wondering about the correct way of keeping my application in sync with a timebase master application using the jack audio api.

Let's say I have Hydrogen drum machine running in master mode and I want to print a message on every 1/4 note Hydrogen is playing.

This is what I would do intuitive (using python):

#!/usr/bin/env python3

import time
import jack

client = jack.Client('klicker')

def print_msg (last_tick):
    state, pos = client.transport_query()
    if state == jack.ROLLING:
        if pos['tick'] < last_tick:
            print ("klick")

    return pos['tick']

with client:
   last_tick = 0
   while True:
      last_tick = print_msg (last_tick)
      time.sleep(0.00002)

So I'm running a loop with very little sleep time and check in every iteration if the current beat is already over.

This seems a little bit dirty and imprecise to me. So what would the right way of solving this problem?

1

There are 1 answers

0
flappix On

Finally, I found a solution which semms to be more precise:

First, we want to use the process callback instead of an infinite loop.

def process (f):

Every time this callback is called, f number of frames are processed. The sample rate tells us how many frames we will process in 1 second. By multiplying this with 60 and dividing by the number of beats per minute we get the number of frames which are processed in one beat.

#!/usr/bin/env python3

import jack
client = jack.Client('Klick')
frame_counter = 0

@client.set_process_callback
def process (f):
    global frame_counter
    state, pos = client.transport_query()

    if state == jack.ROLLING:
        frame_counter += f

        # how many frames are get processed in 1 beat?
        frames_per_beat = client.samplerate * 60 / pos['beats_per_minute']

        # did we process enough frames for 1 beat?
        if frame_counter >= frames_per_beat:
            print ('klick')
            frame_counter -= frames_per_beat


with client:
    client.activate()
    input()