DIY Midi Footpedal with Arduino

I'm a keyboardist. I'm trying to resolve a solution. I use a Roland PK5 to trigger drum samples and play drums with my feet in MainStage.

The PK5 is bulky.

I ordered a Keith McMillen 12Step. A lot of reasons that didn't work.

I'm wondering if I can, with an Arduino and some momentary buttons, build my own sort of foot pedal drum machine.

To hook up the Uno via USB to my MacBook, wire up the buttons to the Uno and when I press one of the buttons, it triggers a NOTE ON in MainStage and triggers a kick or snare drum sample...is this even possible?

Does anyone have any helpful links on the basic code and also how to assign each button to a specific Midi note.

thanks in advance.

Yes up this is possible, with a Uno you will need to run a helper application like hairless on your Mac to make the serial look like a MIDI device. Their is no need for this when you an Arduino Leonardo or Micro.

Their are lots and lots of projects on the net that do that sort of thing. I have a few on my site, this one uses reed switches to send notes but they could just as well be foot switches. Chaotic Pendulum

Take a look at my MIDI Controller library. It makes writing code for these kinds of MIDI projects really easy.

Like Grumpy_Mike said, the Arduino Uno isn't the best fit for a USB MIDI instrument, because it doesn't support MIDI over USB natively. You can use all kinds of tricks to get it to work, but it's really cumbersome. Arduino-compatible boards with a native USB connection in the main MCU (Arduino Leonardo, Micro, Due, Zero, Teensy ...) are much easier to use.

Read more about MIDI over USB on Arduino here.

Connect your buttons between an Arduino pin and ground, as explained here, or arrange them in a matrix to save pins on the Arduino, as explained further down that page.

Take a look at the example Ex.02.Button to learn how to use the library with push buttons.

You can add as many buttons as you want, for example:

Digital buttons[] = {
    {2, 0x10, 1, 0x7F}, // Create a new instance of class 'Digital' with a button connected to pin 2, that sends note number 16 on MIDI channel 1, with maximum velocity.
    {3, 0x11, channel, velocity},
    {4, 0x12, channel, velocity},
    {5, 0x13, channel, velocity},
};

Pieter

So I found online someone who wrote the code. Problem is, this was used with an UNO board to hardwire to a MIDI jack.

I don’t need a midi jack and need the Midi messages to travel through USB.

I have successfully imported the code with no errors. I’m not getting any MIDI CC messages with my button and I suspect its because somewhere in the Code its meant to work with a Midi Jack and not straight through USB?

Here is the Controller.h code…

#ifndef Controller_h
#define Controller_h

#include <Arduino.h>

//***********************************************************************
class Mux
{
  public:
    Mux(byte outpin_, byte numPins_, bool analog_);
    byte outpin;
    byte numPins;
    bool analog;
};
//************************************************************************
//Button (Pin Number, Command, Note Number, Channel, Debounce Time)
class Button
{
  public:
    Button(byte pin, byte command, byte value, byte channel, byte debounce);
    Button(Mux mux, byte muxpin, byte command, byte value, byte channel, byte debounce);
    byte getValue();
    void muxUpdate();
    void newValue(byte command, byte value, byte channel);
    byte Bcommand;
    byte Bvalue;
    byte Bchannel;
    byte Btoggle;

  private:
    byte _previous;
    byte _current;
    unsigned long _time;
    int _debounce;
    byte _pin;
    byte _muxpin;
    byte _numMuxPins;
    byte _value;
    byte _command;
    bool _busy;
    byte _status;
    byte _last;
    byte _enablepin;
};
//*************************************************************************
class Pot
{
  public:
    Pot(byte pin, byte command, byte control, byte channel);
    Pot(Mux mux, byte muxpin ,byte command, byte control, byte channel);
    void muxUpdate();
    void newValue(byte command, byte value, byte channel);
    byte getValue();
    byte Pcommand;
    byte Pcontrol;
    byte Pchannel;

  private:
    byte _pin;
    byte _muxpin;
    byte _numMuxPins;
    byte _control;
    int _value;
    int _oldValue;
    bool _changed;
    byte _enablepin;
};
//*************************************************************************
#endif

Here is the CPP code

#include "Controller.h"

