Re: Has nobody used CoreAudio Clock?
Re: Has nobody used CoreAudio Clock?
- Subject: Re: Has nobody used CoreAudio Clock?
- From: Roni Music <email@hidden>
- Date: Wed, 04 May 2011 15:05:23 +0200
Hi,
"Classic MIDI" (using a hardware MIDI cable) is sent with a baud rate of
31.25
kBaud or 31250 bits/sec. Each MIDI byte includes a start and a stop bit,
10 bits in total. So one MIDI byte would take 10/31250 -> 0.32 ms to
transmit. A
complete note on message would take 0.96 ms or about 1 ms,
a little less if running status is used.
If you are implementing a MIDI sequencer only (no need to synch to anything
else, audio etc) then you can setup a high resolution/high priority timer
using
pthreads and CFAbsoluteTimeGetCurrent(). I've recently changed my OS X MIDI
sequencer/player from using the old and now
deprecated Time Manager stuff (InstallXTimeTask etc) into using a pthread
timer.
Works great both on Mac OS X and iOS. This way you can create a drift free
timer,
the frequency of the timer decides how much jitter will be introduced.
Myself I'm
using a 500 Hz timer on OS X, on the iPhone I've been experimenting with
lower
values
to avoid to much CPU usage (this may introduce jitter but will not cause any
time drift).
You can then transmit the MIDI events using CoreMIDI/MIDISend or
MusicDevice/MusicDeviceMIDIEvent (OS X only, hope that gets added to iOS in
a
future update).
There are probably other ways to do stuff like this but this has worked fine
for
many years for my software (also easy to port over to Windows or Unix if
wanting
to do that).
Rolf
Brian,
I'm a little unclear- there are several ways to play MIDI using CoreAudio
(although maybe I'm confused about what's considered CoreAudio) including
MIDIPackets and the built in sequencer (MusicPlayer). The sequencer seems
to have good timing accuracy but won't work because we need to update the
sequence in real time. Are you talking about using the timer associated
with MIDIpackets?
I'm familiar with the Edirol device, unfortunately we need to cover
everything, including software synths. We can't do anything about
variations in timing caused by whatever synth the user is employing. I
want
to do two things- keep the time between a note is entered for playback and
the time when it is played back as short as possible, and keep our own
output as accurate as we can manage.
Thanks, Tom
On Tue, May 3, 2011 at 3:07 PM, Brian Willoughby
<email@hidden>wrote:
Hi Tom,
No, I'm not talking about MTC (MIDI Time Code). MTC is completely
independent of CoreMIDI's time stamping and MOTU's MTS. If you want MTC,
then you will have to generate it in your MIDI data stream just like any
other MIDI message. Whether you are using MIDI Clock or MIDI Time Code,
your performance will be improved by the timing accuracy of CoreMIDI,
provided there is a MTS or similar hardware interface in use (otherwise,
CoreMIDI does the best that it can with a generic MIDI device).
Software synths are a different matter, because they combine the timing
difficulties of on-board audio and interface latency on top of the MIDI
timing issues. Software synths will always have a degree of latency that
is
determined by the audio interface, and you'd probably want to adjust for
this in your MIDI sequencer playback engine for the tracks that are
targeted
to internal software synths.
In contrast, you would not want to adjust the timing of external MIDI
synths because you want CoreMIDI to deliver the data on time. The only
exception here would be if you allow your user to manually enter a
latency
value for an external synth - basically a time shift of a track under
user
control.
By the way, 10 ms is the pre-loading time. The accuracy of CoreMIDI and
MTS is a fraction of 1 ms, better even than USB is capable of otherwise.
Classic MIDI has a timing resolution of 32 ns (0.032 ms), so that would
be
the theoretical lower limit of CoreMIDI's timing accuracy unless you're
working with an interface that goes beyond MIDI and USB-MIDI. The
latency
of classic MIDI is higher than USB, of course, because of the lower
bandwidth, but the asynchronous nature of classic MIDI allows it to
greatly
outperform the 1 ms timing jitter of USB-MIDI.
To recap:
Classic MIDI has 32 ns timing accuracy, but any significant amount of
traffic potentially creates a bottleneck where the throughput causes
delays.
Thus, classic MIDI has data-dependent jitter. The advanced timing
features
of CoreMIDI allows highly accurate time stamps, and if a MIDI interface
can
divide the traffic among multiple output ports such that there aren't any
bottlenecks, then that 32 ns timing accuracy is available because the
final
output of any MIDI interface is classic MIDI.
USB-MIDI has approximately 1 ms timing accuracy, which amounts to a lot
of
jitter. There isn't even a strict guarantee that you can rely upon that
1
ms jitter, because the system load might cause a USB-MIDI message
delivery
to be delayed by any number of 1 ms frames. The amount of data, for all
practical purposes, has no effect on this jitter, so you're left with a
totally random jitter or a system-load-dependent jitter.
Advanced USB devices which have a non-USB-MIDI implementation (possibly
as
an optional addition to the USB-MIDI standard) gain the advantages of
both
classic MIDI and USB, at the cost of requiring a custom CoreMIDI driver.
The hardware device and CoreMIDI keep themselves synchronized via the
driver to maintain a highly accurate clock. There are no bottlenecks
since
Full Speed USB is much faster than classic MIDI. Even the random delays
in
USB can be circumvented by delivering the data severals frames in
advance,
enough to guarantee that system load will never delay the data beyond its
"due" date. The hardware then maintains a small buffer of MIDI data that
is
held in waiting until the precise moment that it should be transmitted.
Since the classic MIDI output is capable of 32 ns timing, and the
hardware
device itself is independent of your main CPU, this allows very precise
timing - since the MIDI hardware isn't really doing anything but
real-time
MIDI.
P.S. Edirol also makes (made?) a USB MIDI interface with a switch to
choose between the USB-MIDI standard and a custom protocol with
highly-accurate timing that would make CoreMIDI happy. You can't change
the
switch on the fly - you have to set it before you plug in the USB
connector
- but otherwise it's a great option.
On May 3, 2011, at 14:43, Tom Jeffries wrote:
Brian, I assume you are talking about using MTC? Or does the MIDIPacket
architecture have that level of accuracy? We also want to work with
software synths. How is the clock accuracy when the synth is running on
the
computer rather than being external?
10 ms would be excellent.
On Tue, May 3, 2011 at 2:32 PM, Brian Willoughby <email@hidden>
wrote:
On May 3, 2011, at 13:38, Tom Jeffries wrote:
It's very simple- I have a MIDI sequencer that is playing data that is
updated in real time. I want to use a clock to check to see what has
been
added, and then send the MIDI data out. I can probably get reasonable
accuracy using MIDIPackets, but it seems more direct to take control
of the
playback by use of an accurate clock.
Maybe that's not an option on OS X? I've done this on other operating
systems, I'll be a little surprised if OS X doesn't allow it.
Your research has overlooked a very powerful feature of CoreMIDI: The
ability to queue outgoing events in advance of when they should be
transmitted, such that the system and/or hardware can handle the timing
more
precisely than anything you could hope to do as a new OSX programmer.
Basically, by insisting on handling the timing yourself, the accuracy
will only be as good as you can manage in your code. There are options
for
hardware timing that would not be available to you unless you use the
CoreMIDI time stamping.
What is particularly important to take note of is that some MIDI
interfaces have their own clocking. CoreMIDI is able, via the proper
CoreMIDI driver, to synchronize with the MIDI hardware clock to deliver
MIDI
data in advance of when it should be transmitted. Under such
conditions,
the MIDI hardware holds on to this advance data and then uses its own
clock
to control the timing of data transmission. This is much more precise
than
anything you could do at the software level, especially considering the
latency of the link between the main CPU and the actual MIDI hardware.
Thus, even if you were an advanced OSX kernel programmer, you would
not
have access to the same degree of timing accuracy as the internals of
the
MIDI interface itself.
MIDI Interfaces such as the Emagic AMT-8 / Unitor 8 and various MOTU
interfaces with their proprietary MTS (MIDI Time Stamping) feature
support
this hyper-accurate timing capability of CoreMIDI.
Unfortunately, USB-MIDI is an incredibly flawed design that was created
without the cooperation of the MIDI Manufacturers Association. As a
result,
USB-MIDI has absolutely no control over timing or latency. It's "good
enough" for the price point, but not necessarily good enough for music.
This is a problem because most people buy a generic USB-MIDI
interface,
probably because of the price and because a custom driver is not
needed.
You might think that your code doesn't have to be better than 99% of
the
MIDI interfaces out there, but why go to great lengths to device your
own
timing mechanisms when you can use CoreMIDI? As more people learn
about
MIDI interfaces with advanced hardware timing, your application will
automatically take advantage of the improvements, but without any
special-cased code getting in the way of normal operation with inferior
USB-MIDI interfaces.
Then, the challenge becomes managing your recorded or generated MIDI
output stream such that you can deliver data slightly ahead of the
playback
position. I'm not even sure what Apple recommends, but I'd say that at
least 10 ms in advance would probably be a good idea. Your MIDI
sequencer
should thus be designed to always been looking slightly ahead, so that
CoreMIDI will always have a chance to download the MIDI data stream to
the
MIDI interface in time for ultra-precise timing.
Brian Willoughby
Sound Consulting
_______________________________________________
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