Standalone MIDI Controller

Hello all. I'm a guitar player and some time ago, I built myself a MIDI controller with a Leonardo which has 8 toggle switches and 1 expression pedal which sends CC commands to the vst's I use to turn on/off the effects, etc and works thru USB.

Recently, I've gotten a Boss GT-10 guitar processor, which has MIDI IN&OUT ports, and I want to utilize this functionality to expand my control over the unit during live play. I plan to connect a MIDI Out to this switchboard and send the MIDI signals via the TX pin to this processor.

However, when I power the board up without a PC, it just turns on, and I see no signal output. I think I need to tinker the code I use, but I don't know how to proceed actually. It would be great to be able to use this switchboard both via USB and MIDI.

The code I currently use is as below, I just found it on the web and increased the switch quantity & set the pot. range to my need, that's all. I think it belongs to PieterP and as I checked, what I intend to do is somehow achievable by Dual-MIDI-Interface but some assistance over the below code would be great. It'd be also good if its possible to add some LED on-off indicators, but the switches I use have only 2 lugs, so I don't know if it'd be possible for LEDs to sync the real on-off positions of the switches.

#include <Control_Surface.h> // Include the Control Surface library

// Instantiate a MIDI over USB interface

USBMIDI_Interface midi;

// Instantiate an array of latched push buttons that send MIDI CC messages

// when pressed.

CCButtonLatched buttons[] {

{ 2, 0x10 },

// โ”‚ โ””โ”€โ”€โ”€โ”€ MIDI CC controller number

// โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ Button pin number

{ 3, 0x11 },

{ 4, 0x12 },

{ 5, 0x13 },

{ 6, 0x14 },

{ 7, 0x15 },

{ 8, 0x16 },

{ 9, 0x19 },

};

// Setup for an Analog pot for an EXP pedal on cc #11

CCPotentiometer potentiometer = {

A0, {MIDI_CC::Expression_Controller, CHANNEL_1}

};

// The filtered value read when potentiometer is at the 0% position

constexpr analog_t minimumValue = 10550;

// The filtered value read when potentiometer is at the 100% position

constexpr analog_t maximumValue = 14550;

// A mapping function to eliminate the dead zones of the potentiometer:

// Some potentiometers don't output a perfect zero signal when you move them to

// the zero position, they will still output a value of 1 or 2, and the same

// goes for the maximum position.

analog_t mappingFunction(analog_t raw) {

// make sure that the analog value is between the minimum and maximum

raw = constrain(raw, minimumValue, maximumValue);

// map the value from [minimumValue, maximumValue] to [0, 16383]

return map(raw, minimumValue, maximumValue, 0, 16383);

// Note: 16383 = 2ยนโด - 1 (the maximum value that can be represented by

// a 14-bit unsigned number

}

void setup() {

potentiometer.map(mappingFunction);

Control_Surface.begin(); // Initialize the Control Surface

Serial.begin(31250);

}

void loop() {

Control_Surface.loop(); // Update the Control Surface

//Serial.println(potentiometer.getRawValue());

}

Your problem here is that your MIDI controller you built with the Leonardo is a MIDI client device, And so is your Boss effects peddle.

They are both designed to be plugged into a MIDI host device like your computer.

Nothing will happen when you connect two client devices together.

So the simplest thing you can do is to is to plug the Boss into the computer and also plug your Leonardo into an other USB port on your computer and have your DAW relay certain codes from your Leonardo to your Boss.

1 Like

Hi Mike,

According to its manual, GT-10 accepts CC signals between #1 to #31 & #64 to #95 from external sources and can be assigned to any function of GT-10. So theoretically, if I manage to work Leo as a standalone, I can send these CC signals thru MIDI Out -which I'll connect to the TX pin- to GT-10's MIDI In channel.

That is the whole point. The Leonardo can't be a stand-alone because it is only, and can only be a client device. To work stand-alone you have to have a host device.

I think Arduinos like the Due and the Zero or the Teensy 3.5 and higher can be made to work as a host device. But then you won't be able to connect it to your computer which is another host device.

Ok so i think you mean by host the side that accepts midi signals?

So Whats the point of pieterp's library that allows the utilization of both usb and hardware serials?

Also what makes a device a client or a host? What capability(ies) actually?

No.
I think you have a profound misunderstanding about USB connections and how they work.