//****************************************************************************************
Mux::Mux(byte outpin_, byte numPins_, bool analog_)
{
  outpin = outpin_;
  //enablepin = enablepin_;
  numPins = numPins_;
  analog = analog_;
  if (analog == false) pinMode(outpin, INPUT_PULLUP);
  //pinMode(enablepin, OUTPUT);
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  if (numPins > 8) pinMode(5, OUTPUT);
}
//****************************************************************************************
//Button (Pin Number, Command, Note Number, Channel, Debounce Time)
Button::Button(byte pin, byte command, byte value, byte channel, byte debounce)
{
  _pin = pin;
  pinMode(_pin, INPUT_PULLUP);
  _value = value;
  _command = command;
  _debounce = debounce;
  _time = 0;
  _busy = false;
  _status = 0b00000010;
  _last = 1;
  Bcommand = command;
  Bvalue = value;
  Bchannel = channel;
  Btoggle = 0;
}

Button::Button(Mux mux, byte muxpin, byte command, byte value, byte channel, byte debounce)
{
  _pin = mux.outpin;
  _numMuxPins = mux.numPins;
  _muxpin = muxpin;
  _value = value;
  _command = command;
  _debounce = debounce;
  _time = 0;
  _busy = false;
  _status = 0b00000010;
  _last = 1;
  Bcommand = command;
  Bvalue = value;
  Bchannel = channel;
  Btoggle = 0;
}

void Button::muxUpdate()
{
  byte temp = _muxpin;
  temp = temp << 2;
  if (_numMuxPins > 8) PORTD = PORTD & B11000011;
  else PORTD = PORTD & B11100011;
  PORTD = PORTD | temp;
}

byte Button::getValue()
{
  // If BUSY bit not set - read button
  if (bitRead(_status, 0) == false) { // If busy false
    if (digitalRead(_pin) == _last) return 2; // If same as last state - exit
  }

  // If NEW Bit set - Key just pressed, record time
  if (bitRead(_status, 1) == true) { // If new is true
    bitSet(_status, 0); // Set busy TRUE
    bitClear(_status, 1); // Set New FALSE
    _time = millis();
    return 255;
  }

  // Check if debounce time has passed - If no, exit
  if (millis() - _time < _debounce) return 255;

  // Debounce time has passed. Read pin to see if still set the same
  // If it has changed back - assume false alarm
  if (digitalRead(_pin) == _last) {
    bitClear(_status, 0); // Set busy false
    bitSet(_status, 1); // Set new true
    return 255;
  }

  // If this point is reached, event is valid. return event type
  else {
    bitClear(_status, 0); // Set busy false
    bitSet(_status, 1); // Set new true
    _last = ((~_last) & 0b00000001); // invert _last
    return _last;
  }
}

void Button::newValue(byte command, byte value, byte channel)
{
  Bvalue = value;
  Bcommand = command;
  Bchannel = channel;
}

//********************************************************************
Pot::Pot(byte pin, byte command, byte control, byte channel)
{
  _pin = pin;
  _control = control;
  _value = analogRead(_pin);
  _value = _value >> 3;
  _oldValue = _value << 3;
  _value = _value << 3;
  Pcommand = command;
  Pcontrol = control;
  Pchannel = channel;
}

void Pot::muxUpdate()
{
  byte temp = _muxpin;
  temp = temp << 2;
  if (_numMuxPins > 8) PORTD = PORTD & B11000011;
  else PORTD = PORTD & B11100011;
  //PORTD = PORTD & B11000011;
  PORTD = PORTD | temp;
}

Pot::Pot(Mux mux, byte muxpin, byte command, byte control, byte channel)
{
  _pin = mux.outpin;
  _numMuxPins = mux.numPins;
  _muxpin = muxpin;
  _control = control;
  muxUpdate();
  _value = analogRead(_pin);
  _value = _value >> 3;
  _oldValue = _value << 3;
  _value = _value << 3;
  Pcommand = command;
  Pcontrol = control;
  Pchannel = channel;
}

byte Pot::getValue()
{
  _value = analogRead(_pin);
  int tmp = (_oldValue - _value);
  if (tmp >= 8 || tmp <= -8) {
    _oldValue = _value >> 3;
    _oldValue = _oldValue << 3;
    return _value >> 3;
  }
  return 255;
}

