How do you send a MIDI control change message using the USB Host Shield library?

Status
Not open for further replies.

SteveO

Member
I'm trying to use the USB Host Shield 2.0 library to send a control change message to a MIDI device. The MIDI device is connected to the Teensy 3.2 via a USB Host Shield. The device set to MIDI channel 2.

I'm not sure how the message should be formatted, I think I need an example to understand the how a CC message should look.

I have verified the USB host shield is working and have use it and the library successfully for other projects

From the library's usbh_midi.cpp file:


/////////////////////////
// MIDI MESAGES
// midi.org/techspecs/
//////////////////////////
// STATUS BYTES
// 0x8n == noteOff
// 0x9n == noteOn
// 0xAn == afterTouch
// 0xBn == controlChange
// n == Channel(0x0-0xf)
//////////////////////////
//DATA BYTE 1
// note# == (0-127)
// or
// control# == (0-119)
//////////////////////////
// DATA BYTE 2
// velocity == (0-127)
// or
// controlVal == (0-127)
///////////////////////////////////////////////////////////////////////////////
// USB-MIDI Event Packets
// usb.org - Universal Serial Bus Device Class Definition for MIDI Devices 1.0
///////////////////////////////////////////////////////////////////////////////
//+-------------+-------------+-------------+-------------+
//| Byte 0 | Byte 1 | Byte 2 | Byte 3 |
//+------+------+-------------+-------------+-------------+
//|Cable | Code | | | |
//|Number|Index | MIDI_0 | MIDI_1 | MIDI_2 |
//| |Number| | | |
//|(4bit)|(4bit)| (8bit) | (8bit) | (8bit) |
//+------+------+-------------+-------------+-------------+
// CN == 0x0-0xf
//+-----+-----------+-------------------------------------------------------------------
//| CIN |MIDI_x size|Description
//+-----+-----------+-------------------------------------------------------------------
//| 0x0 | 1, 2 or 3 |Miscellaneous function codes. Reserved for future extensions.
//| 0x1 | 1, 2 or 3 |Cable events. Reserved for future expansion.
//| 0x2 | 2 |Two-byte System Common messages like MTC, SongSelect, etc.
//| 0x3 | 3 |Three-byte System Common messages like SPP, etc.
//| 0x4 | 3 |SysEx starts or continues
//| 0x5 | 1 |Single-byte System Common Message or SysEx ends with following single byte.
//| 0x6 | 2 |SysEx ends with following two bytes.
//| 0x7 | 3 |SysEx ends with following three bytes.
//| 0x8 | 3 |Note-off
//| 0x9 | 3 |Note-on
//| 0xA | 3 |Poly-KeyPress
//| 0xB | 3 |Control Change
//| 0xC | 2 |Program Change
//| 0xD | 2 |Channel Pressure
//| 0xE | 3 |PitchBend Change
//| 0xF | 1 |Single Byte
//+-----+-----------+------------------------


My sample code, which does not work, i.e. the device does not respond. I think I have the hex values/message wrong.
Code:
#include <usbh_midi.h>
#include <usbhub.h>

USB Usb;
//USBHub Hub(&Usb);
USBH_MIDI  Midi(&Usb);

void setup()
{
  Serial.begin(115200);
  if (Usb.Init() == -1) {
    while (1); //halt
  }//if (Usb.Init() == -1...
  delay( 200 );
}

void loop()
{
  Usb.Task();
  ccOn();
  delay(400);
  ccOff();
  delay(100);
}

//note On
void controlChangeOn(void)
{
  uint8_t buf[3];
  buf[0] = 0x1B; // Control change type message on channel 2 ??
  buf[1] = 0x51; // control change #81
  buf[2] = 127; // turn effect off
  Midi.SendData(buf);
}

//note Off
void controlChangecOff(void)
{
  uint8_t buf[3];
  buf[0] = 0x1B; // Control change type message on channel 2 ??
  buf[1] = 0x51; // control change #81
  buf[2] = 0;   // turn effect off
  Midi.SendData(buf);
}
 
Last edited:
Thanks Pete,

I changed my code to buf[0] = 0xB1; I also noticed I had another mistake in the code above, corrected code with your suggestion below. I'm still not getting a response from my MIDI device. If the CC message is now correct it must be a something else. The device does accept sysex messages via a library called MS3. The device also responds to PC and CC messages from a Raspberry PI. This might not be an easily fixable problem using the USB Host Shield library.

Code:
#include <usbh_midi.h>
#include <usbhub.h>

USB Usb;
//USBHub Hub(&Usb);
USBH_MIDI  Midi(&Usb);

void setup()
{
  Serial.begin(115200);
  if (Usb.Init() == -1) {
    while (1); //halt
  }//if (Usb.Init() == -1...
  delay( 200 );
}

void loop()
{
  Usb.Task();
  controlChangeOn();
  delay(400);
  controlChangecOff();
  delay(400);
}

//note On
void controlChangeOn(void)
{
  uint8_t buf[3];
  buf[0] = 0xB1; // Control change type message on channel 2 ??
  buf[1] = 0x51; // control change #81
  buf[2] = 127; // turn effect off
  Midi.SendData(buf);
}

//note Off
void controlChangecOff(void)
{
  uint8_t buf[3];
  buf[0] = 0xB1; // Control change type message on channel 2 ??
  buf[1] = 0x51; // control change #81
  buf[2] = 0;   // turn effect off
  Midi.SendData(buf);
}
 
It might be difficult to distinguish between no response from the MIDI device (what is it anyway?) and failing to initialize the USB host device.
Print a message when the init fails.
Code:
  if (Usb.Init() == -1) {
    Serial.println("Usb.Init() failed");
    while (1); //halt
  }//if (Usb.Init() == -1...

Pete
 
Ok, I added the Print and it looks like the the USB Host is initializing the host device.

The device is a Boss Katana amplifier. I'm not sure this is going to be easy and really don't expect anyone to help me fix this problem but I'll elaborate anyway. This is the project I'm working on: https://github.com/SteveObert/KatanaUSB_Midi_controller. The code is still very much a work in progress and does not yet include the test code I posted in this thread.

I'm working on adding the expression pedal and have it working with sysex in a limited fashion. However, if I can get it to work with CC messages it will be much more flexible because each effect requires a different sysex message for foot pedal control, but a change control 81 should work for any effect.

In the code below, which is part of the full code, I'm trying to replace MS3.write(FV_PDL, pedalVal1, 1); with Midi.SendData(buf); where buff is CC 81 channel 2 pedalVal1.

Code:
  MIDI.read();

  //handle expression pedal 1 input
  if (millis() - lastRead1 > 40 && exp1Connected_sel == 1) {   // This delay is necessary to prevent overwhelming the MS3 queue

    pedalVal1 = analogRead(8);
    pedalVal1 = map(pedalVal1, exp1Min, exp1Max, 0, 63);     // apply the calibration to the sensor reading
    pedalVal1 = constrain(pedalVal1, 0, 63);     // in case the pedal value is outside the range seen during calibration

    if (abs(pedalVal1 - lastPedalVal1) > 1) { // If the value does not = the last value the pedal has moved.
      MS3.write(FV_PDL, pedalVal1, 1);
      lastRead1 = millis();
      lastPedalVal1 = pedalVal1;  // remeber the last value of the pedal position so we can see if it changed later
      Serial.print("expression pedal 1 position: ");
      Serial.println(pedalVal1);
    }
  }
 
Status
Not open for further replies.
Back
Top