Re: Timing mechanism for MIDI ?
Re: Timing mechanism for MIDI ?
- Subject: Re: Timing mechanism for MIDI ?
- From: Brian Willoughby <email@hidden>
- Date: Tue, 9 Dec 2008 04:14:01 -0800
You have not described a situation where scheduling ahead of time is
not possible. A regular metronomic stream of notes is perfectly
predictable. All you need to do is poll the current CoreAudioClock
value, then pick some point in the future, just ahead of the
transport position, and send the whole range of included MIDI events
to CoreMIDI with their proper time stamps. CoreMIDI will take care
of playing everything you give it with precise timing, whether the
various pieces have a common subdivision or not.
The absolute worst thing you can do here is design several threads
which must each deliver time-critical data at the last minute, only
to hand this data over to CoreMIDI which would prefer to have the
information in advance. Not to mention the fact that CoreMIDI can
pass off the responsibility for scheduling of data to the MIDI
hardware itself under ideal conditions. If you don't deliver the
data in advance, you'll get the worst performance because the data
must still transition through several layers from your application to
the hardware, especially if you create several time-critical threads
and add them to the system when none are needed.
Instead of multiple threads, you can simply create multiple data
collections, each with a time reference, a pattern, and a current
position. "Playing" would merely entail merging all of this data
together to send to CoreMIDI, slightly ahead of time. Actually, you
don't even need to merge the data first. You could simply send MIDI
events from each separate data collection directly to CoreMIDI, and
let CoreMIDI sort the events by their requested time stamps.
The only time-critical piece that you have described is when a user
changes a UI parameter that would change or otherwise affect the
notes or their timing. You've not stated whether the application's
metronome sets its own time or reacts to the timing of the UI input.
If the latter, you would check the CoreAudioClock as soon as possible
when the UI is clicked, then store this timing reference in your data
collection associated with that UI. From then on, until the user
clicks again, everything is predictable based on the most recent time
reference. You merely want to avoid scheduling so far ahead that the
user would notice a delay in the reaction of the MIDI events after a
UI change.
I'm also curious why you would trigger a thread to poll UI parameters
when you could do away will polling completely and simply update your
data collection whenever the user interacts with the UI. But perhaps
your description is not as clear as you hoped.
Executive Summary: Let CoreMIDI do all of the time-critical work for
you. Your application should only be concerned with rough estimates
of when MIDI events should happen, just accurately enough to hand the
event data over to CoreMIDI slightly before it should be played. If
all you're doing is managing collections of repeating events, then
you don't even need threads.
In some respects, this is like buffering of audio. CoreAudio does
not call an AU to process each individual sample, but rather collects
samples together by the thousand in buffers that can be processed all
at once. Time gets sliced into chunks that are quite a bit larger
than a single sample. Some latency occurs, but the processing
becomes much more efficient. CoreAudio makes sure this happens with
precise timing, and no gaps in the audio. CoreMIDI can operate much
the same way, but typically with less than thousands of events, and
certainly with no requirements that the "buffers" hold a precise
number of events. You can think of it as a similar time window,
though, and just make sure that your application collects together
all of the events which need to happen in the next time window, and
hand them off to CoreMIDI with a little advance notice. CoreMIDI
will handle all of the heavy lifting with regard to time critical
scheduling, making sure that there will never be a needless thread
transition on a metronome beat which has no MIDI note. Your approach
would undoubtedly have many such thread transitions which produce
nothing, other than spin CPU cycles.
Brian Willoughby
Sound Consulting
On Dec 9, 2008, at 03:00, Aengus Martin wrote:
What if scheduling ahead of time is not possible?
I might describe my situation a bit more clearly. I have a number
of threads each with an input source on its runloop which, when
triggered, goes and checks the current values of certain UI
parameters and uses the values to figure out which MIDI note to
play and then sends it to a previously specified device or software
synth. The program requires each of these MIDI playing threads to
play a regular metronomic stream of notes, e.g. one thread might
output a note every 100 ms, and another every 250 ms, and another
every 123 ms. Generally though, the user would want all of the
threads to output on some simple subdivision on a common tempo.
So I was thinking that an extra 'timer' thread might be used to
send triggers to all of the note players, so that they'd be kept in
synch. I suppose the fundamental time unit would have to be a
common divisor of all the different periods.
Is this a good way to think about it? Or is there something simpler
or better that I can do? What's the best timing accuracy I can hope
for in this real-time scenario?
Thanks,
Aengus.
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Coreaudio-api mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden