spatialaudio / jackclient-python

🂻 JACK Audio Connection Kit (JACK) Client for Python :snake:
https://jackclient-python.readthedocs.io/
MIT License
131 stars 26 forks source link

More than one callback in `jack.Client.set_process_callback` #101

Closed Stemby closed 3 years ago

Stemby commented 3 years ago

Related to #100: can jack.Client.set_process_callback register more than one process callback?

Thank you!

Carlo

C0nsultant commented 3 years ago

Strictly speaking, no. At least not in the way you're thinking about in https://github.com/spatialaudio/jackclient-python/issues/100#issuecomment-725984668.

Since this framework is really just a nice pythonic wrapper around the JACK API, Client.set_process_callback() only wraps the corresponding C function jack_set_process_callback(). Every time that function is called, the last registered callback is overwritten.

But there is a pretty easy way to accomplish your goal of calling multiple callbacks per cycle per client. Instead of registering multiple callbacks individually, create a wrapper function around your callbacks and register that as the callback.

# you want these two callbacks to be called on every cycle
def process_first(frames):
    # wörkwörk
    pass

def process_last(frames):
    # wörkwörk
    pass
# so instead of
wont_client = jack.Client('wontwork')
wont_client.set_process_callback(process_first)     # will never be called
wont_client.set_process_callback(process_last)      # only this one is actually called
# you create a combining callback
def process_all(frames):
    try:
        process_first(frames)
    except jack.CallbackExit:
        # proper handling recommended
        pass 
    try:
        process_last(frames)
    except jack.CallbackExit:
        # proper handling recommended
        pass
# and register that one
will_client = jack.Client('willwork')
will_client.set_process_callback(process_all)       # will always call both callbacks in a specific order

If you're concerned about performance, do not care about execution order of your sub-callbacks and can guarantee freedom from race conditions, you can run them asynchronously.

Stemby commented 3 years ago

Thank you, @C0nsultant!

mgeier commented 3 years ago

The above example uses pass as a placeholder, but the "proper handling recommended" should imply that the exception should probably not be swallowed but in many cases it should probably be propagated to the main callback with raise.