View Full Version : USB MIDI missing feature: setHandlePolyPressure, *usb_midi_handlePolyPressure

07-20-2013, 07:50 PM
MIDI messages can be divided into three categories (http://www.midi.org/techspecs/midimessages.php): Channel Voice Messages, System Common Messages and System Real-Time Messages. Of these, the Teesny 3 USB MIDI supports sending all five types of Channel Voice Messages (NoteOff, NoteOn, AfterTouchPoly, ControlChange, ProgramChange, AfterTouchChannel and PitchBend) but only supports receiving (by setting a message handler) four of them. Polyphonic Aftertouch is missing. This looks like a simple oversight.

Relevance: I suspect the impact of this has been slight, because hardware that sends polyphponic after touch needs a pressure or movement sensor per key and has thus tended to be expensive. A well known example is the Vax77 keyboard (http://www.infiniteresponse.com/), which sold for around 3500 USD and was recently discontinued. A new keyboard campaign on indiegogo (http://www.indiegogo.com/projects/ndvr-note-masterkeyboard--88/x/2692640) with hardware starting at 235 USD, might make this lack more relevant. (I just backed that project; thinking about a Teensy-based MIDI to control voltage (CV) interface led to my noticing this missing feature).

Solution: in usb_midi.h add

extern void (*usb_midi_handlePolyPressure)(uint8_t ch, uint8_t note, uint8_t pressure);


inline void setHandlePolyPressure(void (*fptr)(uint8_t channel, uint8_t note, uint8_t pressure)) {
usb_midi_handlePolyPressure = fptr;

In usb_midi.c add

extern void (*usb_midi_handlePolyPressure)(uint8_t ch, uint8_t note, uint8_t pressure) = NULL;

07-22-2013, 02:32 PM
I've added this to my TO-DO list for an upcoming Teensyduino release.

Please make sure you're subscribed to this thread. When a release candidate is ready with this added, I'll post here asking for a confirmation it's fixed.

11-25-2013, 12:31 AM
I know this is now a very old thread.... but indeed this was put on my TO-DO list, and now I'm looking into it.

Currently Teensy's USB MIDI has setHandleAfterTouch(). Isn't that the same thing?

11-25-2013, 04:19 AM
From my understand of MIDI, there's basic 'mono' Aftertouch, which is channel-wide. Whichever key has the highest 'pressure' will define the aftertouch value. Polyphonic Aftertouch is a 2-byte message, one for the note, the next for the pressure of that note.


11-25-2013, 05:48 AM
Hmm I have a couple of soft synths sending polyphonic aftertouch like Moog's animoog and I'm able to get those messages using setHandleVelocityChange, I have the feeling it's the same thing...

11-25-2013, 06:01 AM
the midi 3.2 lib seems to define this:
void MIDI_Class::setHandleAfterTouchPoly ( void(*)(byte channel, byte note, byte pressure) fptr )
Not sure where HandleVelocityChange comes from and why it seems to work with poly aftertouch messages.
I also noticed they had an handler for sysex which would be convenient...

11-25-2013, 04:29 PM
Just checked again and I think the issue is just that the function is not named properly.
If you look at line 228 of usb_api.cpp you can see this :

if (type1 == 0x0A && type2 == 0xA0) {
msg_type = 2; // Poly Pressure
if (handleVelocityChange) (*handleVelocityChange)(c, b2, b3);
goto return_message;
so to comply more with the midi spec handleVelocityChange could be renamed to handleAfterTouchPoly (that's the name in midi 3.2) or handlePolyPressure...

11-25-2013, 04:51 PM
Yes, I agree that a function with the correct parameters is there, and has an odd and misleading name which is why I thought it was missing. Velocity does not change; there is a noteOn velocity and (optionally) a NoteOff velocity per sounded note.
Looking at the function names for sending this info:

void sendNoteOn(uint8_t note, uint8_t velocity, uint8_t channel);
void sendPolyPressure(uint8_t note, uint8_t pressure, uint8_t channel);
void sendControlChange(uint8_t control, uint8_t value, uint8_t channel);
void sendProgramChange(uint8_t program, uint8_t channel);
void sendAfterTouch(uint8_t pressure, uint8_t channel);
void sendPitchBend(uint16_t value, uint8_t channel);
void sendSysEx(uint8_t length, const uint8_t *data);
then for handling them:

inline void setHandleNoteOff(void (*fptr)(uint8_t channel, uint8_t note, uint8_t velocity)) {
handleNoteOff = fptr;
inline void setHandleNoteOn(void (*fptr)(uint8_t channel, uint8_t note, uint8_t velocity)) {
handleNoteOn = fptr;
inline void setHandleVelocityChange(void (*fptr)(uint8_t channel, uint8_t note, uint8_t velocity)) {
handleVelocityChange = fptr;
inline void setHandleControlChange(void (*fptr)(uint8_t channel, uint8_t control, uint8_t value)) {
handleControlChange = fptr;
inline void setHandleProgramChange(void (*fptr)(uint8_t channel, uint8_t program)) {
handleProgramChange = fptr;
inline void setHandleAfterTouch(void (*fptr)(uint8_t channel, uint8_t pressure)) {
handleAfterTouch = fptr;
inline void setHandlePitchChange(void (*fptr)(uint8_t channel, int pitch)) {
handlePitchChange = fptr;
inline void setHandleRealTimeSystem(void (*fptr)(uint8_t realtimebyte)) {
handleRealTimeSystem = fptr;
I suggest two changes.

One, rename setHandleVelocityChange to setHandlePolyPressure for consistency with sendPolyPressure. (That renaming also makes it the same name as my original suggestion in message #1 of this thread).
Document that this handles Polyphonic Aftertouch.

Two, keep the name setHandleAfterTouch but clearly document that it handles Channel Aftertouch. Avoid renaming because this one is most certainly in use in running code.
I think this documentation is needed because people regularly confuse the two types of Aftertouch. (As Paul did for example in this thread, but I have seen a lot of confusion on this subject in many places).