void Pot::newValue(byte command, byte value, byte channel) {
  Pcommand = command;
  Pcontrol = value;
  Pchannel = channel;
}

Can someone point me in the right direction on how to amend this code to work with Midi over USB?

Do I need to post the Arduino code? I think it’s longer than 9000 characters and I was having trouble posting it :frowning:

I don't need a midi jack and need the Midi messages to travel through USB.

Makes no difference to the code.

I suspect its because somewhere in the Code its meant to work with a Midi Jack and not straight through USB?

No. Not in anything you just posted, we need to see your code to say why it is not working for CC messages.

Here is the Arduino code for my Leonardo

#include <MIDI.h>
#include <frequencyToNote.h>
#include <MIDIUSB.h>
#include <pitchToFrequency.h>
#include <pitchToNote.h>
#include "Controller.h"

/*************************************************************
  MIDI CONTROLLER

  by Notes and Volts
  www.notesandvolts.com

  Version 1.2 **Arduino UNO ONLY!**
 *************************************************************/

MIDI_CREATE_DEFAULT_INSTANCE();

//************************************************************
//***SET THE NUMBER OF CONTROLS USED**************************
//************************************************************
//---How many buttons are connected directly to pins?---------
byte NUMBER_BUTTONS = 8;
//---How many potentiometers are connected directly to pins?--
byte NUMBER_POTS = 0;
//---How many buttons are connected to a multiplexer?---------
byte NUMBER_MUX_BUTTONS = 0;
//---How many potentiometers are connected to a multiplexer?--
byte NUMBER_MUX_POTS = 0;
//************************************************************

//***ANY MULTIPLEXERS? (74HC4067)************************************
//MUX address pins must be connected to Arduino UNO pins 2,3,4,5
//A0 = PIN2, A1 = PIN3, A2 = PIN4, A3 = PIN5
//*******************************************************************
//Mux NAME (OUTPUT PIN, , How Many Mux Pins?(8 or 16) , Is It Analog?);


//Mux M1(10, 16, false); //Digital multiplexer on Arduino pin 10
//Mux M2(A5, 8, true); //Analog multiplexer on Arduino analog pin A0
//*******************************************************************


//***DEFINE DIRECTLY CONNECTED POTENTIOMETERS************************
//Pot (Pin Number, Command, CC Control, Channel Number)
//**Command parameter is for future use**

//Pot PO1(A0, 0, 1, 1);
//Pot PO2(A1, 0, 10, 1);
//Pot PO3(A2, 0, 22, 1);
//Pot PO4(A3, 0, 118, 1);
//Pot PO5(A4, 0, 30, 1);
//Pot PO6(A5, 0, 31, 1);
//*******************************************************************
//Add pots used to array below like this->  Pot *POTS[] {&PO1, &PO2, &PO3, &PO4, &PO5, &PO6};
Pot *POTS[] {};
//*******************************************************************


//***DEFINE DIRECTLY CONNECTED BUTTONS*******************************
//Button (Pin Number, Command, Note Number, Channel, Debounce Time)
//** Command parameter 0=NOTE  1=CC  2=Toggle CC **

Button BU1(2, 0, 0, 10, 5 );
Button BU2(3, 0, 61, 10, 5 );
Button BU3(4, 0, 62, 10, 5 );
Button BU4(5, 0, 63, 10, 5 );
Button BU5(6, 0, 64, 10, 5 );
Button BU6(7, 0, 65, 10, 5 );
Button BU7(8, 1, 64, 10, 5 );
Button BU8(9, 2, 64, 10, 5 );
//*******************************************************************
//Add buttons used to array below like this->  Button *BUTTONS[] {&BU1, &BU2, &BU3, &BU4, &BU5, &BU6, &BU7, &BU8};
Button *BUTTONS[] {&BU1, &BU2, &BU3, &BU4, &BU5, &BU6, &BU7, &BU8};
//*******************************************************************


//***DEFINE BUTTONS CONNECTED TO MULTIPLEXER*************************
//Button::Button(Mux mux, byte muxpin, byte command, byte value, byte channel, byte debounce)
//** Command parameter 0=NOTE  1=CC  2=Toggle CC **

