-
Notifications
You must be signed in to change notification settings - Fork 28
Description
Hi and thanks for the great library, been using it for years!
What's the best way to detect if the last process callback lead to an xrun? Here's my use case: I'm sending MIDI, which works 99% of the time. But when an xrun occurs, the MIDI events aren't sent to connected inputs and on the next process callback I clear the buffer and they're lost forever. Here's how I'm currently doing it:
jack_midi_event_write = jack._lib.jack_midi_event_write
jack_port_get_buffer = jack._lib.jack_port_get_buffer
class Process:
__slots__ = ('_before', '_buffer', '_client', '_port', '_xrun')
def __init__(self, client: jack.Client, port: jack.OwnMidiPort) -> None:
self._before = 0;
self._buffer = jack.RingBuffer(2 ** 8)
self._xrun = threading.Event()
self._client = client
self._port = port
def process(self, frames: int) -> None:
xrun = self._xrun
xrun_set = xrun.is_set()
port = self._port
client = port._client
last_frame_time = client.last_frame_time
blocksize = client.blocksize
if not xrun_set and last_frame_time - blocksize == self._before:
port.clear_buffer()
if xrun_set:
xrun.clear()
self._before = last_frame_time
src_buffer = self._buffer
space = src_buffer.read_space
if space != 0:
data = src_buffer.read(space)
dst_buffer = jack_port_get_buffer(port._ptr, blocksize)
i = 0
while i != space:
jack_midi_event_write(dst_buffer, 0, data[i : i + 3], 3)
i += 3
def handle_xrun(self, delay_usec: float) -> None:
self._xrun.set()
def _append(self, event: Tuple[int, int, int]) -> None:
self._buffer.write(bytes(event))
def note_on(self, note: int) -> None:
self._append((0x99, note, 100))
def note_off(self, note: int) -> None:
self._append((0x89, note, 0))I'm doing two things:
-
I'm comparing
last_frame_time - blocksizeto thelast_frame_timeon the previous process callback. -
Using the
set_xrun_callbackto set athreading.Event()
I'm not sure if I'm doing any of this correctly, just experimenting to see what works. I know you're not meant to use Python for realtime, but it's working too well to justify moving to C++.
Thanks.