USB devices come in two types, client and host. A computer always has a host type of USB. Anything you plug into a computer has to be a client device. You can't connect two computers together through USB. The types of plugs and sockets used in USB devices will prevent you from connecting two computers together.

If you could get an adaptor to connect two computers together then nothing much would happen because the software on a host device is fundamental different from the software on a client device.

The point is that the USB side is a client device and the serial device is just an input / output for a normal 5 pin DIN connector, for audio devices that have them. MIDI predates USB by about 20 years, and is almost a separate protocol.

I think you need to research the USB protocol. I have bought a whole book dedicated to the protocol and describes in great detail. Much more that I can explain in a post reply.

But you can find most of this information on line if you look for it.

Ok so, simply put, is there any way to use an Arduino board over MIDI port as a standalone device, without connecting the USB and just powering it externally? Assuming that its connecting to PC via MIDI, not USB..

Yes, there are two ways.

  1. use a host shield on an AVR processor, like a Uno or MEGA.
  2. use an Arduino with a processor capable of acting as a host device, like a Teensy, and I think a Due or a zero would be able to do that, but I would look up some examples before I spent any money.

I wonder how this guy achieves the thing I want to do mostly. Just for trial purposes, I've uploaded as it is and gave it a go and saw that it really works externally, yet not the way I want to be (different pins, PC instead of CC etc..) If this code somehow be cleaned and revised according to my needs, I'll be good to go.

https://www.youtube.com/watch?v=z4jOhp0Z0G4&t=154s

And his code is as below;

/*
  Use at your own risk - wasn't too sure what I was doing :)

  Build vid: https://www.youtube.com/watch?v=z4jOhp0Z0G4

  4 button, 3 bank Arduino Uno midi controller - 5 pin DIN output.

  Selects programmes 1 - 12 with PC command

  Toggles effect on/off using CC#11 (used for Line 6 M5 pedal) - change CC# in line 35 for anything else

  Effect on/off is either latching or momentary, depending on pin on line 19 reading high or low. Input pullup used with a single pole switch to ground it.

  Still a few bugs - works best on its own power supply - when daisy chained with other pedals I have issues with the momentary mode being grouned when the footswitches were used. 

*/

int buttonPinsAll[] = {2, A2, 4, 5, 6, A1}; // all button inputs to set global pullup
int ledPins[] = {7, 8, 9, 10, 11, 12, A0 }; // output pins for bank LEDs
int fxLeds[] = {A3, A4, A5,13}; // leds for effect on
int effectOn[] = {0, 0, 0, 0}; // increments for each button pressed; even number is effect on, odd number is effect off / writes button state for momentary mode
int effectPins[] = {2, A2, 4, 5}; // effect on off button pins
int bankButton = 6; // bank change button pin 
int momentary = A1; //

int currentBank = 1; // currently selected bank, starts on 1
int prevBank = 1;  // prev selected bank, starts on 1
int bankOffset = 0; // gives buttons 1 - 4 the values 1 - 12 depending on bank selected
int bankButtonState = 1;         // current state of the bank button
int lastBankButtonState = 1;     // previous state of the bank button

int buttonState = 1;         // current state of the effect button
int lastButtonState = 1;     // previous state of the effect button
int lastButtonNum = 9; // to differentiate buttons; same button: on to off, diff button, on to on
int buttonNum[] = {1, 2, 3, 4}; // which button was pressed
int buttonDelay = 350; // time in ms delay after button press. Only way debouncing is being handled.

// midi messages:
byte progChange = 0xC0; // PC midi command
byte contChange = 0xB0; // CC Midi command
byte contNum = 11; // CC# for on/off
byte contOn = 70; // CC# value for FX on
byte contOff = 0; // CC# value for FX off
int presets[] {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC}; // hex values for presets 1 - 12

void fxOn() {
  Serial.write(contChange);
  Serial.write(contNum);
  Serial.write(contOn);
}

void fxLedsOff() {
  digitalWrite(fxLeds[0],LOW);
  digitalWrite(fxLeds[1],LOW);
  digitalWrite(fxLeds[2],LOW);
  digitalWrite(fxLeds[3],LOW);
}

void fxOff() {
  Serial.write(contChange);
  Serial.write(contNum);
  Serial.write(contOff);
}

void clearDisplay() {
  digitalWrite(ledPins[0], LOW); // Turns Off all LEDs
  digitalWrite(ledPins[1], LOW);
  digitalWrite(ledPins[2], LOW);
  digitalWrite(ledPins[3], LOW);
  digitalWrite(ledPins[4], LOW);
  digitalWrite(ledPins[5], LOW);
}

