[sdiy] Bunching of MIDI clock messages
rsdio at sounds.wa.com
rsdio at sounds.wa.com
Thu Sep 12 21:23:16 CEST 2013
I have to disagree with one part of Neil's suggestion, even though I
agree in general.
I've written a great deal of firmware with interrupt handlers, and
you certainly want to use "male shopping tactics" (love that
dysphemism). However, I'd also like to allude to that quote
attributed to Einstein, where he suggested to keep things "as simple
as possible, but no simpler." In that light, I say that:
Interrupt routines should do as little as is necessary, but no less.
In this case, it's necessary to process Real-Time MIDI messages
a.s.a.p., which means they must be handled in the interrupt - at
least the critical parts. Thankfully, the MIDI protocol was designed
with the understanding of how it would be implemented, and thus it's
dead simple to detect Real-Time messages. Just mask out the upper 5
bits of each byte, and if all bits are set then it's a Real-Time
message. The interrupt routine code should be able to make this test
in fewer cycles than it takes to store the byte in a buffer, and
that's true even with 8-bit CPU chips from the 1980s. Basically, the
interrupt routine would have two parts; one for Real-Time and the
second half for all other messages.
But in keeping with your rule of keeping interrupt handlers fast,
this then becomes a question of how you implement the code. When
designing the buffer, the clock, active sensing, and all other
aspects that are touched in the interrupt, the code must be designed
to make the interrupt routine run fast. For examples:
A) Active Sensing is probably a counter that it decremented over
time, restored to a maximum count when Active Sensing is received,
and set up to kill all MIDI Notes if the counter runs out. The Real-
Time section of the interrupt really only needs to store the maximum
count into a data structure or register and then get out. This
implementation fits within the rules for interrupt routines.
B) The buffer for MIDI data should not be a C++ object, and it
particularly should not allocate memory when the buffer overflows.
The MIDI buffer should be an efficient structure that can have data
added in as few cycles as possible by the interrupt routine. The code
to pull data out of the buffer is not so critical, but the interrupt
code should be efficient.
C) The internal sequencer clock is very timing sensitive, so it will
probably be implemented by a timer peripheral (vintage synths used an
external timer chip, modern CPU chips have the timer peripheral built
in). The interrupt routine should probably test for a clock message
as soon as it determines that it has received a Real-Time message,
and then the interrupt code should read the timer counter register
and save it away somewhere. It's not necessary to actually calculate
any adjustments based on the MIDI clock message inside the interrupt,
but it is critical that the timing be checked against the reference
during the interrupt. If you put the Real-Time MIDI Clock byte in a
buffer and then check the timing when you pull the byte out of the
buffer, then it will be too late for an accurate measurement of when
the MIDI Clock arrived.
In other words, the interrupt routine should do one very basic step
of MIDI data parsing - determining whether a byte is real-time or not
- but then it's possible to leave the subsequent steps of MIDI
parsing to the routing that is pulling the data out of the buffer.
Theoretically, all MIDI parsing could be handled in the interrupt
with careful coding, but I won't say that it's necessary. Only the
real-time parsing is necessary in the interrupt.
Note that I sort of agree with your assertion that there is no reason
to use polling, except that I think that you've overlooked something
with regard to the definition of polling. If you fill a buffer in an
interrupt routine, and pull MIDI data out of that buffer in normal
mode, then all of that normal code is technically polling the buffer.
The normal code must read the semaphores and buffer pointers to
detect when data has arrived, and that is the definition of polling.
To clarify, it's not the same as polling the hardware itself, e.g.
the UART registers, but it's still polling.
By the way, the rest of Neil's suggestions about a software PLL for
the MIDI clock are dead on.
Brian Willoughby
Sound Consulting
On Sep 12, 2013, at 05:42, Neil Johnson wrote:
> Firstly, minimise processing in interrupt handlers. Interrupt
> handlers should follow male shopping tactics: get in, get it, get out
> FAST! Get the received byte out of the UART, store it in a buffer,
> and bump a semaphore. Any MIDI data parsing should be done on the
> other side of the buffer in normal mode. There is no reason this has
> to be slow, and no reason to use polling.
More information about the Synth-diy
mailing list