MIDIUSB Relay / Converter

Ok here is my project. I want to use Two Seeduino Xaio SAMD21 boards to use the onboard USBC ports to send and recieve MIDI commands while using Serial1 to transfer the codes to one another.

This is for a Mutli FX pedal board to control an amp sim plug in that uses USBMIDI for desktop editors. This MUST be as small as possible and the reason for the Xaio boards.

How it should work:

So there will be (Board A) and (Board B) (MFX unit on A and Plug-in unit on B for example)

So an example is I have the board in a preset selection mode to select the next preset up or down. It should send a MIDI command. Board A sees MIDI input and all it has to do is send the data to Board B via Serial1 via the Tx pin.

Board B sees this data via Serial1 and then converts it to what ever MIDI data I assign and then sends out its USBC port to the linked device. It may use a different code for its preset selection mode or I may want it to something different. This will need work both ways as I may need to send inputs from the Plug In back to the FX pedal.

Now the test set up. So have the two boards communicating via Serial1. I can turn the onboard LED on and off on Board B and it sends a return message. I can see this in the serial monitor with the IDE connected to Board A.

Now what I need is to read MIDI from the onboard USBC port from board B and send what ever is recieved over Serial1. It does not need to be complicated this can be a single number not a sting as Ill have to remap the MIDI command back out anyways.

if MIDI data = X
Serial1.print (21)

Is there a way to send the MIDI data to a variable? Then say Ok if this variable equals this: Serial1 print this?

Here is the code set for now there is a master and slave. Board A is the master.

Master




void setup() {
       
  // put your setup code here, to run once:
Serial.begin(115200);
  // Initialize the second serial port on pins 5 and 4 
Serial1.begin(115200);

}

void loop() {
  // put your main code here, to run repeatedly:
String readString;
String Q;

//-------------------------------Check Serial Port---------------------------------------
 
 while (Serial1.available()){
     delay(1);
     if(Serial1.available()>0){
     char c = Serial1.read();
     Serial.print(c);
     if (isControl(c)){
     break;
    }
   
  }
 
 }
 
 while (Serial.available()) {
     delay(1);
    if (Serial.available() >0) {
      char c = Serial.read();  //gets one byte from serial buffer
    if (isControl(c)) {
      //'Serial.println("it's a control character");
      break;
    }
      readString += c; //makes the string readString    
    }
 }   

 Q = readString;
//--------Checking Serial Read----------
      if(Q=="on"){         
        Serial1.print("1");
        Serial.println("Sent:On");               
      }
      if(Q=="off"){         
        Serial1.print("2");  
        Serial.println("Sent:Off");                          
      }



}

Slave

//#include "usbmidi.h"

#include "MIDIUSB_Defs.h"

#include "MIDIUSB.h"


void noteOn(byte channel, byte pitch, byte velocity) {
  midiEventPacket_t noteOn = {0x09, 0x90 | channel, pitch, velocity};
  MidiUSB.sendMIDI(noteOn);
}

void noteOff(byte channel, byte pitch, byte velocity) {
  midiEventPacket_t noteOff = {0x08, 0x80 | channel, pitch, velocity};
  MidiUSB.sendMIDI(noteOff);
}



void setup() {
       
  // put your setup code here, to run once:
  pinMode(13,OUTPUT); 
Serial1.begin(115200);
Serial.begin(115200);

}

// First parameter is the event type (0x0B = control change).
// Second parameter is the event type, combined with the channel.
// Third parameter is the control number number (0-119).
// Fourth parameter is the control value (0-127).

void controlChange(byte channel, byte control, byte value) {
  midiEventPacket_t event = {0x0B, 0xB0 | channel, control, value};
  MidiUSB.sendMIDI(event);
}

void loop() {

  // put your main code here, to run repeatedly:
String readString;
String Q;

//-------------------------------Check Serial Port---------------------------------------
 while (Serial1.available()) {
      delay(1);
    if (Serial1.available() >0) {
      char c = Serial1.read();  //gets one byte from serial buffer
    if (isControl(c)) {

      break;
    }
      readString += c; //makes the string readString    
    }
 }   

 Q = readString;
//--------Checking Serial Read----------
      if(Q=="1"){         
        digitalWrite(13,LOW);
        Serial1.println("I see You!!");                       
      }
      if(Q=="2"){         
        digitalWrite(13,HIGH);             
      }
  midiEventPacket_t rx;
  do {
    rx = MidiUSB.read();
    if (rx.header != 0) {
      Serial1.print("Received: ");
      Serial1.print(rx.header, HEX);
      Serial1.print("-");
      Serial1.print(rx.byte1, HEX);
      Serial1.print("-");
      Serial1.print(rx.byte2, HEX);
      Serial1.print("-");
      Serial1.println(rx.byte3, HEX);
      
     
    }
  } while (rx.header != 0);


}

You're not transmitting any control characters after "1" or "2".

This could be useful:

1 Like

That part is working fine. That is sending the On and Off command over serial to turn the LED on and off.

What I need is to save the incoming MIDIUSB codes store those to a string or varable and when that verable becomes true else where in the code we send it to the other board.

I should note; Ive never used strings in code, never needed too. So I have zero understanding how they work. Im assuming its a series data set sepperated by comma's? If thats true I just need to learn how to format those lines of code.

Then MIDI I litterally just learned this exist less than a week ago. Ive written touch screen interfaces with Python and used I2C integrate that into Arduino. So have that experience, its been a while.

Ill check out those links tonight. Thank you for your input as I have a lot to learn.

I wouldn't use Strings in this case. The incoming MIDIUSB messages are already stored in a variable, namely rx. Why do you think you need to convert it to a string?

What do you mean?

I'd like to suggest a different approach: if board B receives a MIDI message over USB, you do the following:

  1. Check if it's a message you're interested in. If not, don't do anything else.
  2. Make changes to this message if necessary (e.g. map it to a different MIDI controller number).
  3. Send the (possibly modified) MIDI message over Serial1 (as MIDI, not as text).
  4. Board A receives this message and decides what to do with it.

In this case, there's no need for Strings, manual parsing, delays, etc.

1 Like

Just because a code is sent, dont mean I need to use it. So why process it?

Here is what I have. I have a Valeton GP100 MFX pedal and a Tone X One. First level is simply to use the foot swicthes to advance and desend the presets on both units using only the Valeton switches.

Second projects will be a mode for when Tone X One is set up where you have access to all three presets on the pedal in that mode. Its sort of like having scenes. Tone X can swicth only one way. Id like to make a blank (FX block) in the Valeton to switch the other direction and then I can use the other switch for an FX on the Valeton.