void display1() {
  digitalWrite(ledPins[0], HIGH); // Display no 1
  digitalWrite(ledPins[5], HIGH);

  return;
}

void display2() {
  digitalWrite(ledPins[0], HIGH); // Display no 2
  digitalWrite(ledPins[1], HIGH);
  digitalWrite(ledPins[2], HIGH);
  digitalWrite(ledPins[3], HIGH);
  digitalWrite(ledPins[4], HIGH);
  return;
}

void display3() {
  digitalWrite(ledPins[0], HIGH); // Display no 3
  digitalWrite(ledPins[1], HIGH);
  digitalWrite(ledPins[2], HIGH);
  digitalWrite(ledPins[4], HIGH);
  digitalWrite(ledPins[5], HIGH);
  return;
}

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

  for (int i = 0; i < 7; i++) pinMode(ledPins[i], OUTPUT);
  for (int i = 0; i < 4; i++) pinMode(fxLeds[i], OUTPUT);
  for (int i = 0; i < 5; i++) pinMode(buttonPinsAll[i], INPUT_PULLUP); // input pullup used without external resistors
  Serial.write(progChange);
  Serial.write(0x00);
  fxLedsOff();
  fxOff();
  display1(); // 
  
}

void loop() {

  int momState = digitalRead(momentary);
  int bankButtonState = digitalRead(bankButton);
  if (bankButtonState == lastBankButtonState && bankButtonState == 1) { // if no bank change then:

    for (int i = 0; i <4 ; i++) { // read all the button pin states:
      buttonState = digitalRead(effectPins[i]);

      switch (momState) { 

        case 1: // momentary mode
        digitalWrite(ledPins[6], LOW);

          if (buttonState != effectOn[i] && buttonState == 0) { //pressed
            Serial.write(progChange);
            Serial.write(presets[bankOffset + i]);
            fxOn();
            digitalWrite(fxLeds[i],HIGH);
            delay(10);
          }

          else if (buttonState != effectOn[i] && buttonState == 1) { //released
            fxOff();
            fxLedsOff();
            delay(10);
          }

          else {
          }

          effectOn[i] = buttonState;
          break;

        case 0: // on/off mode
        digitalWrite(ledPins[6], HIGH);

          if (buttonState != lastButtonState && buttonState != 1) { // if button pressed:
            lastButtonState = buttonState;
            effectOn[i]++;

            if (lastButtonNum != buttonNum[i]) { // turn effect on
              fxLedsOff();
              Serial.write(progChange);
              Serial.write(presets[bankOffset + i]);
              fxOn();
              digitalWrite(fxLeds[i],HIGH);
              effectOn[i] = 1; 
              delay(buttonDelay);

            }
            else if (lastButtonNum == buttonNum[i] && effectOn[i] % 2 == 0) { // turn effect off if same button pressed
              Serial.write(progChange);
              Serial.write(presets[bankOffset + i]);
              fxLedsOff();
              fxOff();
              delay(buttonDelay);
            }
            else if (lastButtonNum == buttonNum[i] && effectOn[i] % 2 != 0) { // turn effect back on if turned off
              Serial.write(progChange);
              Serial.write(presets[bankOffset + i]);
              fxLedsOff();
              fxOn();
              digitalWrite(fxLeds[i],HIGH);
              delay(buttonDelay);
            }
            lastButtonNum = buttonNum[i];

          }
          lastButtonState = buttonState;

          break;
      }
    }
  }

  else if (bankButtonState != lastBankButtonState && bankButtonState == 0 && currentBank == 3) { // if bank is changed and current bank is 3, change to 1
    currentBank = 1;
    bankOffset = 0;
    clearDisplay();
    display1();
    lastButtonNum = int (buttonNum + 4);
    delay(buttonDelay);

  }
  else if (bankButtonState != lastBankButtonState && bankButtonState == 0 && currentBank == 1) { // if bank 1, change to 2
    currentBank++;
    bankOffset = 4;
    clearDisplay();
    display2();
    lastButtonNum = int (buttonNum + 1);
    delay(buttonDelay);

  }
  else if (bankButtonState != lastBankButtonState && bankButtonState == 0 && currentBank == 2) { // if bank 2, change to 3
    currentBank++;
    bankOffset = 8;
    clearDisplay();
    display3();
    lastButtonNum = int (buttonNum + 1);
    delay(buttonDelay);
  }
  lastBankButtonState = bankButtonState;
}




