Pretty MIDI
Moved the MIDI code over to thread 7 where it now co-exists with the encoder and pushbutton sampling, debouncing, and conditioning code. These are invoked via the 48kHz IRQ, and a 0-9 counter time-slices them (0-7:encoder conditioning; 8:sampling; 9:MIDI) so it's running at 4.8kHz. Each slice gets the full 180MHz / 48kHz / 8 threads = 468 cycles, which is way more than enough (I count 87 cycles max for MIDI). Given this extra contiguous real-time, I was able to reduce the state machine states to 5:
State 0 is inactive, and if the volume hand crosses the trigger point we calculate velocity and go to state 1. In state 1 we transmit CC, pitch bend, and note-on. Then we go to state 2 where we check for activity and transmit MIDI CC data. Then to state 3 where we transmit pitchbend data and check to see if the pitchbend range has been exceeded. The loop from state 2 to 3 and back again is the main path for pitch bending an active note. In state 4 we transmit note-off, and go to state 1 to play a new note (at the same velocity) if still active (which means the pitchbend range was exceeded), otherwise we go inactive.
There is code at the entrance of the state machine which can prevent it from running at all, such as when chan=0 or Mute=1, and transmitting MIDI mute data is handled there.
===============
More Saferer Encoder Velocity
I was taking one last swing at calculating encoder velocity, this time with a bi-modal low-pass filter instead of the funky slew limiter. That was a bust so the slew limiter remains, but in the process I came up with a safer way to apply velocity.
When sampled, the two bit encoder detent delta takes on one of 4 values: {-2, -1, 0, +1}. Since -2 is ambiguous (it could represent -2 or 2) we set it to zero, which leaves: {-1, 0, +1}. Velocity is just accumulated deltas over time, with a leaky bucket type arrangement for when delta = 0. So say a bunch of +1 deltas come in quickly and they peg the velocity at +3. For each +1 delta we issue the encoder delta added to the velocity, for a total of +4 per detent, which speeds up the knob action by 4. What should we do if in the middle of all of this we suddenly get a -1 delta due to an encoder glitch? I think the best action is to always take the delta at face value, but not use the velocity when it differs in sign with the delta. In this case then we accumulate the -1 which drives the velocity downward to +2, but since the velocity is positive we don't use it and only issue the -1 delta, which limits the damage.
How might one implement this?
1. Save the velocity sign (-1 or +1).
2. Multiply velocity and delta.
3. Limit the result of step 2 (set negative values to 0).
4. Multiply the result of step 3 by the velocity sign of step 1.
5. Add the result of step 4 and delta together, issue this value to the software.
To see how this works, plug in some values:
Velocity=+3 and delta=+1: the result is +4.
Velocity=+3 and delta=-1: the result is -1.
Velocity=-3 and delta=+1: the result is +1.
Velocity=-3 and delta=-1: the result is -4.
Viola Voila!
[EDIT] Put more simply: multiplying two things with the same sign will always be positive; multiplying dissimilar signs will always be negative. So just lop off any negative results and restore the sign.