[RESOLVED] Multiple MIDI devices must be defined to support connectivity thru a USB hub on T4 USBhost

kd5rxt-mark

Well-known member
EDIT: This has been resolved. See P#7 for a detailed discussion of the solution, along with a fully working sketch that supports two MIDI devices connected thru a USB hub which is connected to the T4.1 USBhost interface.

EDIT2: Changed the topic title to more accurately reflect my actual mistake which caused the original problem (was "Whether multiple MIDI devices work thru USB hub seems to be plug-order dependent").


I have wrapped up my latest TeensyMIDIPolySynth project & a friend of mine is running it thru its paces to verify whether everything works as designed & expected. One of the tests involves plugging a secondary TMPS into the USBhost port of the primary TMPS & having them both to respond appropriately to MIDI commands & notes (which can originate from traditional MIDI on either TMPS, USB MIDI on either TMPS, and/or USBhostMIDI (such as a USB MIDI keyboard and/or MIDI sequencer) on either TMPS). One possible configuration involves connecting a USB hub to the primary TMPS, to which a USB MIDI keyboard and the secondary TMPS are connected. Whether the secondary TMPS and/or the keyboard work in this cascaded configuration seems to be dependent on which device is plugged in first [ THE PROBLEM TO BE INVESTIGATED ].

I have been able to reproduce the apparent (mis)behavior in a simplified setup. I will describe the successive tests (starting with a very basic setup & progressing to the more complex setups) & the results of each (using the following nomenclature to describe the connectivity, with the specific interface on each device in parentheses):

Code:
T1 = primary Teensy 4.1 - simply because it is easy to access the USBhost interface
T2 = secondary Teensy 4.0 - could also be a T4.1
TAA = Teensy Audio Adapter
USBhub = Sabrent HB-UMP3 powered USB hub (with individual port power switches), typically connected to the USBhost interface of T1 - could probably be any USB hub
KB = MIDIPLUS AKM322 USB MIDI keyboard - could probably be any USB MIDI keyboard, or any MIDI sequencer
PC = Windows PC running Aria Maestosa to generate MIDI notes & controls  - could probably be any MIDI source under any OS
HP = headphone jack on the TAA

<<< Simple MIDI-to-AUDIO setup - PC driven >>>
PC(USB port) ==> (microUSB)T1 + TAA(headphone jack) ==> HP
   - when fed by MIDI notes & controls from the PC
         - [ WORKS ] T1 generates MIDI output audio as expected

<<< Simple MIDI-to-AUDIO setup - KB driven >>>
KB(USB cable) ==> (USBhost)T1 + TAA(headphone jack) ==> HP
   - when fed by MIDI notes & controls from the keyboard
         - [ WORKS ] T1 generates MIDI output audio as expected

<<< Simple MIDI-to-AUDIO setup w/ USB HUB - PC driven >>>
PC(USB port) ==> (microUSB)T1 + TAA(headphone jack) ==> HP
                           T1(USBhost) ==> (USB cable)KB
   - when fed by MIDI notes & controls from the PC
         - [ WORKS ] T1 generates MIDI output audio as expected
   - when fed by MIDI notes & controls from the keyboard
         - [ WORKS ] T1 generates MIDI output audio as expected
    - NOTE: the two MIDI sources work simultaneously

<<< Simple MIDI-to-AUDIO setup w/ USB HUB - PC and/or KB driven >>>
PC(USB port) ==> (microUSB)T1 + TAA(headphone jack) ==> HP
                           T1(USBhost) ==> (USB input)USBhub(USB port) ==> (USB cable)KB
   - when fed by MIDI notes & controls from the PC
         - [ WORKS ] T1 generates MIDI output audio as expected
   - when fed by MIDI notes & controls from the keyboard
         - [ WORKS ] T1 generates MIDI output audio as expected
    - NOTE: the two MIDI sources work simultaneously

<<< Cascaded MIDI-to-AUDIO setup - PC driven >>>
PC(USB port) ==> (microUSB)T1(USBhost) ==> (microUSB)T2 + TAA(headphone jack) ==> HP
   - when fed by MIDI notes & controls from the PC
         - [ WORKS ] T2 generates MIDI output audio as expected

<<< Cascaded MIDI-to-AUDIO setup w/ USB hub - PC driven >>>
PC(USB port) ==> (microUSB)T1(USBhost) ==> (USB input)USBhub(USB port) ==>(microUSB)T2 + TAA(headphone jack) ==> HP
   - when fed by MIDI notes & controls from the PC
          - [ WORKS ] T2 generates MIDI output audio as expected

<<< Cascaded MIDI-to-AUDIO setup w/ USB hub - PC and/or KB driven >>>
PC(USB port) ==> (microUSB)T1(USBhost) ==> (USB input)USBhub(USB port) ==>(microUSB)T2 + TAA(headphone jack) ==> HP
                                                      USBhub(USB port) ==> (USB cable)KB
   - if T2 is plugged into the USBhub, then the keyboard is plugged into the USBhub
         - when fed by MIDI notes & controls from the PC
               - [ WORKS ] T2 generates MIDI output as expected
               - [ FAILS ] keyboard does not generate any MIDI notes or controls (suspect that the MIDI notes & controls are not getting thru the USBhub)
   - if keyboard is plugged into the USBhub, then T2 is plugged into the USBhub
         - when fed by MIDI notes & controls from the keyboard
               - [ WORKS ] keyboard generates MIDI notes & controls (as observed in the Serial Monitor)
               - [ FAILS ] T2 does not generate any MIDI output (suspect that the MIDI notes & controls are not getting thru the USBhub)


Here's the test sketch (programmed identically into both T1 & T2):

Code:
//
// Teensy MIDI USBhost test
//
//   - reads MIDI data & cmds from traditional MIDI, usbMIDI, or USBhost & plays the indicated note(s)
//
//  Arduino IDE Configuration:
//     Tools/Board:           "Teensy 4.0"
//     Tools/USB Type:        "Serial + MIDI"
//     Tools/CPU Speed:       "600MHz"
//     Tools/Optimize:        "Debug"
//     Tools/Keyboard Layout: "US English"
//     Tools/Port:            "COMx Serial (Teensy 4.0)"
//

#define DEBUG_NOTE_MSGS
#define DEBUG_MIDI_NOTE_MSGS
#define DEBUG_USB_MIDI_NOTE_MSGS
#define DEBUG_USBHOST_MIDI_NOTE_MSGS

#include <SPI.h>
#include <USBHost_t36.h>
#include <MIDI.h>
#include <Audio.h>

// GUItool: begin automatically generated code
AudioSynthWaveform       square01;       //xy=94,37.75
AudioOutputI2S           i2s1;           //xy=1431.75,487.75
AudioConnection          patchCord1(square01, 0, i2s1, 0);
AudioConnection          patchCord2(square01, 0, i2s1, 1);
AudioControlSGTL5000     sgtl5000_1;     //xy=1283,157.75
// GUItool: end automatically generated code

#define LOCAL_MIDI_CHANNEL_OMNI -1
int midi_channel = LOCAL_MIDI_CHANNEL_OMNI;

USBHost thisUSB;
USBHub hub1(thisUSB);
USBHub hub2(thisUSB);
USBHub hub3(thisUSB);
USBHub hub4(thisUSB);
MIDIDevice_BigBuffer usbhostMIDI(thisUSB);

MIDI_CREATE_DEFAULT_INSTANCE();

//
// The following pins are used in this (Audio) portion of the Teensy 4.x PolySynth project:
//
// PIN D0       = (not used)
// PIN D1       = (not used)
// PIN D2       = (not used)
// PIN D3       = (not used)
// PIN D4       = (not used)
// PIN D5       = (not used)
// PIN D6       = Audio adapter memory chip select (MEMCS)
// PIN D7       = Audio adapter data in (DIN)
// PIN D8       = Audio adapter data out (DOUT)
// PIN D9       = (not used)
// PIN D10      = Audio adapter SD card chip select (SDCS)
// PIN D11      = Audio adapter SPI data in (MOSI)
// PIN D12      = Audio adapter SPI data out (MISO)
// PIN D13      = Audio adapter SPI serial clock (SCK) + on-board LED
// PIN D14/A0   = (not used)
// PIN D15/A1   = Volume pot on audio adapter
// PIN D16/A2   = EA Receive
// PIN D17/A3   = EA Transmit
// PIN D18/A4   = Audio adapter I2C control data (SDA)
// PIN D19/A5   = Audio adapter I2C control clock (SCL)
// PIN D20/A6   = Audio adapter Left/Right Clock (LRCLK)
// PIN D21/A7   = Audio adapter Bit Clock (BCLK)
// PIN D22/A8   = (not used)
// PIN D23/A9   = Audio adapter Master Clock (MCLK)
// PIN D24/A10  = (not used)
// PIN D25/A11  = (not used)
// PIN D26/A12  = (not used)
// PIN D27/A13  = (not used)
// PIN D28      = (not used)
// PIN D29      = (not used)
// PIN D30      = (not used)
// PIN D31      = (not used)
// PIN D32      = (not used)
// PIN D33      = (not used)
// PIN D34      = (not used)
// PIN D35      = (not used)
// PIN D36      = (not used)
// PIN D37      = (not used)
// PIN D38/A14  = (not used)
// PIN D39/A15  = (not used)
// PIN D40/A16  = (not used)
// PIN D41/A17  = (not used)

#define LED_PIN 13

// MIDI note-to-frequency data from: http://tonalsoft.com/pub/news/pitch-bend.aspx

