Comments (12)
Multiple MIDI events can be generated for the same offset
.
See my example midi_chords.py, where three notes are generated at the same offset
.
@macdroid53 A few caveats regarding @MaurizioB's code above:
-
Depending on the exact requirements it may be the right thing to use threads, but I would first try to tackle the problem without (additional) threads. You should only create your own threads if you really need them.
-
Within the audio callback, you shouldn't use the blocking
Queue.get()
method. Use get_nowait() instead. This will throw an exception is the queue is empty (see below). -
You shouldn't use
Queue.empty()
, since according to the official docs it's rather useless (since it doesn't guarantee anything): https://docs.python.org/3/library/queue.html#queue.Queue.empty. Just use atry
/except
block and check for the right exception (queue.Empty
). This is more Pythonic anyway (EAFP).
See my example play_file.py for the (hopefully!) proper use of queue.Queue
.
from jackclient-python.
it repeats the MIDI message forever
Yes, that's what you tell it to do.
Starting with client.activate()
, the callback function macsend()
is called once for each audio block, each time generating a MIDI event.
BTW, you should call client.deactivate()
in the end (or use a with
statement) to properly stop the audio callback.
I can't seem to find the correct way to send a single midi message under my control.
When do you want to send that message?
If you describe what you actually want to do, I can probably give you some kind of a hint.
from jackclient-python.
Yes, I read that it will be called each process loop on the web site. So, I really wasn't surprised that this snippet is doing that. (I cobbled it from one of the examples, so it is lacking deactivate due to my lazy cobbling.) ;o
I read through the examples and they all use the callback to do the work. I'm missing the part that says "the work" is only one midi packet.
The simplest example of what I'm trying to do is: When the user clicks a button, my app must send, for example, a control change message to a specific midi channel. (So, for the event in the example, on my mixer, on midi channel 2 set the slider for channel 1, to -10db.)
from jackclient-python.
I usually have a process callback which uses a Queue.
This is an example, taken from a custom program I use.
class JackThread(SomeThreadingClass):
def __init__(self):
[...]
self.client.set_process_callback(self.process)
self.client.activate()
[...]
def output_event(self, event):
self.equeue.put(event)
def process(self, frames):
for port in self.client.midi_outports:
port.clear_buffer()
offset = 0
while not self.equeue.empty():
event = self.equeue.get()
self.client.midi_outports[event[0]].write_midi_event(offset, event[1:])
offset += 1
Then, from the main loop, I just call the output_event
method with the midi event as argument; in your case it might be something like this.
def button_clicked(self):
self.jack_client.output_event(0, 0xB2, 0x01, 0x40)
from jackclient-python.
I haven't tried to run this code, but I do use queues so I get what you're doing.
What does the offset variable and subsequent increment of offset do? Is this actually indexing the jack buffer so the next set of midi bytes are added rather than overwritten when there is more than one event in the queue? (I just looked at the doc and it says the argument is: "Time (in samples) relative to the beginning of the current audio block." Your example increments by 1, so 1 sample per 3 midi bytes? Am I reading/groking that right? )
(I have implemented based on MaurizioB's example, thanks!, that works just I was seeking. I would still like to understand the time/sample argument mentioned above though for future reference.)
from jackclient-python.
I'm glad you sorted that out, even if my example wasn't complete.
About your question, I don't exactly know how it (jack midi) works, but as far as I understand, you can only have a certain number of events per audio block, and they have to be ordered, according to the timing in the current block.
As explained in the help, indeed, unordered events are ignored, but I don't actually know what happens if you write two events with the same order, I haven't tested that yet.
from jackclient-python.
Thank you @mgeier for those tips!
from jackclient-python.
I've looked at play_file.py extensively and I admit that I have not groked every detail. But, I've adjust my code somewhat based on what I think I understand.
At this point I have the following code in my process function
and I have a xrun callback as well:
def process(self, frames):
self.print_error( 'frames={0}'.format(frames))
for port in self.client.midi_outports:
port.clear_buffer()
offset = 0
try:
midievent = self.MIDIsndrqueue.get_nowait()
# while not self.MIDIsndrqueue.empty():
# event = self.MIDIsndrqueue.get()
print('In midi process: {0} || {1}'.format(midievent[0], midievent[1:]))
self.client.midi_outports[midievent[0]].write_midi_event(offset, midievent[1:])
sleep(0.100)
offset += 1
except queue.Empty:
self.print_error('JACK midi queue empty')
But, just siting there it gets xruns:
frames=1024
JACK midi queue empty
An xrun occured, increase JACK's period size?
An xrun occured, increase JACK's period size?
Jack: JackClient::ClientNotify ref = 11 name = jmidi_ShowMixer notify = 3
Jack: JackClient::kXRunCallback
frames=1024
JACK midi queue empty
frames=1024
JACK midi queue empty
An xrun occured, increase JACK's period size?
Jack: JackActivationCount::Signal value = 0 ref = 11
Jack: JackActivationCount::Signal value = 0 ref = 11
frames=1024
JACK midi queue empty
Jack: JackClient::ClientNotify ref = 11 name = jmidi_ShowMixer notify = 3
Jack: JackClient::kXRunCallback
frames=1024
An xrun occured, increase JACK's period size?
JACK midi queue empty
frames=1024
JACK midi queue empty
Jack: JackActivationCount::Signal value = 0 ref = 11
Jack: JackActivationCount::Signal value = 0 ref = 11
frames=1024
So, I don't get why it would xrun when nothing is being processed. And how does one increase JACK's period? Can that be done in code based on buffer size, etc.? Or do the settings have to be adjusted from a JACK controller like QJackctl?
It also gets an xrun every time I something is queued. I basically send 3 byte single midi commands, is the buffer in the client that small by default?
from jackclient-python.
I don't get why it would xrun when nothing is being processed.
Well that's not quite true, you are doing plenty in your process callback.
Did you try it with an actually empty callback?
Strictly speaking, you shouldn't even print stuff in the process callback.
But I guess the real problem is this:
sleep(0.100)
I don't know which exact function this is (it might be time.sleep()
from the standard library?), but are you really sleeping 0.1 seconds here?
Why are you doing that?
You should never sleep for any amount of time in the process callback, except if you want to deliberately cause xruns!
If it's really 0.1 seconds, you should think for a moment what that means: Assuming that you use a sampling rate of 48000 Hz and a block size of 1024 frames, playing back one frame takes 0.021333 seconds. Obviously, your process callback must not take longer than that. Now if you sleep 0.1 seconds, that's five times as long!
Apart from that, you still use offset += 1
.
If you don't really need this, please remove it.
And how does one increase JACK's period? Can that be done in code based on buffer size, etc.?
This might work by assigning a new value to self.client.blocksize
, see http://jackclient-python.readthedocs.io/#jack.Client.blocksize.
But it probably makes more sense to choose the block size when starting the JACK daemon.
Or do the settings have to be adjusted from a JACK controller like QJackctl?
Yes, that's typically where you would do that.
Or via command line options if you are starting jackd
manually.
I basically send 3 byte single midi commands, is the buffer in the client that small by default?
I don't think so. I guess the problem is somewhere else.
You should provide a minimal but runnable code example, then I can also try it and help find the problem.
from jackclient-python.
So, I removed the sleep (it was indeed a time.sleep() call). I had put it there attempting to debug what I thought was a timing issue with the moving faders on one of the mixers. The xruns have quieted down to occasionally. (I should have known better having written plenty of interrupt callbacks for micro-controllers.) My bad... :(
I guess I don't get what the offset is, but, I removed the offset += 1 and it seems to work. Does it offset into a ring buffer for large blocks of data when the buffer is not empty?
from jackclient-python.
Good. You can probably tweak some JACK settings to completely get rid of xruns.
offset
is much simpler than you probably think. In the docs it's called time
: http://jackclient-python.readthedocs.io/#jack.OwnMidiPort.write_midi_event.
It's just the time when you want your MIDI event to be sent. And this time is given in samples relative to the beginning of the current audio block.
If you want to send your event as soon as possible, just use offset = 0
.
Note that write_midi_event()
might raise a JackError
, you should check for that, just to be sure.
If you want to send multiple events at the same time anyway, it's probably easier to use reserve_midi_event()
, which returns an empty buffer if anything goes wrong.
Unless you have more questions, can you please close this issue?
from jackclient-python.
Ok, I was definitely making offset out to be more complicated than it is. Thanks for the enlightenment!
And, thanks again for the help.
from jackclient-python.
Related Issues (20)
- Audio + MIDI HOT 13
- More than one callback in `jack.Client.set_process_callback` HOT 3
- Jack keeps sending last MIDI messages HOT 1
- negative xrun times HOT 4
- Real-time plotting example HOT 4
- Wrong kind of system capture HOT 2
- FR: jack.Ringbuffer example HOT 6
- Anyway to check if client is activated HOT 2
- Is there a way to get the precise time that each period is played? HOT 4
- Example program for playing audio data from memory? HOT 2
- Library not found on Apple silicon HOT 8
- plot get_array() data in real-time HOT 5
- jack client closes itself just after start HOT 13
- playing sound in 3 speaker devices HOT 2
- "operands could not be broadcast together with shapes" error playing sound HOT 6
- How To Access Multiple Soundcard? HOT 4
- API for starting and controlling a JACK server? HOT 21
- Segfault during import HOT 5
- JackOpenError when (re)creating clients with identical name HOT 3
- midi_file_player.py + multiprocessing HOT 7
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from jackclient-python.