Teensy 3.6: MIDI and usbMIDI have different calls for a specific function

XFer

Well-known member
Hello,
I'm implementing a test MIDI device with T3.6.

At the moment it just forwards incoming MIDI messages to both a serial MIDI output (DIN) and usb-MIDI.

So, I wrote my handlers for various type of incoming MIDI messages.
For example:

C++:
void timeCodeQuarterFrameHandler(const byte data)
{
....
MIDI.sendTimeCodeQuarterFrame(data);
....

}

My problem: using MIDI class, we have

Code:
MIDI.sendTimeCodeQuarterFrame(data);

which takes 1 argument.
But when trying to push the same content to usbMIDI, the equivalent:

Code:
usbMIDI.sendTimeCodeQuarterFrame(data);

does not exist: it wants 3 arguments (and so I don't know what to pass within my handler, which only has 1 input argument)

C++:
Teensy_MIDIConverter_v2:435: error: no matching function for call to 'usb_midi_class::sendTimeCodeQuarterFrame(const byte&)'
  435 |                 usbMIDI.sendTimeCodeQuarterFrame(data);
      |                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~
In file included from D:\Arduino\hardware\teensy\avr\cores\teensy3/WProgram.h:63,
                 from D:\Arduino\arduino-build-output\pch\Arduino.h:6:
D:\Arduino\hardware\teensy\avr\cores\teensy3/usb_midi.h:216:14: note: candidate: 'void usb_midi_class::sendTimeCodeQuarterFrame(uint8_t, uint8_t, uint8_t)'
  216 |         void sendTimeCodeQuarterFrame(uint8_t type, uint8_t value, uint8_t cable=0) __attribute__((always_inline)) __attribute__((always_inline)) {
      |              ^~~~~~~~~~~~~~~~~~~~~~~~
D:\Arduino\hardware\teensy\avr\cores\teensy3/usb_midi.h:216:14: note:   candidate expects 3 arguments, 1 provided

There are similar issues with other functions, which again need more arguments in their usbMIDI implementations.
Edit: after some cleanup, the only function with different calls between usbMIDI and MIDI is sendTimeCodeQuarterFrame()

Full source code is very large ( > 800 lines) so I cannot paste here; I hope I gave enough infos..?

Edit: using Arduino IDE 1.8.19 and Teensyduino 1.59beta4 (because of all the nice MIDI improvements! :) )

Thanks for any hint
 
Last edited:
MIDI.h has 2 functions for sendTimeCodeQuarterFrame:

sendTimeCodeQuarterFrame(inTypeNibble, inValuesNibble)
sendTimeCodeQuarterFrame(inData)

Teensy's usbMIDI only supports the first of these 2. I'll try to explain why...

All of the usbMIDI transmit functions have an optional extra parameter to specify which virtual cable to use. Even if your situation is the common case of using only 1 cable, the USB MIDI protocol differs from normal serial MIDI. It fundamentally supports up to 16 cables. usbMIDI makes that capability available by adding an extra optional cable number input to all the send functions.

Unfortunately, the original MIDI library send functions weren't designed to able to have an extra parameter. In some cases, like sendTimeCodeQuarterFrame, we just can't support the send function with fewer inputs because adding the extra optional input for the USB cable creates a C++ ambiguous override problem.

This is why usbMIDI only offers the 2 input sendTimeCodeQuarterFrame(), as technically a 3 input functions, but that 3rd input is the cable number which defaults to zero if you give only 2 inputs.

Full source code is very large ( > 800 lines) so I cannot paste here; I hope I gave enough infos..?

I'm only commenting about sendTimeCodeQuarterFrame(), but I will say the C++ ambiguous override problem exists with extending any of the MIDI send functions where a version of the function exists with more inputs and all are a single byte. usbMIDI just can't support those shorter versions and also give access to all 16 virtual cables.
 
Thanks for the explanation Paul, it makes sense of course.

Now: do you have a suggestion to handle my case? Could I simply write the affected handlers as 2-args functions and be done?

Like, for example

C++:
void timeCodeQuarterFrameHandler(byte type, byte value)
{
MIDI.sendTimeCodeQuarterFrame(type, value);
usbMIDI.sendTimeCodeQuarterFrame(type, value);
}

instead of void timeCodeQuarterFrameHandler(byte data) ?
Would it work?

EDIT: seems the answer is no :( , because when I assign the handler

C++:
gInputMIDIUSBDevice.setHandleTimeCodeQuarterFrame(timeCodeQuarterFrameHandler);

it expects a 1-arg handler:

C++:
F:\Progetti\Arduino\Teensy_MIDIConverter_v2\Teensy_MIDIConverter_v2.ino:738:59: warning: invalid conversion from 'void (*)(uint8_t, uint8_t)' {aka 'void (*)(unsigned char, unsigned char)'} to 'void (*)(uint8_t)' {aka 'void (*)(unsigned char)'} [-fpermissive]
  738 |         gInputMIDIUSBDevice.setHandleTimeCodeQuarterFrame(timeCodeQuarterFrameHandler);

so what are my options?

Many thanks for any suggestion
 
Last edited:
Don't want to further messing up my message, anyway I think I found a way.

When I stumble upon a usbMIDI send function which also needs "type" along with "value", I just define a proper const inside the handler, like:

C++:
void timeCodeQuarterFrameHandler(const uint8_t data)
{
  const byte type = 0xF1;
[...]
 
  MIDI.sendTimeCodeQuarterFrame(data);
  usbMIDI.sendTimeCodeQuarterFrame(type, data);
}

am I wrong?
 
Back
Top