#define FLOAT_NOTE_C0 16.352
#define FLOAT_NOTE_CS0 17.324
#define FLOAT_NOTE_D0 18.354
#define FLOAT_NOTE_DS0 19.445
#define FLOAT_NOTE_E0 20.602
#define FLOAT_NOTE_F0 21.827
#define FLOAT_NOTE_FS0 23.125
#define FLOAT_NOTE_G0 24.500
#define FLOAT_NOTE_GS0 25.957
#define FLOAT_NOTE_A0 27.500
#define FLOAT_NOTE_AS0 29.135
#define FLOAT_NOTE_B0 30.868
#define FLOAT_NOTE_C1 32.703
#define FLOAT_NOTE_CS1 34.648
#define FLOAT_NOTE_D1 36.708
#define FLOAT_NOTE_DS1 38.891
#define FLOAT_NOTE_E1 41.203
#define FLOAT_NOTE_F1 43.654
#define FLOAT_NOTE_FS1 46.249
#define FLOAT_NOTE_G1 48.999
#define FLOAT_NOTE_GS1 51.913
#define FLOAT_NOTE_A1 55.000
#define FLOAT_NOTE_AS1 58.270
#define FLOAT_NOTE_B1 61.735
#define FLOAT_NOTE_C2 65.406
#define FLOAT_NOTE_CS2 69.296
#define FLOAT_NOTE_D2 73.416
#define FLOAT_NOTE_DS2 77.782
#define FLOAT_NOTE_E2 82.407
#define FLOAT_NOTE_F2 87.307
#define FLOAT_NOTE_FS2 92.499
#define FLOAT_NOTE_G2 97.999
#define FLOAT_NOTE_GS2 103.826
#define FLOAT_NOTE_A2 110.000
#define FLOAT_NOTE_AS2 116.541
#define FLOAT_NOTE_B2 123.471
#define FLOAT_NOTE_C3 130.813
#define FLOAT_NOTE_CS3 138.591
#define FLOAT_NOTE_D3 146.832
#define FLOAT_NOTE_DS3 155.563
#define FLOAT_NOTE_E3 164.814
#define FLOAT_NOTE_F3 174.614
#define FLOAT_NOTE_FS3 184.997
#define FLOAT_NOTE_G3 195.998
#define FLOAT_NOTE_GS3 207.652
#define FLOAT_NOTE_A3 220.000
#define FLOAT_NOTE_AS3 233.082
#define FLOAT_NOTE_B3 246.942
#define FLOAT_NOTE_C4 261.626
#define FLOAT_NOTE_CS4 277.183
#define FLOAT_NOTE_D4 293.665
#define FLOAT_NOTE_DS4 311.127
#define FLOAT_NOTE_E4 329.628
#define FLOAT_NOTE_F4 349.228
#define FLOAT_NOTE_FS4 369.994
#define FLOAT_NOTE_G4 391.995
#define FLOAT_NOTE_GS4 415.305
#define FLOAT_NOTE_A4 440.000
#define FLOAT_NOTE_AS4 466.164
#define FLOAT_NOTE_B4 493.883
#define FLOAT_NOTE_C5 523.251
#define FLOAT_NOTE_CS5 554.365
#define FLOAT_NOTE_D5 587.330
#define FLOAT_NOTE_DS5 622.254
#define FLOAT_NOTE_E5 659.255
#define FLOAT_NOTE_F5 698.456
#define FLOAT_NOTE_FS5 739.989
#define FLOAT_NOTE_G5 783.991
#define FLOAT_NOTE_GS5 830.609
#define FLOAT_NOTE_A5 880.000
#define FLOAT_NOTE_AS5 932.328
#define FLOAT_NOTE_B5 987.767
#define FLOAT_NOTE_C6 1046.502
#define FLOAT_NOTE_CS6 1108.731
#define FLOAT_NOTE_D6 1174.659
#define FLOAT_NOTE_DS6 1244.508
#define FLOAT_NOTE_E6 1318.510
#define FLOAT_NOTE_F6 1396.913
#define FLOAT_NOTE_FS6 1479.978
#define FLOAT_NOTE_G6 1567.982
#define FLOAT_NOTE_GS6 1661.219
#define FLOAT_NOTE_A6 1760.000
#define FLOAT_NOTE_AS6 1864.655
#define FLOAT_NOTE_B6 1975.533
#define FLOAT_NOTE_C7 2093.005
#define FLOAT_NOTE_CS7 2217.461
#define FLOAT_NOTE_D7 2349.318
#define FLOAT_NOTE_DS7 2489.016
#define FLOAT_NOTE_E7 2637.020
#define FLOAT_NOTE_F7 2793.826
#define FLOAT_NOTE_FS7 2959.955
#define FLOAT_NOTE_G7 3135.963
#define FLOAT_NOTE_GS7 3322.438
#define FLOAT_NOTE_A7 3520.000
#define FLOAT_NOTE_AS7 3729.310
#define FLOAT_NOTE_B7 3951.066
#define FLOAT_NOTE_C8 4186.009
#define FLOAT_NOTE_CS8 4434.922
#define FLOAT_NOTE_D8 4698.636
#define FLOAT_NOTE_DS8 4978.032
#define FLOAT_NOTE_E8 5274.041
#define FLOAT_NOTE_F8 5587.651
#define FLOAT_NOTE_FS8 5919.911
#define FLOAT_NOTE_G8 6271.927
#define FLOAT_NOTE_GS8 6644.875
#define FLOAT_NOTE_A8 7040.000
#define FLOAT_NOTE_AS8 7458.620
#define FLOAT_NOTE_B8 7902.133
#define FLOAT_NOTE_C9 8372.018
#define FLOAT_NOTE_CS9 8869.844
#define FLOAT_NOTE_D9 9397.273
#define FLOAT_NOTE_DS9 9956.063
#define FLOAT_NOTE_E9 10548.082
#define FLOAT_NOTE_F9 11175.303
#define FLOAT_NOTE_FS9 11839.822
#define FLOAT_NOTE_G9 12543.854
#define FLOAT_NOTE_GS9 13289.750
#define FLOAT_NOTE_A9 14080.000
#define FLOAT_NOTE_AS9 14917.240
#define FLOAT_NOTE_B9 15804.266
#define FLOAT_NOTE_C10 16744.036

// NOTE: this array includes valid entries for indices 0..120 (to cover the extended range sent by my MIDI keyboard)
const float fNotePitches[] = {
   FLOAT_NOTE_C0, FLOAT_NOTE_CS0, FLOAT_NOTE_D0, FLOAT_NOTE_DS0, FLOAT_NOTE_E0, FLOAT_NOTE_F0, FLOAT_NOTE_FS0, FLOAT_NOTE_G0, FLOAT_NOTE_GS0, FLOAT_NOTE_A0, FLOAT_NOTE_AS0, FLOAT_NOTE_B0,
   FLOAT_NOTE_C1, FLOAT_NOTE_CS1, FLOAT_NOTE_D1, FLOAT_NOTE_DS1, FLOAT_NOTE_E1, FLOAT_NOTE_F1, FLOAT_NOTE_FS1, FLOAT_NOTE_G1, FLOAT_NOTE_GS1, FLOAT_NOTE_A1, FLOAT_NOTE_AS1, FLOAT_NOTE_B1,
   FLOAT_NOTE_C2, FLOAT_NOTE_CS2, FLOAT_NOTE_D2, FLOAT_NOTE_DS2, FLOAT_NOTE_E2, FLOAT_NOTE_F2, FLOAT_NOTE_FS2, FLOAT_NOTE_G2, FLOAT_NOTE_GS2, FLOAT_NOTE_A2, FLOAT_NOTE_AS2, FLOAT_NOTE_B2,
   FLOAT_NOTE_C3, FLOAT_NOTE_CS3, FLOAT_NOTE_D3, FLOAT_NOTE_DS3, FLOAT_NOTE_E3, FLOAT_NOTE_F3, FLOAT_NOTE_FS3, FLOAT_NOTE_G3, FLOAT_NOTE_GS3, FLOAT_NOTE_A3, FLOAT_NOTE_AS3, FLOAT_NOTE_B3,
   FLOAT_NOTE_C4, FLOAT_NOTE_CS4, FLOAT_NOTE_D4, FLOAT_NOTE_DS4, FLOAT_NOTE_E4, FLOAT_NOTE_F4, FLOAT_NOTE_FS4, FLOAT_NOTE_G4, FLOAT_NOTE_GS4, FLOAT_NOTE_A4, FLOAT_NOTE_AS4, FLOAT_NOTE_B4,
   FLOAT_NOTE_C5, FLOAT_NOTE_CS5, FLOAT_NOTE_D5, FLOAT_NOTE_DS5, FLOAT_NOTE_E5, FLOAT_NOTE_F5, FLOAT_NOTE_FS5, FLOAT_NOTE_G5, FLOAT_NOTE_GS5, FLOAT_NOTE_A5, FLOAT_NOTE_AS5, FLOAT_NOTE_B5,
   FLOAT_NOTE_C6, FLOAT_NOTE_CS6, FLOAT_NOTE_D6, FLOAT_NOTE_DS6, FLOAT_NOTE_E6, FLOAT_NOTE_F6, FLOAT_NOTE_FS6, FLOAT_NOTE_G6, FLOAT_NOTE_GS6, FLOAT_NOTE_A6, FLOAT_NOTE_AS6, FLOAT_NOTE_B6,
   FLOAT_NOTE_C7, FLOAT_NOTE_CS7, FLOAT_NOTE_D7, FLOAT_NOTE_DS7, FLOAT_NOTE_E7, FLOAT_NOTE_F7, FLOAT_NOTE_FS7, FLOAT_NOTE_G7, FLOAT_NOTE_GS7, FLOAT_NOTE_A7, FLOAT_NOTE_AS7, FLOAT_NOTE_B7,
   FLOAT_NOTE_C8, FLOAT_NOTE_CS8, FLOAT_NOTE_D8, FLOAT_NOTE_DS8, FLOAT_NOTE_E8, FLOAT_NOTE_F8, FLOAT_NOTE_FS8, FLOAT_NOTE_G8, FLOAT_NOTE_GS8, FLOAT_NOTE_A8, FLOAT_NOTE_AS8, FLOAT_NOTE_B8,
   FLOAT_NOTE_C9, FLOAT_NOTE_CS9, FLOAT_NOTE_D9, FLOAT_NOTE_DS9, FLOAT_NOTE_E9, FLOAT_NOTE_F9, FLOAT_NOTE_FS9, FLOAT_NOTE_G9, FLOAT_NOTE_GS9, FLOAT_NOTE_A9, FLOAT_NOTE_AS9, FLOAT_NOTE_B9,
   FLOAT_NOTE_C10
};


// function headers
void handleNoteOff(byte channel, byte pitch, byte velocity);
void handleNoteOn(byte channel, byte pitch, byte velocity);
void MIDIhandleNoteOff(byte channel, byte pitch, byte velocity);
void MIDIhandleNoteOn(byte channel, byte pitch, byte velocity);
void USBhandleNoteOff(byte channel, byte pitch, byte velocity);
void USBhandleNoteOn(byte channel, byte pitch, byte velocity);
void usbhostMIDIhandleNoteOff(byte channel, byte pitch, byte velocity);
void usbhostMIDIhandleNoteOn(byte channel, byte pitch, byte velocity);