//Button MBU1(M1, 0, 0, 70, 1, 5);
//Button MBU2(M1, 1, 1, 71, 1, 5);
//Button MBU3(M1, 2, 2, 72, 1, 5);
//Button MBU4(M1, 3, 0, 73, 1, 5);
//Button MBU5(M1, 4, 0, 74, 1, 5);
//Button MBU6(M1, 5, 0, 75, 1, 5);
//Button MBU7(M1, 6, 0, 76, 1, 5);
//Button MBU8(M1, 7, 0, 77, 1, 5);
//Button MBU9(M1, 8, 0, 78, 1, 5);
//Button MBU10(M1, 9, 0, 79, 1, 5);
//Button MBU11(M1, 10, 0, 80, 1, 5);
//Button MBU12(M1, 11, 0, 81, 1, 5);
//Button MBU13(M1, 12, 0, 82, 1, 5);
//Button MBU14(M1, 13, 0, 83, 1, 5);
//Button MBU15(M1, 14, 0, 84, 1, 5);
//Button MBU16(M1, 15, 0, 85, 1, 5);
//*******************************************************************
////Add multiplexed buttons used to array below like this->  Button *MUXBUTTONS[] {&MBU1, &MBU2, &MBU3, &MBU4, &MBU5, &MBU6.....};
Button *MUXBUTTONS[] {};

//*******************************************************************


//***DEFINE POTENTIOMETERS CONNECTED TO MULTIPLEXER*******************
//Pot::Pot(Mux mux, byte muxpin, byte command, byte control, byte channel)
//**Command parameter is for future use**

//Pot MPO1(M2, 0, 0, 1, 1);
//Pot MPO2(M2, 1, 0, 7, 1);
//Pot MPO3(M2, 2, 0, 50, 1);
//Pot MPO4(M2, 3, 0, 55, 2);
//Pot MPO5(M2, 4, 0, 50, 1);
//Pot MPO6(M2, 5, 0, 55, 2);
//Pot MPO7(M2, 6, 0, 50, 1);
//Pot MPO8(M2, 7, 0, 55, 2);
//Pot MPO9(M2, 8, 0, 50, 1);
//Pot MPO10(M2, 9, 0, 55, 2);
//Pot MPO11(M2, 10, 0, 50, 1);
//Pot MPO12(M2, 11, 0, 55, 2);
//Pot MPO13(M2, 12, 0, 50, 1);
//Pot MPO14(M2, 13, 0, 55, 2);
//Pot MPO15(M2, 14, 0, 50, 1);
//Pot MPO16(M2, 15, 0, 55, 2);
//*******************************************************************
//Add multiplexed pots used to array below like this->  Pot *MUXPOTS[] {&MPO1, &MPO2, &MPO3, &MPO4, &MPO5, &MPO6.....};
Pot *MUXPOTS[] {};
//*******************************************************************


void setup() {
  MIDI.begin(MIDI_CHANNEL_OFF);
}

void loop() {
  if (NUMBER_BUTTONS != 0) updateButtons();
  if (NUMBER_POTS != 0) updatePots();
  if (NUMBER_MUX_BUTTONS != 0) updateMuxButtons();
  if (NUMBER_MUX_POTS != 0) updateMuxPots();
}