Because he is just required a straight forward serial 5 pin DIN output.
No messing with USB.
It is not the best quality code, the repetition of lines over and over marks him out as a beginner.

Fair enough, i can sacrifice the usb functionality then.

So its doable, right? As it seems so.

Can you assist me for applying this code for a scenario that includes 8 mom. Switches and 1 exp. Pedal, all of which shall send Cc numbers?

diagram.pdf (2.8 MB)

I'm attaching a diagram I made for what I want to do.

Not exactly a schematic it is more a collection of photographs and random wires. The bit that looks wrong is all the stuff going into a MIDI socket, including a +5V but showing none of the wiring or resistors around that socket. Then three black wires going into your Boss system where you can't distinguish them.

This is my schematic of a input and output shield for the Arduino Uno.
http://www.thebox.myzen.co.uk/Hardware/MIDI_Shield.html
Note there is a small error in the schematic where the connectors are labelled as looking from the back of the socket, it is indeed from the front of the socket.

You need a switch to isolate the MIDI signals from the inputs for when you are uploading the code, otherwise the MIDI device can "go mad" or stop code upload from working correctly.

The code to do what you want is almost trivial.

Sorry for not being a Picasso of the 21th century on the quick show-up I prepared and disappointing you for missing resistors or cable colors etc. What I intend to demonstrate was my setup.

Can we just get to the point instead of discussing the meaninglessness of 3 cables merely showing the connection of the Boss & board ? It's a placeholder, all right? It was a quick sketch and I thought you guys were clever enough to get what I'm trying to say.

Basically, I just need some sort of a cheap-ass clone of Behringer's FCB1010, which is a stand-alone, DC-powered midi controller, doesn't need any PC connection (apart from programming maybe), and can be used to send MIDI signals to any device that's connected to.

I believe, this scenario is somehow possible, because theoretically it should be.

Yes it is possible.

We get what you are trying to say, so what do you want me to say?
Go ahead an make that?

Thing is you can't.

Well given the sort of abstract work that Picasso produced then I would say you were pretty close. :slight_smile:

So can you use the schematic of my shield? You will only need the output side.

I'm checking now

If you want your current code to send MIDI over serial for 5-pin DIN MIDI, you can just replace the line USBMIDI_Interface midi; by HardwareSerialMIDI_Interface midi {Serial1};.

Serial refers to the virtual USB Serial port on a Leonardo. For 5-pin DIN MIDI, you should use Serial1, the hardware UART.

Oh Hi Pieter, its been good to hear from you.

As you can see from the initial message, I'm using your library to create what I intend to do. Can you somehow guide for this ?

Below code does not give any response on TX (no led blink). Is it correct?

I tried the piped version as well (dual interface), then it only works on PC, not externally.

#include <Control_Surface.h> // Include the Control Surface library

HardwareSerialMIDI_Interface midi {Serial1};

CCButtonLatched buttons[] {

{ 2, 0x10 },
// โ”‚ โ””โ”€โ”€โ”€โ”€ MIDI CC controller number

// โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ Button pin number
{ 3, 0x11 },
{ 4, 0x12 },
{ 5, 0x13 },
{ 6, 0x14 },
{ 7, 0x15 },
{ 8, 0x16 },
{ 9, 0x19 },
};

// Setup for an Analog pot for an EXP pedal on cc #11

CCPotentiometer potentiometer = {
A0, {MIDI_CC::Expression_Controller, CHANNEL_1}
};

constexpr analog_t minimumValue = 10550;
constexpr analog_t maximumValue = 14550;

analog_t mappingFunction(analog_t raw) {

raw = constrain(raw, minimumValue, maximumValue);
return map(raw, minimumValue, maximumValue, 0, 16383);

}

void setup() {
potentiometer.map(mappingFunction);
Control_Surface.begin(); // Initialize the Control Surface
Serial1.begin(31250);
}

void loop() {
Control_Surface.loop(); // Update the Control Surface
}

I started to think that the board itself doesn't support hardware output;

As I see from here, only Uno & Mega has serial output for MIDI. Leonardo is more based on a USB-based scenario, is that right?

No.

The Leonardo has both a serial output, and is capable of a USB I/O as well. So you can send conventional 5 pin DIN serial MIDI as well.