void handleNoteOff(byte channel, byte pitch, byte velocity)
{
   digitalWrite(LED_PIN, HIGH);

#ifdef DEBUG_NOTE_MSGS
   Serial.print("Note Off:             ch=");
   if (channel < 10)
   {
      Serial.print("0");
   }
   Serial.print(channel);
   Serial.print("  pitch=");
   if (pitch < 100)
   {
      Serial.print(" ");
   }
   if (pitch < 10)
   {
      Serial.print(" ");
   }
   Serial.println(pitch);
#endif

   if ((midi_channel == LOCAL_MIDI_CHANNEL_OMNI) || (midi_channel == channel))
   {
      square01.amplitude(0);
   }

   digitalWrite(LED_PIN, LOW);
}  //handleNoteOff()


void handleNoteOn(byte channel, byte pitch, byte velocity)
{
   digitalWrite(LED_PIN, HIGH);

#ifdef DEBUG_NOTE_MSGS
   Serial.print("Note On:              ch=");
   if (channel < 10)
   {
      Serial.print("0");
   }
   Serial.print(channel);

   Serial.print("  pitch=");
   if (pitch < 100)
   {
      Serial.print(" ");
   }
   if (pitch < 10)
   {
      Serial.print(" ");
   }
   Serial.print(pitch);

   Serial.print("  velocity=");
   if (velocity < 100)
   {
      Serial.print(" ");
   }
   if (velocity < 10)
   {
      Serial.print(" ");
   }
   Serial.println(velocity);

   Serial.print(channel);
   Serial.print("  ");
   Serial.print(fNotePitches[pitch]);
   Serial.print("  ");
   Serial.println(float(velocity) / 255.0);
#endif

   if ((midi_channel == LOCAL_MIDI_CHANNEL_OMNI) || (midi_channel == channel))
   {
      square01.frequency(fNotePitches[pitch] / 2.0);
      square01.amplitude(velocity);
   }

   digitalWrite(LED_PIN, LOW);
}  // handleNoteOn


// -----------------------------------------------------------------------------


void loop()
{
   MIDI.read();
   usbMIDI.read();
   usbhostMIDI.read();

   thisUSB.Task();
}  // loop()


void MIDIhandleNoteOff(byte channel, byte pitch, byte velocity)
{
#ifdef DEBUG_MIDI_NOTE_MSGS
   Serial.print("MIDI Note Off:             ch=");
   if (channel < 10)
   {
      Serial.print("0");
   }
   Serial.print(channel);
   Serial.print("  pitch=");
   if (pitch < 100)
   {
      Serial.print(" ");
   }
   if (pitch < 10)
   {
      Serial.print(" ");
   }
   Serial.println(pitch);
#endif

   if ((midi_channel == LOCAL_MIDI_CHANNEL_OMNI) || (midi_channel == channel))
   {
#ifdef DEBUG_USB_MIDI_NOTE_MSGS
      Serial.print("Sending USB MIDI Note Off:             ch=");
      if (channel < 10)
      {
         Serial.print("0");
      }
      Serial.print(channel);
      Serial.print("  pitch=");
      if (pitch < 100)
      {
         Serial.print(" ");
      }
      if (pitch < 10)
      {
         Serial.print(" ");
      }
      Serial.println(pitch);
#endif

      usbMIDI.sendNoteOff(pitch, velocity, channel);

#ifdef DEBUG_USBHOST_MIDI_NOTE_MSGS
      Serial.print("Sending USBhost MIDI Note Off:             ch=");
      if (channel < 10)
      {
         Serial.print("0");
      }
      Serial.print(channel);
      Serial.print("  pitch=");
      if (pitch < 100)
      {
         Serial.print(" ");
      }
      if (pitch < 10)
      {
         Serial.print(" ");
      }
      Serial.println(pitch);
#endif

      usbhostMIDI.sendNoteOff(pitch, velocity, channel);

      handleNoteOff(channel, pitch, velocity);
   }
}  // MIDIhandleNoteOff()


void MIDIhandleNoteOn(byte channel, byte pitch, byte velocity)
{
#ifdef DEBUG_MIDI_NOTE_MSGS
   Serial.print("MIDI Note On:              ch=");
   if (channel < 10)
   {
      Serial.print("0");
   }
   Serial.print(channel);

   Serial.print("  pitch=");
   if (pitch < 100)
   {
      Serial.print(" ");
   }
   if (pitch < 10)
   {
      Serial.print(" ");
   }
   Serial.print(pitch);

   Serial.print("  velocity=");
   if (velocity < 100)
   {
      Serial.print(" ");
   }
   if (velocity < 10)
   {
      Serial.print(" ");
   }
   Serial.println(velocity);

   Serial.print(channel);
   Serial.print("  ");
   Serial.print(fNotePitches[pitch]);
   Serial.print("  ");
   Serial.println(float(velocity) / 255.0);
#endif

   if ((midi_channel == LOCAL_MIDI_CHANNEL_OMNI) || (midi_channel == channel))
   {
#ifdef DEBUG_USB_MIDI_NOTE_MSGS
      Serial.print("Sending USB MIDI Note On:              ch=");
      if (channel < 10)
      {
         Serial.print("0");
      }
      Serial.print(channel);

      Serial.print("  pitch=");
      if (pitch < 100)
      {
         Serial.print(" ");
      }
      if (pitch < 10)
      {
         Serial.print(" ");
      }
      Serial.print(pitch);

      Serial.print("  velocity=");
      if (velocity < 100)
      {
         Serial.print(" ");
      }
      if (velocity < 10)
      {
         Serial.print(" ");
      }
      Serial.println(velocity);

      Serial.print(channel);
      Serial.print("  ");
      Serial.print(fNotePitches[pitch]);
      Serial.print("  ");
      Serial.println(float(velocity) / 255.0);
#endif

      usbMIDI.sendNoteOn(pitch, velocity, channel);

#ifdef DEBUG_USBHOST_MIDI_NOTE_MSGS
      Serial.print("Sending USBhost MIDI Note On:              ch=");
      if (channel < 10)
      {
         Serial.print("0");
      }
      Serial.print(channel);

      Serial.print("  pitch=");
      if (pitch < 100)
      {
         Serial.print(" ");
      }
      if (pitch < 10)
      {
         Serial.print(" ");
      }
      Serial.print(pitch);

      Serial.print("  velocity=");
      if (velocity < 100)
      {
         Serial.print(" ");
      }
      if (velocity < 10)
      {
         Serial.print(" ");
      }
      Serial.println(velocity);

      Serial.print(channel);
      Serial.print("  ");
      Serial.print(fNotePitches[pitch]);
      Serial.print("  ");
      Serial.println(float(velocity) / 255.0);
#endif

      usbhostMIDI.sendNoteOn(pitch, velocity, channel);

      handleNoteOn(channel, pitch, velocity);
   }
}  // MIDIhandleNoteOn()


void setup()
{
   Serial.begin(57600);

   pinMode(LED_PIN, OUTPUT);

   usbMIDI.setHandleNoteOn(handleNoteOn);  // Put only the name of the function
   usbMIDI.setHandleNoteOff(handleNoteOff);

   MIDI.setHandleNoteOn(MIDIhandleNoteOn);  // Put only the name of the function
   MIDI.setHandleNoteOff(MIDIhandleNoteOff);

   usbMIDI.setHandleNoteOn(USBhandleNoteOn);
   usbMIDI.setHandleNoteOff(USBhandleNoteOff);

   usbhostMIDI.setHandleNoteOn(usbhostMIDIhandleNoteOn);
   usbhostMIDI.setHandleNoteOff(usbhostMIDIhandleNoteOff);

   AudioNoInterrupts();

   AudioMemory(18);

   sgtl5000_1.enable();

   square01.amplitude(0.5);
   square01.begin(WAVEFORM_SQUARE);

   sgtl5000_1.volume(0.25);

   AudioInterrupts();

   // start the USBhost for MIDI inputs/devices
   usbhostMIDI.begin();

   // Initiate MIDI communications, listen to all channels
   MIDI.begin(MIDI_CHANNEL_OMNI);
}  // setup()


void USBhandleNoteOff(byte channel, byte pitch, byte velocity)
{
#ifdef DEBUG_USB_MIDI_NOTE_MSGS
   Serial.print("USB MIDI Note Off:             ch=");
   if (channel < 10)
   {
      Serial.print("0");
   }
   Serial.print(channel);
   Serial.print("  pitch=");
   if (pitch < 100)
   {
      Serial.print(" ");
   }
   if (pitch < 10)
   {
      Serial.print(" ");
   }
   Serial.println(pitch);
#endif

   if ((midi_channel == LOCAL_MIDI_CHANNEL_OMNI) || (midi_channel == channel))
   {
#ifdef DEBUG_MIDI_NOTE_MSGS
      Serial.print("Sending MIDI Note Off:             ch=");
      if (channel < 10)
      {
         Serial.print("0");
      }
      Serial.print(channel);
      Serial.print("  pitch=");
      if (pitch < 100)
      {
         Serial.print(" ");
      }
      if (pitch < 10)
      {
         Serial.print(" ");
      }
      Serial.println(pitch);
#endif

      MIDI.sendNoteOff(pitch, velocity, channel);

#ifdef DEBUG_USBHOST_MIDI_NOTE_MSGS
      Serial.print("Sending USBhost MIDI Note Off:             ch=");
      if (channel < 10)
      {
         Serial.print("0");
      }
      Serial.print(channel);
      Serial.print("  pitch=");
      if (pitch < 100)
      {
         Serial.print(" ");
      }
      if (pitch < 10)
      {
         Serial.print(" ");
      }
      Serial.println(pitch);
#endif

      usbhostMIDI.sendNoteOff(pitch, velocity, channel);

      handleNoteOff(channel, pitch, velocity);
   }
}  // USBhandleNoteOff()


