Re: Timing mechanism for MIDI ?
Re: Timing mechanism for MIDI ?
- Subject: Re: Timing mechanism for MIDI ?
- From: "Aengus Martin" <email@hidden>
- Date: Wed, 10 Dec 2008 00:27:03 +1100
Thanks Brian, this has been really helpful. I may have some specific questions trying to implement this, but you've certainly provided a strategy that sounds reasonable.
On Tue, Dec 9, 2008 at 11:14 PM, Brian Willoughby
<email@hidden> wrote:
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.
--
____________________
www.am-process.org
_______________________________________________
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