//*****************************************************************
void updateButtons() {

  // Cycle through Button array
  for (int i = 0; i < NUMBER_BUTTONS; i = i + 1) {
    byte message = BUTTONS[i]->getValue();

    //  Button is pressed
    if (message == 0) {
      switch (BUTTONS[i]->Bcommand) {
        case 0: //Note
          MIDI.sendNoteOn(BUTTONS[i]->Bvalue, 127, BUTTONS[i]->Bchannel);
          break;
        case 1: //CC
          MIDI.sendControlChange(BUTTONS[i]->Bvalue, 127, BUTTONS[i]->Bchannel);
          break;
        case 2: //Toggle
          if (BUTTONS[i]->Btoggle == 0) {
            MIDI.sendControlChange(BUTTONS[i]->Bvalue, 127, BUTTONS[i]->Bchannel);
            BUTTONS[i]->Btoggle = 1;
          }
          else if (BUTTONS[i]->Btoggle == 1) {
            MIDI.sendControlChange(BUTTONS[i]->Bvalue, 0, BUTTONS[i]->Bchannel);
            BUTTONS[i]->Btoggle = 0;
          }
          break;
      }
    }

    //  Button is not pressed
    if (message == 1) {
      switch (BUTTONS[i]->Bcommand) {
        case 0:
          MIDI.sendNoteOff(BUTTONS[i]->Bvalue, 0, BUTTONS[i]->Bchannel);
          break;
        case 1:
          MIDI.sendControlChange(BUTTONS[i]->Bvalue, 0, BUTTONS[i]->Bchannel);
          break;
      }
    }
  }
}
//*******************************************************************
void updateMuxButtons() {

  // Cycle through Mux Button array
  for (int i = 0; i < NUMBER_MUX_BUTTONS; i = i + 1) {

    MUXBUTTONS[i]->muxUpdate();
    byte message = MUXBUTTONS[i]->getValue();

    //  Button is pressed
    if (message == 0) {
      switch (MUXBUTTONS[i]->Bcommand) {
        case 0: //Note
          MIDI.sendNoteOn(MUXBUTTONS[i]->Bvalue, 127, MUXBUTTONS[i]->Bchannel);
          break;
        case 1: //CC
          MIDI.sendControlChange(MUXBUTTONS[i]->Bvalue, 127, MUXBUTTONS[i]->Bchannel);
          break;
        case 2: //Toggle
          if (MUXBUTTONS[i]->Btoggle == 0) {
            MIDI.sendControlChange(MUXBUTTONS[i]->Bvalue, 127, MUXBUTTONS[i]->Bchannel);
            MUXBUTTONS[i]->Btoggle = 1;
          }
          else if (MUXBUTTONS[i]->Btoggle == 1) {
            MIDI.sendControlChange(MUXBUTTONS[i]->Bvalue, 0, MUXBUTTONS[i]->Bchannel);
            MUXBUTTONS[i]->Btoggle = 0;
          }
          break;
      }
    }
    //  Button is not pressed
    if (message == 1) {
      switch (MUXBUTTONS[i]->Bcommand) {
        case 0:
          MIDI.sendNoteOff(MUXBUTTONS[i]->Bvalue, 0, MUXBUTTONS[i]->Bchannel);
          break;
        case 1:
          MIDI.sendControlChange(MUXBUTTONS[i]->Bvalue, 0, MUXBUTTONS[i]->Bchannel);
          break;
      }
    }
  }
}
//***********************************************************************
void updatePots() {
  for (int i = 0; i < NUMBER_POTS; i = i + 1) {
    byte potmessage = POTS[i]->getValue();
    if (potmessage != 255) MIDI.sendControlChange(POTS[i]->Pcontrol, potmessage, POTS[i]->Pchannel);
  }
}
//***********************************************************************
void updateMuxPots() {
  for (int i = 0; i < NUMBER_MUX_POTS; i = i + 1) {
    MUXPOTS[i]->muxUpdate();
    byte potmessage = MUXPOTS[i]->getValue();
    if (potmessage != 255) MIDI.sendControlChange(MUXPOTS[i]->Pcontrol, potmessage, MUXPOTS[i]->Pchannel);
  }
}

So I went to the website where I found this and just read this ...