void USBhandleNoteOn(byte channel, byte pitch, byte velocity)
{
#ifdef DEBUG_USB_MIDI_NOTE_MSGS
   Serial.print("USB MIDI Note On:              ch=");
   if (channel < 10)
   {
      Serial.print("0");
   }
   Serial.print(channel);

   Serial.print("  pitch=");
   if (pitch < 100)
   {
      Serial.print(" ");
   }
   if (pitch < 10)
   {
      Serial.print(" ");
   }
   Serial.print(pitch);

   Serial.print("  velocity=");
   if (velocity < 100)
   {
      Serial.print(" ");
   }
   if (velocity < 10)
   {
      Serial.print(" ");
   }
   Serial.println(velocity);

   Serial.print(channel);
   Serial.print("  ");
   Serial.print(fNotePitches[pitch]);
   Serial.print("  ");
   Serial.println(float(velocity) / 255.0);
#endif

   if ((midi_channel == LOCAL_MIDI_CHANNEL_OMNI) || (midi_channel == channel))
   {
#ifdef DEBUG_MIDI_NOTE_MSGS
      Serial.print("Sending MIDI Note On:              ch=");
      if (channel < 10)
      {
         Serial.print("0");
      }
      Serial.print(channel);

      Serial.print("  pitch=");
      if (pitch < 100)
      {
         Serial.print(" ");
      }
      if (pitch < 10)
      {
         Serial.print(" ");
      }
      Serial.print(pitch);

      Serial.print("  velocity=");
      if (velocity < 100)
      {
         Serial.print(" ");
      }
      if (velocity < 10)
      {
         Serial.print(" ");
      }
      Serial.println(velocity);

      Serial.print(channel);
      Serial.print("  ");
      Serial.print(fNotePitches[pitch]);
      Serial.print("  ");
      Serial.println(float(velocity) / 255.0);
#endif

      MIDI.sendNoteOn(pitch, velocity, channel);

#ifdef DEBUG_USBHOST_MIDI_NOTE_MSGS
      Serial.print("Sending USBhost MIDI Note On:              ch=");
      if (channel < 10)
      {
         Serial.print("0");
      }
      Serial.print(channel);

      Serial.print("  pitch=");
      if (pitch < 100)
      {
         Serial.print(" ");
      }
      if (pitch < 10)
      {
         Serial.print(" ");
      }
      Serial.print(pitch);

      Serial.print("  velocity=");
      if (velocity < 100)
      {
         Serial.print(" ");
      }
      if (velocity < 10)
      {
         Serial.print(" ");
      }
      Serial.println(velocity);

      Serial.print(channel);
      Serial.print("  ");
      Serial.print(fNotePitches[pitch]);
      Serial.print("  ");
      Serial.println(float(velocity) / 255.0);
#endif

      usbhostMIDI.sendNoteOn(pitch, velocity, channel);

      handleNoteOn(channel, pitch, velocity);
   }
}  // USBhandleNoteOn()


// MIDI message callback - note off via usbhostMIDI
void usbhostMIDIhandleNoteOff(byte channel, byte pitch, byte velocity)
{
#ifdef DEBUG_USBHOST_MIDI_NOTE_MSGS
   Serial.print("USBhost MIDI Note Off:             ch=");
   if (channel < 10)
   {
      Serial.print("0");
   }
   Serial.print(channel);
   Serial.print("  pitch=");
   if (pitch < 100)
   {
      Serial.print(" ");
   }
   if (pitch < 10)
   {
      Serial.print(" ");
   }
   Serial.println(pitch);
#endif

   if ((midi_channel == LOCAL_MIDI_CHANNEL_OMNI) || (midi_channel == channel))
   {
#ifdef DEBUG_MIDI_NOTE_MSGS
      Serial.print("Sending MIDI Note Off:             ch=");
      if (channel < 10)
      {
         Serial.print("0");
      }
      Serial.print(channel);
      Serial.print("  pitch=");
      if (pitch < 100)
      {
         Serial.print(" ");
      }
      if (pitch < 10)
      {
         Serial.print(" ");
      }
      Serial.println(pitch);
#endif

      MIDI.sendNoteOff(pitch, velocity, channel);

#ifdef DEBUG_USB_MIDI_NOTE_MSGS
      Serial.print("Sending USB MIDI Note Off:             ch=");
      if (channel < 10)
      {
         Serial.print("0");
      }
      Serial.print(channel);
      Serial.print("  pitch=");
      if (pitch < 100)
      {
         Serial.print(" ");
      }
      if (pitch < 10)
      {
         Serial.print(" ");
      }
      Serial.println(pitch);
#endif

      usbMIDI.sendNoteOff(pitch, velocity, channel);

      handleNoteOff(channel, pitch, velocity);
   }
}  // usbhostMIDIhandleNoteOff()


// MIDI message callback - note on via usbhostMIDI
void usbhostMIDIhandleNoteOn(byte channel, byte pitch, byte velocity)
{
#ifdef DEBUG_USBHOST_MIDI_NOTE_MSGS
   Serial.print("USBhost MIDI Note On:              ch=");
   if (channel < 10)
   {
      Serial.print("0");
   }
   Serial.print(channel);

   Serial.print("  pitch=");
   if (pitch < 100)
   {
      Serial.print(" ");
   }
   if (pitch < 10)
   {
      Serial.print(" ");
   }
   Serial.print(pitch);

   Serial.print("  velocity=");
   if (velocity < 100)
   {
      Serial.print(" ");
   }
   if (velocity < 10)
   {
      Serial.print(" ");
   }
   Serial.println(velocity);

   Serial.print(channel);
   Serial.print("  ");
   Serial.print(fNotePitches[pitch]);
   Serial.print("  ");
   Serial.println(float(velocity) / 255.0);
#endif

   if ((midi_channel == LOCAL_MIDI_CHANNEL_OMNI) || (midi_channel == channel))
   {
#ifdef DEBUG_MIDI_NOTE_MSGS
      Serial.print("Sending MIDI Note On:              ch=");
      if (channel < 10)
      {
         Serial.print("0");
      }
      Serial.print(channel);

      Serial.print("  pitch=");
      if (pitch < 100)
      {
         Serial.print(" ");
      }
      if (pitch < 10)
      {
         Serial.print(" ");
      }
      Serial.print(pitch);

      Serial.print("  velocity=");
      if (velocity < 100)
      {
         Serial.print(" ");
      }
      if (velocity < 10)
      {
         Serial.print(" ");
      }
      Serial.println(velocity);

      Serial.print(channel);
      Serial.print("  ");
      Serial.print(fNotePitches[pitch]);
      Serial.print("  ");
      Serial.println(float(velocity) / 255.0);
#endif

      MIDI.sendNoteOn(pitch, velocity, channel);

#ifdef DEBUG_USB_MIDI_NOTE_MSGS
      Serial.print("Sending USB MIDI Note On:              ch=");
      if (channel < 10)
      {
         Serial.print("0");
      }
      Serial.print(channel);

      Serial.print("  pitch=");
      if (pitch < 100)
      {
         Serial.print(" ");
      }
      if (pitch < 10)
      {
         Serial.print(" ");
      }
      Serial.print(pitch);

      Serial.print("  velocity=");
      if (velocity < 100)
      {
         Serial.print(" ");
      }
      if (velocity < 10)
      {
         Serial.print(" ");
      }
      Serial.println(velocity);

      Serial.print(channel);
      Serial.print("  ");
      Serial.print(fNotePitches[pitch]);
      Serial.print("  ");
      Serial.println(float(velocity) / 255.0);
#endif

      usbMIDI.sendNoteOn(pitch, velocity, channel);

      handleNoteOn(channel, pitch, velocity);
   }
}  // usbhostMIDIhandleNoteOn


// EOF PLACEHOLDER

I am hoping that someone else is able to recreate these same setups & most importantly is able to reproduce the apparent problem when using multiple MIDI devices connected thru a USB hub.

Thanks in advance for taking a look !!

Mark J Culross
KD5RXT
 
Last edited:
First quick glance, I'm wondering how 2 MIDI devices plugged into a hub can work at all? I see 4 hub driver instances so you should be good for the hub, but only 1 MIDI driver instance. How could 2 devices work? Did I miss something?

Code:
USBHost thisUSB;
USBHub hub1(thisUSB);
USBHub hub2(thisUSB);
USBHub hub3(thisUSB);
USBHub hub4(thisUSB);
MIDIDevice_BigBuffer usbhostMIDI(thisUSB);
 
First quick glance, I'm wondering how 2 MIDI devices plugged into a hub can work at all? I see 4 hub driver instances so you should be good for the hub, but only 1 MIDI driver instance. How could 2 devices work? Did I miss something?

Code:
USBHost thisUSB;
USBHub hub1(thisUSB);
USBHub hub2(thisUSB);
USBHub hub3(thisUSB);
USBHub hub4(thisUSB);
MIDIDevice_BigBuffer usbhostMIDI(thisUSB);

@PaulStoffregen:

More than likely, I missed something & this is a case of a misunderstanding on my part !! Would I need two USBhost devices, then two corresponding MIDIDevice_BigBuffer devices each associated with one of those USBhosts ?? Or would that be a single USBhost device (the USBhost interface on the T4), then multiple MIDIDevice_BigBuffer devices, each associated with that single USBhost device ??

I hope that it is easy to imagine the physical case where you have two MIDI devices (e.g. sequencer & keyboard), both feeding the same T4 ?? Or you have one T4 feeding multiple other MIDI devices (e.g. other synths) ??

Thanks for the quick reply !!

Mark J Culross
KD5RXT
 
Last edited:
You need 2 MIDIDevice_BigBuffer. Each MIDI instrument/controller/device you connect gets serviced by 1 of those. To use 2 devices, you need 2 instances.

You only need 1 USBhost. In fact, you can't use more than 1, because Teensy has only 1 USB host port.
 
@PaulStoffregen:

Thanks again for your quick replies. I have pared everything back to the simplest sketch that I can create.

So, with two MIDIDevice_BigBuffer devices, if I call the begin() function on both devices, everything appears to hang (no Serial Monitor output from loop() & I have to press the PROGRAM button to upload an updated sketch) after two passes thru loop(). There is no CrashReport() generated.

