spatialaudio / jackclient-python

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

question: simple MIDI beeping #29

Closed phoracek closed 8 years ago

phoracek commented 8 years ago

Hello,

first of all I'd like to thank you for this nice module. It's great to see it's not a dead project.

I have a problem/question. Let's say I want to create a simple application which writes MIDI beeps on output, Morse code for example. How can I do that? In all examples there is some trigger, like MIDI input, but I want my application to send those signals whenever it wants. Can I do it without callbacks?

I tried this, but it does not work:

import jack

client = jack.Client("MYMIDI")
outport = client.midi_outports.register("output")

@client.set_process_callback
def process(frames):
    outport.clear_buffer()
    i = client.frame_time
    outport.write_midi_event(i, (144, 36, 64))
    i += 1000
    outport.write_midi_event(i, (128, 36, 64))

with client:
    input()

Thanks very much, Petr

phoracek commented 8 years ago

I think i figured it out. This is ugly, but it's working. Huray

import jack

client = jack.Client('WRITEDRUMS')
outport = client.midi_outports.register('output')

c = 0

@client.set_process_callback
def process(frames):
    global c
    outport.clear_buffer()
    if c == 0:
        outport.write_midi_event(0, (144, 36, 64))
        c += frames
    elif c > 100000:
        outport.write_midi_event(0, (128, 36, 64))
        c = 0
    else:
        c += frames

with client:
    input()
mgeier commented 8 years ago

Thanks, I'm glad you find my little JACK module useful.

Can I do it without callbacks?

No, the JACK MIDI functions are only supposed to be used from within the process callback. Some of the other Python-JACK wrappers might hide the process callback from the user and provide functions to "immediately" send MIDI events, but here you don't have that.

The first argument to write_midi_event() specifies the time in samples starting with 0 at the beginning of the current block.

If you want to create a sequence of events with given time delays (in samples), you'll have to keep a counter similar to what you did in your second example. If the next event in the sequence falls within the current block, you can use write_midi_event() with the remaining time (in samples since the beginning of the current block). If the next event in the sequence falls beyond the current block, you have to somehow keep track of it and just wait for the next call of the callback and handle it there.

I'm sorry if this doesn't make sense ... if you still have troubles, feel free to describe a bit more concretely what sequence of events you would like to send, then I can probably give some less confusing advice ...

BTW, frame_time should only be used outside of the process callback, last_frame_time should be used within the process callback.