Before You Start
This tutorial will ONLY work with the Arduino UNO. (Please don't ask if it will work on other Arduino models.) I am using some direct port manipulation in the code that is currently specific to the UNO. I'll let you know if this changes in the future.

Obviously I didn't do my due diligence before heading down this path.

I have an Arduino Leonardo because I need Midi over USB.

Oh well. Sidebar ... If anyone wants to be hired to help write this code ... I'd be glad to work together to help me get this up and running.

::angry::

Have you actually read reply #2 and the links posted there?
MIDI over USB on a Leonardo is not something new. It’s all over Google.

What does that have anything to do with my latest entry?

I know Leonardo does USB over MIDI.

Well, the links I posted there explain how to do USB MIDI on Arduino boards, including the Leonardo, and they explain how to use it to create MIDI controller, which is what you asked for.

I appreciate it.

My original question was for help with the sketch code, to which I don't know how to write.

I have successfully turned the Leonardo into a USB interface ... I just don't know how to write code to assign buttons to Midi CC information.

I found a code and have successfully implemented it.

Problem is … its triggering a sample sometime on the Note Off message … as well as sometime triggering a doubling of the sample. Almost as if it’s hitting the drum sample on a quick repeat.

Could this be some sort of Bounce problem?

Can someone help me configure or edit this code so when I press down it definitely only triggers ONE note. And when I let up the button, it simply sends a NOTE OFF and a sample doesnt trigger?

/*
   Based on example code linked below by Arturo Guadalupi, 4/10/15
   
   Sparkfun Pro Micro board was used.
   
   http://www.arduino.cc/en/Tutorial/MidiDevice
*/

#include "MIDIUSB.h"
#include "PitchToNote.h"
#define NUM_BUTTONS  4

const uint16_t button1 = 2;
const uint16_t button2 = 3;
const uint16_t button3 = 4;
const uint16_t button4 = 5;
//const uint16_t button5 = 6;
//const uint16_t button6 = 7;
//const uint16_t button7 = 8;
//const uint16_t button8 = 9;


const uint16_t buttons[NUM_BUTTONS] = {button1, button2, button3, button4,};
const byte notePitches[NUM_BUTTONS] = {pitchC2, pitchD2b, pitchD2, pitchE2b};

uint16_t notesTime[NUM_BUTTONS];
uint16_t pressedButtons = 0x00;
uint16_t previousButtons = 0x00;
uint16_t intensity;

void setup() {
  for (int i = 0; i < NUM_BUTTONS; i++)
    pinMode(buttons[i], INPUT_PULLUP);
}


void loop() {
  readButtons();
  playNotes();
}

// 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 readButtons()
{
  for (int i = 0; i < NUM_BUTTONS; i++)
  {
    if (digitalRead(buttons[i]) == LOW)
    {
      bitWrite(pressedButtons, i, 1);
      delay(2);
    }
    else
      bitWrite(pressedButtons, i, 0);
  }
}

void playNotes()
{
  for (int i = 0; i < NUM_BUTTONS; i++)
  {
    if (bitRead(pressedButtons, i) != bitRead(previousButtons, i))
    {
      if (bitRead(pressedButtons, i))
      {
        bitWrite(previousButtons, i , 1);
        noteOn(0, notePitches[i], 100);
        MidiUSB.flush();
      }
      else
      {
        bitWrite(previousButtons, i , 0);
        noteOff(0, notePitches[i], 0);
        MidiUSB.flush();
      }
    }
  }
}

// First parameter is the event type (0x09 = note on, 0x08 = note off).
// Second parameter is note-on/note-off, combined with the channel.
// Channel can be anything between 0-15. Typically reported to the user as 1-16.
// Third parameter is the note number (48 = middle C).
// Fourth parameter is the velocity (64 = normal, 127 = fastest).

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);
}

dallaskruse:
I found a code and have successfully implemented it.

Problem is ... its triggering a sample sometime on the Note Off message ... as well as sometime triggering a doubling of the sample. Almost as if it's hitting the drum sample on a quick repeat.

Could this be some sort of Bounce problem?

Most likely. Software debounce is pretty easy to do, take look at how it's implemented here.

Pieter

I will have to try this. I guess its just a matter of copying the code and pasting into my code?

I'm a noob.

dallaskruse:
I will have to try this. I guess its just a matter of copying the code and pasting into my code?

I'm a noob.

No, you also have to declare the right variables, and keep the button states in a some kind of variable, just like with the previous states.

Perfectly doable if you understand how it works, so you may want to figure that out first. Try to understand every single line of the sketch you copied. Not all at once of course, but go through it, and look up things you don't know. If something's unclear, and Google can't answer your questions, you can ask it here on the forum.
You'll learn a lot by isolating small sections you don't understand and write a small test sketch and adapting it to see how it works.

If you want an easy solution, you can just use the example shown in reply #2.

Pieter

Hello,

I know this is an old post but I followed your suggestion and used Ex.02.Button example but while I am trying to map this and any other pushbutton it is sending Program Change 0.

Can you please review the code once?

Again please note I am trying to make an 8 button footswitch to control Overloud thU with Arduino Nano (since this is what I have).

#include <MIDI_Controller.h> // Include the library

const uint8_t velocity = 0b1111111; // Maximum velocity (0b1111111 = 0x7F = 127)
const uint8_t C4 = 60;              // Note number 60 is defined as middle C in the MIDI specification

