[Media_api] new user
Roger Dannenberg
rbd at cs.cmu.edu
Sat Mar 8 18:13:53 PST 2008
> It even says "don't look for a download there"
Well, actually I just added that line in response to your first message,
so maybe it wasn't so obvious the first time you looked.
Yes, having portmidi add latency to the timestamp may seem convoluted
compared to having the app just send absolute timestamps for the
delivery time, but consider that if portmidi sends messages at the
timestamp (without adding latency), then it becomes the application's
job to say "I want to play something at time T, but my maximum latency
is 50ms, so I'll schedule myself at T-50. Then when I wake up and read
the time, I'll add 50ms to figure out all the stuff I need to send now."
That seems convoluted (to me).
The alternative is: "I want to play something at time T, so I'll
schedule myself at T, and when I wake up I'll send whatever needs to be
sent at time T" The actual output will be delayed to T+50ms, and that
may actually be a problem, but consider that if you are outputing audio
as well, and you set the midi latency to equal the audio buffer
duration, then the audio and midi will be synchronized -- with audio,
you have no timestamps, so audio is going to behave much like the
portmidi model, and you really don't have a choice.
I can see the logic in both approaches, but either way you think about
it, it's a small amount of adding or subtracting.
Note that with MIDI THRU, you are really limited by system latency so
you really should have a high-priority thread doing both THRU and MIDI
generation. If you buffer stuff ahead and then MIDI input arrives that
you want to forward to the output, (with portmidi,) messages go out in
order (no sorting by timestamps), so the forwarded messages may be
delayed. It might be possible to open two output streams and use one for
timestamped MIDI and one for THRU. This would then use the underlying
OS-level MIDI system to do the merging. Portmidi isn't really intended
to let you do this though, so I'm not sure if it will work (or on what
systems).
Pm_Read does not block mainly for historical reasons: early Mac and
Windows systems did not use real threads for low-latency processing, so
they could not block or suspend. In most cases, a Midi processing thread
will do work depending upon: MIDI input, timed events in a queue, and
user actions. If you suspend waiting for input, you might not run when
it's time to perform a timed event or respond to a user action, so
generally you end up polling anyway. There are other approaches, and
polling is generally frowned upon (I'm even teaching Intro to OS at
Carnegie Mellon, and this is really heresy in most of the OS world) but
it's interesting that polling (compared to being waked up by something
like Unix select() waiting on many devices) is more and more efficient
as load increases. In real-time systems, it's performance under load
that really matters.
I agree with most of your comments about SysEx. Another issue is that
SysEx messages are handled in different ways on different platforms.
E.g. I think ALSA does actually buffer full sysex messages until they
are complete to allow for merging. So if PortMidi tried to merge
realtime data and sysex data, I think that would be undone by ALSA.
Merging on other systems can really only be done by the lowest-level
driver because it's not known to the application how many bytes are
queued up in the driver. I agree that PortMidi passes some thorny
problems to the application writer. I think it's better that these
things be worked out there in the app, or in a separate library rather
than hard-wiring more design decisions into the PortMidi API. In other
words, I think we really don't know the "right" way to do this, and
maybe there's not one "right" way.
I'll post a separate message about Nyquist.
-Roger
More information about the media_api
mailing list