If I simply comment out the call to the begin() function on one of the devices (it doesn't matter which), everything runs as expected.

Here's the minimized sketch that I'm using. Do you see anything that I'm obviously doing wrong in this ??

Code:
//
// Teensy MIDI USBhost test
//   as originally submitted to the Teensy forum 20240226
//      (https://forum.pjrc.com/index.php?threads/whether-multiple-midi-devices-work-thru-usb-hub-seems-to-be-plug-order-dependent.74561/post-339860)
//
//   - reads MIDI data & cmds from traditional MIDI, usbMIDI, or USBhost & plays the indicated note(s)
//
//  Arduino IDE Configuration:
//     Tools/Board:           "Teensy 4.1"
//     Tools/USB Type:        "Serial + MIDI"
//     Tools/CPU Speed:       "600MHz"
//     Tools/Optimize:        "Debug"
//     Tools/Keyboard Layout: "US English"
//     Tools/Port:            "COMx Serial (Teensy 4.1)"
//

#include <SPI.h>
#include <USBHost_t36.h>
#include <MIDI.h>

USBHost thisUSB;
USBHub hub1(thisUSB);
USBHub hub2(thisUSB);
USBHub hub3(thisUSB);
USBHub hub4(thisUSB);
MIDIDevice_BigBuffer usbhostMIDIa(thisUSB);
MIDIDevice_BigBuffer usbhostMIDIb(thisUSB);

MIDI_CREATE_DEFAULT_INSTANCE();


void loop()
{
   Serial.println("...loop(): before MIDI.read()");

   MIDI.read();

   Serial.println("...loop(): before usbMIDI.read()");

   usbMIDI.read();

   Serial.println("...loop(): before usbhostMIDIa.read()");

   usbhostMIDIa.read();

   Serial.println("...loop(): before usbhostMIDIb.read()");

   usbhostMIDIb.read();

   Serial.println("...loop(): before thisUSB.Task()");

   thisUSB.Task();

   Serial.println("...loop(): before delay(100)");

   delay(100);
}  // loop()


void setup()
{
   unsigned long check_time;

   Serial.begin(57600);

   check_time = millis();
   while (!Serial && ((millis() - check_time) <= 3000));

   if (CrashReport)
   {
      Serial.print(CrashReport);
   }

   // start the USBhost for MIDI inputs/devices
   usbhostMIDIa.begin();
   usbhostMIDIb.begin();

   // Initiate MIDI communications, listen to all channels
   MIDI.begin(MIDI_CHANNEL_OMNI);
}  // setup()


// EOF PLACEHOLDER
Thanks again !!

Mark J Culross
KD5RXT

EDIT: Sorry, had to fix a cut & paste error on the sketch
 
UPDATE: Using the sketch in P#5 with nothing commented out (unlike what is reported in P#5), everything actually runs fine, as long as the USB hub is not connected. As soon as the USB hub is connected to the T4.1's USBhost interface (the USB hub doesn't even have to have anything connected to it), loop() stops.

Mark J Culross
KD5RXT
 
Last edited:
[RESOLVED]

So, it turns out that I was attempting to call the begin() function on each of the MIDIDevice_BigBuffer devices. This is actually incorrect. Rather, the begin() function should only be called on the single USBhost device.


Here's a fully working test sketch that supports two MIDIDevice_BigBuffer devices connected thru a USB hub which is connected to the USBhost interface on the T4.1 (with this implementation, both MIDI devices connected thru the USB hub can simultaneously generate MIDI notes & controls, & they are all handled independently & simultaneously on all of the different types of MIDI interfaces):

Code:
//
// Teensy MIDI USBhost test
//   as submitted to the Teensy forum 20240226 (https://forum.pjrc.com/index.php?threads/whether-multiple-midi-devices-work-thru-usb-hub-seems-to-be-plug-order-dependent.74561/post-339860)
//
//   - reads MIDI data & cmds from traditional MIDI, usbMIDI, or USBhost & plays the indicated note(s)
//
//  Arduino IDE Configuration:
//     Tools/Board:           "Teensy 4.0"
//     Tools/USB Type:        "Serial + MIDI"
//     Tools/CPU Speed:       "600MHz"
//     Tools/Optimize:        "Debug"
//     Tools/Keyboard Layout: "US English"
//     Tools/Port:            "COMx Serial (Teensy 4.0)"
//

#define DEBUG_NOTE_MSGS
#define DEBUG_MIDI_NOTE_MSGS
#define DEBUG_USB_MIDI_NOTE_MSGS
#define DEBUG_USBHOST_MIDI_NOTE_MSGS

#include <SPI.h>
#include <USBHost_t36.h>
#include <MIDI.h>
#include <Audio.h>

// GUItool: begin automatically generated code
AudioSynthWaveform       square01;       //xy=94,37.75
AudioOutputI2S           i2s1;           //xy=1431.75,487.75
AudioConnection          patchCord1(square01, 0, i2s1, 0);
AudioConnection          patchCord2(square01, 0, i2s1, 1);
AudioControlSGTL5000     sgtl5000_1;     //xy=1283,157.75
// GUItool: end automatically generated code

#define LOCAL_MIDI_CHANNEL_OMNI -1
int midi_channel = LOCAL_MIDI_CHANNEL_OMNI;

USBHost thisUSB;
USBHub hub1(thisUSB);
USBHub hub2(thisUSB);
USBHub hub3(thisUSB);
USBHub hub4(thisUSB);
MIDIDevice_BigBuffer usbhostMIDIa(thisUSB);
MIDIDevice_BigBuffer usbhostMIDIb(thisUSB);

MIDI_CREATE_DEFAULT_INSTANCE();

//
// The following pins are used in this (Audio) portion of the Teensy 4.x PolySynth project:
//
// PIN D0       = (not used)
// PIN D1       = (not used)
// PIN D2       = (not used)
// PIN D3       = (not used)
// PIN D4       = (not used)
// PIN D5       = (not used)
// PIN D6       = Audio adapter memory chip select (MEMCS)
// PIN D7       = Audio adapter data in (DIN)
// PIN D8       = Audio adapter data out (DOUT)
// PIN D9       = (not used)
// PIN D10      = Audio adapter SD card chip select (SDCS)
// PIN D11      = Audio adapter SPI data in (MOSI)
// PIN D12      = Audio adapter SPI data out (MISO)
// PIN D13      = Audio adapter SPI serial clock (SCK) + on-board LED
// PIN D14/A0   = (not used)
// PIN D15/A1   = Volume pot on audio adapter
// PIN D16/A2   = EA Receive
// PIN D17/A3   = EA Transmit
// PIN D18/A4   = Audio adapter I2C control data (SDA)
// PIN D19/A5   = Audio adapter I2C control clock (SCL)
// PIN D20/A6   = Audio adapter Left/Right Clock (LRCLK)
// PIN D21/A7   = Audio adapter Bit Clock (BCLK)
// PIN D22/A8   = (not used)
// PIN D23/A9   = Audio adapter Master Clock (MCLK)
// PIN D24/A10  = (not used)
// PIN D25/A11  = (not used)
// PIN D26/A12  = (not used)
// PIN D27/A13  = (not used)
// PIN D28      = (not used)
// PIN D29      = (not used)
// PIN D30      = (not used)
// PIN D31      = (not used)
// PIN D32      = (not used)
// PIN D33      = (not used)
// PIN D34      = (not used)
// PIN D35      = (not used)
// PIN D36      = (not used)
// PIN D37      = (not used)
// PIN D38/A14  = (not used)
// PIN D39/A15  = (not used)
// PIN D40/A16  = (not used)
// PIN D41/A17  = (not used)

#define LED_PIN 13

// MIDI note-to-frequency data from: http://tonalsoft.com/pub/news/pitch-bend.aspx

#define FLOAT_NOTE_C0 16.352
#define FLOAT_NOTE_CS0 17.324
#define FLOAT_NOTE_D0 18.354
#define FLOAT_NOTE_DS0 19.445
#define FLOAT_NOTE_E0 20.602
#define FLOAT_NOTE_F0 21.827
#define FLOAT_NOTE_FS0 23.125
#define FLOAT_NOTE_G0 24.500
#define FLOAT_NOTE_GS0 25.957
#define FLOAT_NOTE_A0 27.500
#define FLOAT_NOTE_AS0 29.135
#define FLOAT_NOTE_B0 30.868
#define FLOAT_NOTE_C1 32.703
#define FLOAT_NOTE_CS1 34.648
#define FLOAT_NOTE_D1 36.708
#define FLOAT_NOTE_DS1 38.891
#define FLOAT_NOTE_E1 41.203
#define FLOAT_NOTE_F1 43.654
#define FLOAT_NOTE_FS1 46.249
#define FLOAT_NOTE_G1 48.999
#define FLOAT_NOTE_GS1 51.913
#define FLOAT_NOTE_A1 55.000
#define FLOAT_NOTE_AS1 58.270
#define FLOAT_NOTE_B1 61.735
#define FLOAT_NOTE_C2 65.406
#define FLOAT_NOTE_CS2 69.296
#define FLOAT_NOTE_D2 73.416
#define FLOAT_NOTE_DS2 77.782
#define FLOAT_NOTE_E2 82.407
#define FLOAT_NOTE_F2 87.307
#define FLOAT_NOTE_FS2 92.499
#define FLOAT_NOTE_G2 97.999
#define FLOAT_NOTE_GS2 103.826
#define FLOAT_NOTE_A2 110.000
#define FLOAT_NOTE_AS2 116.541
#define FLOAT_NOTE_B2 123.471
#define FLOAT_NOTE_C3 130.813
#define FLOAT_NOTE_CS3 138.591
#define FLOAT_NOTE_D3 146.832
#define FLOAT_NOTE_DS3 155.563
#define FLOAT_NOTE_E3 164.814
#define FLOAT_NOTE_F3 174.614
#define FLOAT_NOTE_FS3 184.997
#define FLOAT_NOTE_G3 195.998
#define FLOAT_NOTE_GS3 207.652
#define FLOAT_NOTE_A3 220.000
#define FLOAT_NOTE_AS3 233.082
#define FLOAT_NOTE_B3 246.942
#define FLOAT_NOTE_C4 261.626
#define FLOAT_NOTE_CS4 277.183
#define FLOAT_NOTE_D4 293.665
#define FLOAT_NOTE_DS4 311.127
#define FLOAT_NOTE_E4 329.628
#define FLOAT_NOTE_F4 349.228
#define FLOAT_NOTE_FS4 369.994
#define FLOAT_NOTE_G4 391.995
#define FLOAT_NOTE_GS4 415.305
#define FLOAT_NOTE_A4 440.000
#define FLOAT_NOTE_AS4 466.164
#define FLOAT_NOTE_B4 493.883
#define FLOAT_NOTE_C5 523.251
#define FLOAT_NOTE_CS5 554.365
#define FLOAT_NOTE_D5 587.330
#define FLOAT_NOTE_DS5 622.254
#define FLOAT_NOTE_E5 659.255
#define FLOAT_NOTE_F5 698.456
#define FLOAT_NOTE_FS5 739.989
#define FLOAT_NOTE_G5 783.991
#define FLOAT_NOTE_GS5 830.609
#define FLOAT_NOTE_A5 880.000
#define FLOAT_NOTE_AS5 932.328
#define FLOAT_NOTE_B5 987.767
#define FLOAT_NOTE_C6 1046.502
#define FLOAT_NOTE_CS6 1108.731
#define FLOAT_NOTE_D6 1174.659
#define FLOAT_NOTE_DS6 1244.508
#define FLOAT_NOTE_E6 1318.510
#define FLOAT_NOTE_F6 1396.913
#define FLOAT_NOTE_FS6 1479.978
#define FLOAT_NOTE_G6 1567.982
#define FLOAT_NOTE_GS6 1661.219
#define FLOAT_NOTE_A6 1760.000
#define FLOAT_NOTE_AS6 1864.655
#define FLOAT_NOTE_B6 1975.533
#define FLOAT_NOTE_C7 2093.005
#define FLOAT_NOTE_CS7 2217.461
#define FLOAT_NOTE_D7 2349.318
#define FLOAT_NOTE_DS7 2489.016
#define FLOAT_NOTE_E7 2637.020
#define FLOAT_NOTE_F7 2793.826
#define FLOAT_NOTE_FS7 2959.955
#define FLOAT_NOTE_G7 3135.963
#define FLOAT_NOTE_GS7 3322.438
#define FLOAT_NOTE_A7 3520.000
#define FLOAT_NOTE_AS7 3729.310
#define FLOAT_NOTE_B7 3951.066
#define FLOAT_NOTE_C8 4186.009
#define FLOAT_NOTE_CS8 4434.922
#define FLOAT_NOTE_D8 4698.636
#define FLOAT_NOTE_DS8 4978.032
#define FLOAT_NOTE_E8 5274.041
#define FLOAT_NOTE_F8 5587.651
#define FLOAT_NOTE_FS8 5919.911
#define FLOAT_NOTE_G8 6271.927
#define FLOAT_NOTE_GS8 6644.875
#define FLOAT_NOTE_A8 7040.000
#define FLOAT_NOTE_AS8 7458.620
#define FLOAT_NOTE_B8 7902.133
#define FLOAT_NOTE_C9 8372.018
#define FLOAT_NOTE_CS9 8869.844
#define FLOAT_NOTE_D9 9397.273
#define FLOAT_NOTE_DS9 9956.063
#define FLOAT_NOTE_E9 10548.082
#define FLOAT_NOTE_F9 11175.303
#define FLOAT_NOTE_FS9 11839.822
#define FLOAT_NOTE_G9 12543.854
#define FLOAT_NOTE_GS9 13289.750
#define FLOAT_NOTE_A9 14080.000
#define FLOAT_NOTE_AS9 14917.240
#define FLOAT_NOTE_B9 15804.266
#define FLOAT_NOTE_C10 16744.036

// NOTE: this array includes valid entries for indices 0..120 (to cover the extended range sent by my MIDI keyboard)
const float fNotePitches[] = {
   FLOAT_NOTE_C0, FLOAT_NOTE_CS0, FLOAT_NOTE_D0, FLOAT_NOTE_DS0, FLOAT_NOTE_E0, FLOAT_NOTE_F0, FLOAT_NOTE_FS0, FLOAT_NOTE_G0, FLOAT_NOTE_GS0, FLOAT_NOTE_A0, FLOAT_NOTE_AS0, FLOAT_NOTE_B0,
   FLOAT_NOTE_C1, FLOAT_NOTE_CS1, FLOAT_NOTE_D1, FLOAT_NOTE_DS1, FLOAT_NOTE_E1, FLOAT_NOTE_F1, FLOAT_NOTE_FS1, FLOAT_NOTE_G1, FLOAT_NOTE_GS1, FLOAT_NOTE_A1, FLOAT_NOTE_AS1, FLOAT_NOTE_B1,
   FLOAT_NOTE_C2, FLOAT_NOTE_CS2, FLOAT_NOTE_D2, FLOAT_NOTE_DS2, FLOAT_NOTE_E2, FLOAT_NOTE_F2, FLOAT_NOTE_FS2, FLOAT_NOTE_G2, FLOAT_NOTE_GS2, FLOAT_NOTE_A2, FLOAT_NOTE_AS2, FLOAT_NOTE_B2,
   FLOAT_NOTE_C3, FLOAT_NOTE_CS3, FLOAT_NOTE_D3, FLOAT_NOTE_DS3, FLOAT_NOTE_E3, FLOAT_NOTE_F3, FLOAT_NOTE_FS3, FLOAT_NOTE_G3, FLOAT_NOTE_GS3, FLOAT_NOTE_A3, FLOAT_NOTE_AS3, FLOAT_NOTE_B3,
   FLOAT_NOTE_C4, FLOAT_NOTE_CS4, FLOAT_NOTE_D4, FLOAT_NOTE_DS4, FLOAT_NOTE_E4, FLOAT_NOTE_F4, FLOAT_NOTE_FS4, FLOAT_NOTE_G4, FLOAT_NOTE_GS4, FLOAT_NOTE_A4, FLOAT_NOTE_AS4, FLOAT_NOTE_B4,
   FLOAT_NOTE_C5, FLOAT_NOTE_CS5, FLOAT_NOTE_D5, FLOAT_NOTE_DS5, FLOAT_NOTE_E5, FLOAT_NOTE_F5, FLOAT_NOTE_FS5, FLOAT_NOTE_G5, FLOAT_NOTE_GS5, FLOAT_NOTE_A5, FLOAT_NOTE_AS5, FLOAT_NOTE_B5,
   FLOAT_NOTE_C6, FLOAT_NOTE_CS6, FLOAT_NOTE_D6, FLOAT_NOTE_DS6, FLOAT_NOTE_E6, FLOAT_NOTE_F6, FLOAT_NOTE_FS6, FLOAT_NOTE_G6, FLOAT_NOTE_GS6, FLOAT_NOTE_A6, FLOAT_NOTE_AS6, FLOAT_NOTE_B6,
   FLOAT_NOTE_C7, FLOAT_NOTE_CS7, FLOAT_NOTE_D7, FLOAT_NOTE_DS7, FLOAT_NOTE_E7, FLOAT_NOTE_F7, FLOAT_NOTE_FS7, FLOAT_NOTE_G7, FLOAT_NOTE_GS7, FLOAT_NOTE_A7, FLOAT_NOTE_AS7, FLOAT_NOTE_B7,
   FLOAT_NOTE_C8, FLOAT_NOTE_CS8, FLOAT_NOTE_D8, FLOAT_NOTE_DS8, FLOAT_NOTE_E8, FLOAT_NOTE_F8, FLOAT_NOTE_FS8, FLOAT_NOTE_G8, FLOAT_NOTE_GS8, FLOAT_NOTE_A8, FLOAT_NOTE_AS8, FLOAT_NOTE_B8,
   FLOAT_NOTE_C9, FLOAT_NOTE_CS9, FLOAT_NOTE_D9, FLOAT_NOTE_DS9, FLOAT_NOTE_E9, FLOAT_NOTE_F9, FLOAT_NOTE_FS9, FLOAT_NOTE_G9, FLOAT_NOTE_GS9, FLOAT_NOTE_A9, FLOAT_NOTE_AS9, FLOAT_NOTE_B9,
   FLOAT_NOTE_C10
};


// function headers
void handleNoteOff(byte channel, byte pitch, byte velocity);
void handleNoteOn(byte channel, byte pitch, byte velocity);
void loop(void);
void MIDIhandleNoteOff(byte channel, byte pitch, byte velocity);
void MIDIhandleNoteOn(byte channel, byte pitch, byte velocity);
void setup();
void USBhandleNoteOff(byte channel, byte pitch, byte velocity);
void USBhandleNoteOn(byte channel, byte pitch, byte velocity);
void usbhostMIDIahandleNoteOff(byte channel, byte pitch, byte velocity);
void usbhostMIDIahandleNoteOn(byte channel, byte pitch, byte velocity);
void usbhostMIDIbhandleNoteOff(byte channel, byte pitch, byte velocity);
void usbhostMIDIbhandleNoteOn(byte channel, byte pitch, byte velocity);


void handleNoteOff(byte channel, byte pitch, byte velocity)
{
   digitalWrite(LED_PIN, HIGH);

#ifdef DEBUG_NOTE_MSGS
   Serial.print("Note Off:             ch=");
   if (channel < 10)
   {
      Serial.print("0");
   }
   Serial.print(channel);
   Serial.print("  pitch=");
   if (pitch < 100)
   {
      Serial.print(" ");
   }
   if (pitch < 10)
   {
      Serial.print(" ");
   }
   Serial.println(pitch);
#endif

   if ((midi_channel == LOCAL_MIDI_CHANNEL_OMNI) || (midi_channel == channel))
   {
      square01.amplitude(0);
   }

   digitalWrite(LED_PIN, LOW);
}  //handleNoteOff()


void handleNoteOn(byte channel, byte pitch, byte velocity)
{
   digitalWrite(LED_PIN, HIGH);

#ifdef DEBUG_NOTE_MSGS
   Serial.print("Note On:              ch=");
   if (channel < 10)
   {
      Serial.print("0");
   }
   Serial.print(channel);

   Serial.print("  pitch=");
   if (pitch < 100)
   {
      Serial.print(" ");
   }
   if (pitch < 10)
   {
      Serial.print(" ");
   }
   Serial.print(pitch);

   Serial.print("  velocity=");
   if (velocity < 100)
   {
      Serial.print(" ");
   }
   if (velocity < 10)
   {
      Serial.print(" ");
   }
   Serial.println(velocity);

   Serial.print(channel);
   Serial.print("  ");
   Serial.print(fNotePitches[pitch]);
   Serial.print("  ");
   Serial.println(float(velocity) / 255.0);
#endif

   if ((midi_channel == LOCAL_MIDI_CHANNEL_OMNI) || (midi_channel == channel))
   {
      square01.frequency(fNotePitches[pitch] / 2.0);
      square01.amplitude(velocity);
   }

   digitalWrite(LED_PIN, LOW);
}  // handleNoteOn


// -----------------------------------------------------------------------------


void loop(void)
{
   MIDI.read();
   usbMIDI.read();
   usbhostMIDIa.read();
   usbhostMIDIb.read();

   thisUSB.Task();
}  // loop()


void MIDIhandleNoteOff(byte channel, byte pitch, byte velocity)
{
#ifdef DEBUG_MIDI_NOTE_MSGS
   Serial.print("MIDI Note Off:             ch=");
   if (channel < 10)
   {
      Serial.print("0");
   }
   Serial.print(channel);
   Serial.print("  pitch=");
   if (pitch < 100)
   {
      Serial.print(" ");
   }
   if (pitch < 10)
   {
      Serial.print(" ");
   }
   Serial.println(pitch);
#endif

   if ((midi_channel == LOCAL_MIDI_CHANNEL_OMNI) || (midi_channel == channel))
   {
#ifdef DEBUG_USB_MIDI_NOTE_MSGS
      Serial.print("Sending USB MIDI Note Off:             ch=");
      if (channel < 10)
      {
         Serial.print("0");
      }
      Serial.print(channel);
      Serial.print("  pitch=");
      if (pitch < 100)
      {
         Serial.print(" ");
      }
      if (pitch < 10)
      {
         Serial.print(" ");
      }
      Serial.println(pitch);
#endif

      usbMIDI.sendNoteOff(pitch, velocity, channel);

#ifdef DEBUG_USBHOST_MIDI_NOTE_MSGS
      Serial.print("Sending USBhost MIDI Note Off:             ch=");
      if (channel < 10)
      {
         Serial.print("0");
      }
      Serial.print(channel);
      Serial.print("  pitch=");
      if (pitch < 100)
      {
         Serial.print(" ");
      }
      if (pitch < 10)
      {
         Serial.print(" ");
      }
      Serial.println(pitch);
#endif

      usbhostMIDIa.sendNoteOff(pitch, velocity, channel);
      usbhostMIDIb.sendNoteOff(pitch, velocity, channel);

      handleNoteOff(channel, pitch, velocity);
   }
}  // MIDIhandleNoteOff()


void MIDIhandleNoteOn(byte channel, byte pitch, byte velocity)
{
#ifdef DEBUG_MIDI_NOTE_MSGS
   Serial.print("MIDI Note On:              ch=");
   if (channel < 10)
   {
      Serial.print("0");
   }
   Serial.print(channel);

   Serial.print("  pitch=");
   if (pitch < 100)
   {
      Serial.print(" ");
   }
   if (pitch < 10)
   {
      Serial.print(" ");
   }
   Serial.print(pitch);

   Serial.print("  velocity=");
   if (velocity < 100)
   {
      Serial.print(" ");
   }
   if (velocity < 10)
   {
      Serial.print(" ");
   }
   Serial.println(velocity);

   Serial.print(channel);
   Serial.print("  ");
   Serial.print(fNotePitches[pitch]);
   Serial.print("  ");
   Serial.println(float(velocity) / 255.0);
#endif

   if ((midi_channel == LOCAL_MIDI_CHANNEL_OMNI) || (midi_channel == channel))
   {
#ifdef DEBUG_USB_MIDI_NOTE_MSGS
      Serial.print("Sending USB MIDI Note On:              ch=");
      if (channel < 10)
      {
         Serial.print("0");
      }
      Serial.print(channel);

      Serial.print("  pitch=");
      if (pitch < 100)
      {
         Serial.print(" ");
      }
      if (pitch < 10)
      {
         Serial.print(" ");
      }
      Serial.print(pitch);

      Serial.print("  velocity=");
      if (velocity < 100)
      {
         Serial.print(" ");
      }
      if (velocity < 10)
      {
         Serial.print(" ");
      }
      Serial.println(velocity);

      Serial.print(channel);
      Serial.print("  ");
      Serial.print(fNotePitches[pitch]);
      Serial.print("  ");
      Serial.println(float(velocity) / 255.0);
#endif

      usbMIDI.sendNoteOn(pitch, velocity, channel);

#ifdef DEBUG_USBHOST_MIDI_NOTE_MSGS
      Serial.print("Sending USBhost MIDI Note On:              ch=");
      if (channel < 10)
      {
         Serial.print("0");
      }
      Serial.print(channel);

      Serial.print("  pitch=");
      if (pitch < 100)
      {
         Serial.print(" ");
      }
      if (pitch < 10)
      {
         Serial.print(" ");
      }
      Serial.print(pitch);

      Serial.print("  velocity=");
      if (velocity < 100)
      {
         Serial.print(" ");
      }
      if (velocity < 10)
      {
         Serial.print(" ");
      }
      Serial.println(velocity);

      Serial.print(channel);
      Serial.print("  ");
      Serial.print(fNotePitches[pitch]);
      Serial.print("  ");
      Serial.println(float(velocity) / 255.0);
#endif

      usbhostMIDIa.sendNoteOn(pitch, velocity, channel);
      usbhostMIDIb.sendNoteOn(pitch, velocity, channel);

      handleNoteOn(channel, pitch, velocity);
   }
}  // MIDIhandleNoteOn()


void setup()
{
   Serial.begin(57600);

   delay(3000);

   Serial.println("...begin");
 
   if (CrashReport)
   {
      Serial.print(CrashReport);
   }

   pinMode(LED_PIN, OUTPUT);

   usbMIDI.setHandleNoteOn(handleNoteOn);  // Put only the name of the function
   usbMIDI.setHandleNoteOff(handleNoteOff);

   MIDI.setHandleNoteOn(MIDIhandleNoteOn);  // Put only the name of the function
   MIDI.setHandleNoteOff(MIDIhandleNoteOff);

   usbMIDI.setHandleNoteOn(USBhandleNoteOn);
   usbMIDI.setHandleNoteOff(USBhandleNoteOff);

   usbhostMIDIa.setHandleNoteOn(usbhostMIDIahandleNoteOn);
   usbhostMIDIa.setHandleNoteOff(usbhostMIDIahandleNoteOff);

   usbhostMIDIb.setHandleNoteOn(usbhostMIDIbhandleNoteOn);
   usbhostMIDIb.setHandleNoteOff(usbhostMIDIbhandleNoteOff);

   AudioNoInterrupts();

   AudioMemory(18);

   sgtl5000_1.enable();

   square01.amplitude(0.5);
   square01.begin(WAVEFORM_SQUARE);

   sgtl5000_1.volume(0.25);

   AudioInterrupts();

   // start the USBhost for MIDI inputs/devices
   thisUSB.begin();

   // Initiate MIDI communications, listen to all channels
   MIDI.begin(MIDI_CHANNEL_OMNI);
}  // setup()


void USBhandleNoteOff(byte channel, byte pitch, byte velocity)
{
#ifdef DEBUG_USB_MIDI_NOTE_MSGS
   Serial.print("USB MIDI Note Off:             ch=");
   if (channel < 10)
   {
      Serial.print("0");
   }
   Serial.print(channel);
   Serial.print("  pitch=");
   if (pitch < 100)
   {
      Serial.print(" ");
   }
   if (pitch < 10)
   {
      Serial.print(" ");
   }
   Serial.println(pitch);
#endif

   if ((midi_channel == LOCAL_MIDI_CHANNEL_OMNI) || (midi_channel == channel))
   {
#ifdef DEBUG_MIDI_NOTE_MSGS
      Serial.print("Sending MIDI Note Off:             ch=");
      if (channel < 10)
      {
         Serial.print("0");
      }
      Serial.print(channel);
      Serial.print("  pitch=");
      if (pitch < 100)
      {
         Serial.print(" ");
      }
      if (pitch < 10)
      {
         Serial.print(" ");
      }
      Serial.println(pitch);
#endif

      MIDI.sendNoteOff(pitch, velocity, channel);

#ifdef DEBUG_USBHOST_MIDI_NOTE_MSGS
      Serial.print("Sending USBhost MIDI Note Off:             ch=");
      if (channel < 10)
      {
         Serial.print("0");
      }
      Serial.print(channel);
      Serial.print("  pitch=");
      if (pitch < 100)
      {
         Serial.print(" ");
      }
      if (pitch < 10)
      {
         Serial.print(" ");
      }
      Serial.println(pitch);
#endif

      usbhostMIDIa.sendNoteOff(pitch, velocity, channel);
      usbhostMIDIb.sendNoteOff(pitch, velocity, channel);

      handleNoteOff(channel, pitch, velocity);
   }
}  // USBhandleNoteOff()


void USBhandleNoteOn(byte channel, byte pitch, byte velocity)
{
#ifdef DEBUG_USB_MIDI_NOTE_MSGS
   Serial.print("USB MIDI Note On:              ch=");
   if (channel < 10)
   {
      Serial.print("0");
   }
   Serial.print(channel);

   Serial.print("  pitch=");
   if (pitch < 100)
   {
      Serial.print(" ");
   }
   if (pitch < 10)
   {
      Serial.print(" ");
   }
   Serial.print(pitch);

   Serial.print("  velocity=");
   if (velocity < 100)
   {
      Serial.print(" ");
   }
   if (velocity < 10)
   {
      Serial.print(" ");
   }
   Serial.println(velocity);

   Serial.print(channel);
   Serial.print("  ");
   Serial.print(fNotePitches[pitch]);
   Serial.print("  ");
   Serial.println(float(velocity) / 255.0);
#endif

   if ((midi_channel == LOCAL_MIDI_CHANNEL_OMNI) || (midi_channel == channel))
   {
#ifdef DEBUG_MIDI_NOTE_MSGS
      Serial.print("Sending MIDI Note On:              ch=");
      if (channel < 10)
      {
         Serial.print("0");
      }
      Serial.print(channel);

      Serial.print("  pitch=");
      if (pitch < 100)
      {
         Serial.print(" ");
      }
      if (pitch < 10)
      {
         Serial.print(" ");
      }
      Serial.print(pitch);

      Serial.print("  velocity=");
      if (velocity < 100)
      {
         Serial.print(" ");
      }
      if (velocity < 10)
      {
         Serial.print(" ");
      }
      Serial.println(velocity);

      Serial.print(channel);
      Serial.print("  ");
      Serial.print(fNotePitches[pitch]);
      Serial.print("  ");
      Serial.println(float(velocity) / 255.0);
#endif

      MIDI.sendNoteOn(pitch, velocity, channel);

#ifdef DEBUG_USBHOST_MIDI_NOTE_MSGS
      Serial.print("Sending USBhost MIDI Note On:              ch=");
      if (channel < 10)
      {
         Serial.print("0");
      }
      Serial.print(channel);

      Serial.print("  pitch=");
      if (pitch < 100)
      {
         Serial.print(" ");
      }
      if (pitch < 10)
      {
         Serial.print(" ");
      }
      Serial.print(pitch);

      Serial.print("  velocity=");
      if (velocity < 100)
      {
         Serial.print(" ");
      }
      if (velocity < 10)
      {
         Serial.print(" ");
      }
      Serial.println(velocity);

      Serial.print(channel);
      Serial.print("  ");
      Serial.print(fNotePitches[pitch]);
      Serial.print("  ");
      Serial.println(float(velocity) / 255.0);
#endif

      usbhostMIDIa.sendNoteOn(pitch, velocity, channel);
      usbhostMIDIb.sendNoteOn(pitch, velocity, channel);

      handleNoteOn(channel, pitch, velocity);
   }
}  // USBhandleNoteOn()


// MIDI message callback - note off via usbhostMIDI
void usbhostMIDIahandleNoteOff(byte channel, byte pitch, byte velocity)
{
#ifdef DEBUG_USBHOST_MIDI_NOTE_MSGS
   Serial.print("USBhost MIDI(a) Note Off:             ch=");
   if (channel < 10)
   {
      Serial.print("0");
   }
   Serial.print(channel);
   Serial.print("  pitch=");
   if (pitch < 100)
   {
      Serial.print(" ");
   }
   if (pitch < 10)
   {
      Serial.print(" ");
   }
   Serial.println(pitch);
#endif

   if ((midi_channel == LOCAL_MIDI_CHANNEL_OMNI) || (midi_channel == channel))
   {
#ifdef DEBUG_MIDI_NOTE_MSGS
      Serial.print("Sending MIDI Note Off:             ch=");
      if (channel < 10)
      {
         Serial.print("0");
      }
      Serial.print(channel);
      Serial.print("  pitch=");
      if (pitch < 100)
      {
         Serial.print(" ");
      }
      if (pitch < 10)
      {
         Serial.print(" ");
      }
      Serial.println(pitch);
#endif

      MIDI.sendNoteOff(pitch, velocity, channel);

#ifdef DEBUG_USB_MIDI_NOTE_MSGS
      Serial.print("Sending USB MIDI Note Off:             ch=");
      if (channel < 10)
      {
         Serial.print("0");
      }
      Serial.print(channel);
      Serial.print("  pitch=");
      if (pitch < 100)
      {
         Serial.print(" ");
      }
      if (pitch < 10)
      {
         Serial.print(" ");
      }
      Serial.println(pitch);
#endif

      usbMIDI.sendNoteOff(pitch, velocity, channel);

      usbhostMIDIb.sendNoteOff(pitch, velocity, channel);

      handleNoteOff(channel, pitch, velocity);
   }
}  // usbhostMIDIahandleNoteOff()


// MIDI message callback - note on via usbhostMIDI
void usbhostMIDIahandleNoteOn(byte channel, byte pitch, byte velocity)
{
#ifdef DEBUG_USBHOST_MIDI_NOTE_MSGS
   Serial.print("USBhost MIDI(a) Note On:              ch=");
   if (channel < 10)
   {
      Serial.print("0");
   }
   Serial.print(channel);

   Serial.print("  pitch=");
   if (pitch < 100)
   {
      Serial.print(" ");
   }
   if (pitch < 10)
   {
      Serial.print(" ");
   }
   Serial.print(pitch);

   Serial.print("  velocity=");
   if (velocity < 100)
   {
      Serial.print(" ");
   }
   if (velocity < 10)
   {
      Serial.print(" ");
   }
   Serial.println(velocity);

   Serial.print(channel);
   Serial.print("  ");
   Serial.print(fNotePitches[pitch]);
   Serial.print("  ");
   Serial.println(float(velocity) / 255.0);
#endif

   if ((midi_channel == LOCAL_MIDI_CHANNEL_OMNI) || (midi_channel == channel))
   {
#ifdef DEBUG_MIDI_NOTE_MSGS
      Serial.print("Sending MIDI Note On:              ch=");
      if (channel < 10)
      {
         Serial.print("0");
      }
      Serial.print(channel);

      Serial.print("  pitch=");
      if (pitch < 100)
      {
         Serial.print(" ");
      }
      if (pitch < 10)
      {
         Serial.print(" ");
      }
      Serial.print(pitch);

      Serial.print("  velocity=");
      if (velocity < 100)
      {
         Serial.print(" ");
      }
      if (velocity < 10)
      {
         Serial.print(" ");
      }
      Serial.println(velocity);

      Serial.print(channel);
      Serial.print("  ");
      Serial.print(fNotePitches[pitch]);
      Serial.print("  ");
      Serial.println(float(velocity) / 255.0);
#endif

      MIDI.sendNoteOn(pitch, velocity, channel);

#ifdef DEBUG_USB_MIDI_NOTE_MSGS
      Serial.print("Sending USB MIDI Note On:              ch=");
      if (channel < 10)
      {
         Serial.print("0");
      }
      Serial.print(channel);

      Serial.print("  pitch=");
      if (pitch < 100)
      {
         Serial.print(" ");
      }
      if (pitch < 10)
      {
         Serial.print(" ");
      }
      Serial.print(pitch);

      Serial.print("  velocity=");
      if (velocity < 100)
      {
         Serial.print(" ");
      }
      if (velocity < 10)
      {
         Serial.print(" ");
      }
      Serial.println(velocity);

      Serial.print(channel);
      Serial.print("  ");
      Serial.print(fNotePitches[pitch]);
      Serial.print("  ");
      Serial.println(float(velocity) / 255.0);
#endif

      usbMIDI.sendNoteOn(pitch, velocity, channel);

      usbhostMIDIb.sendNoteOn(pitch, velocity, channel);

      handleNoteOn(channel, pitch, velocity);
   }
}  // usbhostMIDIahandleNoteOn


// MIDI message callback - note off via usbhostMIDI
void usbhostMIDIbhandleNoteOff(byte channel, byte pitch, byte velocity)
{
#ifdef DEBUG_USBHOST_MIDI_NOTE_MSGS
   Serial.print("USBhost MIDI(b) Note Off:             ch=");
   if (channel < 10)
   {
      Serial.print("0");
   }
   Serial.print(channel);
   Serial.print("  pitch=");
   if (pitch < 100)
   {
      Serial.print(" ");
   }
   if (pitch < 10)
   {
      Serial.print(" ");
   }
   Serial.println(pitch);
#endif

   if ((midi_channel == LOCAL_MIDI_CHANNEL_OMNI) || (midi_channel == channel))
   {
#ifdef DEBUG_MIDI_NOTE_MSGS
      Serial.print("Sending MIDI Note Off:             ch=");
      if (channel < 10)
      {
         Serial.print("0");
      }
      Serial.print(channel);
      Serial.print("  pitch=");
      if (pitch < 100)
      {
         Serial.print(" ");
      }
      if (pitch < 10)
      {
         Serial.print(" ");
      }
      Serial.println(pitch);
#endif

      MIDI.sendNoteOff(pitch, velocity, channel);

#ifdef DEBUG_USB_MIDI_NOTE_MSGS
      Serial.print("Sending USB MIDI Note Off:             ch=");
      if (channel < 10)
      {
         Serial.print("0");
      }
      Serial.print(channel);
      Serial.print("  pitch=");
      if (pitch < 100)
      {
         Serial.print(" ");
      }
      if (pitch < 10)
      {
         Serial.print(" ");
      }
      Serial.println(pitch);
#endif

      usbMIDI.sendNoteOff(pitch, velocity, channel);

      usbhostMIDIa.sendNoteOff(pitch, velocity, channel);

      handleNoteOff(channel, pitch, velocity);
   }
}  // usbhostMIDIbhandleNoteOff()


// MIDI message callback - note on via usbhostMIDI
void usbhostMIDIbhandleNoteOn(byte channel, byte pitch, byte velocity)
{
#ifdef DEBUG_USBHOST_MIDI_NOTE_MSGS
   Serial.print("USBhost MIDI(b) Note On:              ch=");
   if (channel < 10)
   {
      Serial.print("0");
   }
   Serial.print(channel);

   Serial.print("  pitch=");
   if (pitch < 100)
   {
      Serial.print(" ");
   }
   if (pitch < 10)
   {
      Serial.print(" ");
   }
   Serial.print(pitch);

   Serial.print("  velocity=");
   if (velocity < 100)
   {
      Serial.print(" ");
   }
   if (velocity < 10)
   {
      Serial.print(" ");
   }
   Serial.println(velocity);

   Serial.print(channel);
   Serial.print("  ");
   Serial.print(fNotePitches[pitch]);
   Serial.print("  ");
   Serial.println(float(velocity) / 255.0);
#endif

   if ((midi_channel == LOCAL_MIDI_CHANNEL_OMNI) || (midi_channel == channel))
   {
#ifdef DEBUG_MIDI_NOTE_MSGS
      Serial.print("Sending MIDI Note On:              ch=");
      if (channel < 10)
      {
         Serial.print("0");
      }
      Serial.print(channel);

      Serial.print("  pitch=");
      if (pitch < 100)
      {
         Serial.print(" ");
      }
      if (pitch < 10)
      {
         Serial.print(" ");
      }
      Serial.print(pitch);

      Serial.print("  velocity=");
      if (velocity < 100)
      {
         Serial.print(" ");
      }
      if (velocity < 10)
      {
         Serial.print(" ");
      }
      Serial.println(velocity);

      Serial.print(channel);
      Serial.print("  ");
      Serial.print(fNotePitches[pitch]);
      Serial.print("  ");
      Serial.println(float(velocity) / 255.0);
#endif

      MIDI.sendNoteOn(pitch, velocity, channel);

#ifdef DEBUG_USB_MIDI_NOTE_MSGS
      Serial.print("Sending USB MIDI Note On:              ch=");
      if (channel < 10)
      {
         Serial.print("0");
      }
      Serial.print(channel);

      Serial.print("  pitch=");
      if (pitch < 100)
      {
         Serial.print(" ");
      }
      if (pitch < 10)
      {
         Serial.print(" ");
      }
      Serial.print(pitch);

      Serial.print("  velocity=");
      if (velocity < 100)
      {
         Serial.print(" ");
      }
      if (velocity < 10)
      {
         Serial.print(" ");
      }
      Serial.println(velocity);

      Serial.print(channel);
      Serial.print("  ");
      Serial.print(fNotePitches[pitch]);
      Serial.print("  ");
      Serial.println(float(velocity) / 255.0);
#endif

      usbMIDI.sendNoteOn(pitch, velocity, channel);

      usbhostMIDIa.sendNoteOn(pitch, velocity, channel);

      handleNoteOn(channel, pitch, velocity);
   }
}  // usbhostMIDIbhandleNoteOn


// EOF PLACEHOLDER

Mark J Culross
KD5RXT
 
Back
Top