Digital buttons[] = {
    {2, 0x10, 1, velocity}, 
    {3, 0x11, 1, velocity},
    {4, 0x12, 1, velocity},
    {5, 0x13, 1, velocity},
};

void setup() {
  Serial.begin(115200);
  }

void loop() {
  MIDI_Controller.refresh();
}

This sounds like a baud rate problem. The MIDI controller library will default to the MIDI baud rate of 31250 if you don’t specify it explicitly (it’ll override the baud rate you set in the setup). Are you using Hairless MIDI?

As mentioned on the GitHub page, I no longer offer support for the MIDI controller library. It has been replaced and obsoleted by the Control Surface library.
The equivalent sketch for Control Surface would be:

#include <Control_Surface.h> // Include the Control Surface library
 
// Instantiate a MIDI over USB interface.
USBMIDI_Interface midi;
// Alternatively:
//  - HairlessMIDI_Interface midi;  // For use with Hairless MIDI<->Serial bridge (over USB, uses 115200 baud)
//  - USBSerialMIDI_Interface midi = 115200; // Uses the USB serial port (usually "Serial")
//  - HardwareSerialMIDI_Interface midi = {Serial, 115200}; // Any hardware UART (also Serial1, Serial2 ...)
 
const auto channel = CHANNEL_1;
const uint8_t velocity = 0x7F;

// Instantiate an array of NoteButton objects
NoteButton buttons[] = {
  {2, {0x10, channel}, velocity}, // { pin, {address}, velocity }
  {3, {0x11, channel}, velocity},
  {4, {0x12, channel}, velocity},
  {5, {0x13, channel}, velocity},
};
 
void setup() {
  Control_Surface.begin(); // Initialize Control Surface
}
 
void loop() {
  Control_Surface.loop(); // Update the Control Surface
}

The Arduino Nano doesn’t support MIDI over USB, so you’ll have to select one of the alternative interfaces. Make sure the baud rate in your code matches the baud rate of whatever the Arduino is connected to. If you omit the baud rate parameter on the HardwareSerialMIDI_Interface, it defaults to the MIDI baud rate of 31250.

Hello, Thanks for replying…

Yes, I am using Hairless Midi.

After installing the library and tried running the code got this error. Attachment is given.

I know I am not the brightest when it comes to coding and all, Thanks a lot for your reply.

prat0302:
Hello, Thanks for replying...

Yes, I am using Hairless Midi.

After installing the library and tried running the code got this error. Attachment is given.

I know I am not the brightest when it comes to coding and all, Thanks a lot for your reply.

Please don't post pictures of code or error messages. Post the actual text (using [code] tags).

What version of the Arduino IDE and Arduino AVR Core are you using? I tried compiling it in version 1.8.13 with AVR core 1.8.3 (see Tools > Board > Boards Manager) and it works just fine.

Hello PieterP for all the help.

I finally got it to work once I updated the arduino version. :slight_smile:

I just added the number of buttons I needed and wallah!

This is the final code… Thanks again!

#include <Control_Surface.h> // Include the Control Surface library
 
// Instantiate a MIDI over USB interface.
//USBMIDI_Interface midi;
// Alternatively:
//HairlessMIDI_Interface midi;  // For use with Hairless MIDI<->Serial bridge (over USB, uses 115200 baud)
//USBSerialMIDI_Interface midi = 115200; // Uses the USB serial port (usually "Serial")
HardwareSerialMIDI_Interface midi = {Serial, 115200}; // Any hardware UART (also Serial1, Serial2 ...)
 
const auto channel = CHANNEL_1;
const uint8_t velocity = 0x7F;

// Instantiate an array of NoteButton objects
NoteButton buttons[] = {
  {2, {0x10, channel}, velocity}, // { pin, {address}, velocity }
  {3, {0x11, channel}, velocity},
  {4, {0x12, channel}, velocity},
  {5, {0x13, channel}, velocity},
  {6, {0x14, channel}, velocity},
  {7, {0x15, channel}, velocity},
  {8, {0x16, channel}, velocity},
  {9, {0x17, channel}, velocity},
  {10, {0x18, channel}, velocity},
};
 
void setup() {  
  Control_Surface.begin(); // Initialize Control Surface
}
 
void loop() {
  Control_Surface.loop(); // Update the Control Surface
}