Need Help with MIDI Control Change Messages with Buttons

Hi,

I am very new to Arduino and programming.

I am trying to build a simple MIDI Foot controller to send Control Change Messages to my guitar
effect pedals.

I have be working with the following sketch which allows me to:

Send a CC# or CC Toggle per button, But I can’t send a value with the CC#.

I need to send multiple CC messages (with a value) on up to Three (3) MIDI Channels per button.

E.G.
BUTTON 1 -( CC# 2, Value 0, Chanel 5) & (CC# 31, Value 127, Chanel 3 ) & (CC# 4, Value 3, Chanel 5)

Also I have noticed when I use the CC command, the button is only momentary, I need it to Latch.

Like I said before, I’m a complete beginner, I have spent weeks reading articles and watching tutorials.

I have well and truly hit a brick wall, So any help will be greatly appreciated!

HERE IS THE CODE I'VE BEEN WORKING WITH.

#include <MIDI.h>
#include "Controller.h"

MIDI_CREATE_DEFAULT_INSTANCE();

           //---How many buttons are connected directly to pins?---------

byte NUMBER_BUTTONS = 2;

          //***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, 1, 2, 3, 5 );
Button BU2(3, 1, 31, 3, 3 );
//Add buttons used to array below like this-> Button *BUTTONS[] {&BU1, &BU2, &BU3, &BU4, &BU5, &BU6, &BU7, &BU8};
Button *BUTTONS[] {&BU1, &BU2};

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

}
void loop() {
if (NUMBER_BUTTONS != 0) updateButtons();
}

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

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

}
}

Try something like:

    case 1: //CC
      switch (BUTTONS[i]->Bvalue)
      {
      // BUTTON 1 : 
      //  CC# 2,  Value 0, Chanel 5
      //  CC# 31, Value 127, Chanel 3
      //  CC# 4,  Value 3, Chanel 5
      case 1:
        MIDI.sendControlChange(2, 0, 5);
        MIDI.sendControlChange(31, 127, 3);
        MIDI.sendControlChange(4, 3, 5);
        break;

        // BUTTON 2
        case 2:
        break;
     }
1 Like

Does it need to cycle between the different channels/values? I.e. the first press sends (CC#2, value 0, ch 5), the second press sends (CC#31, val 127, ch 3), the third press sends (CC#4, val 3, ch 5), the fourth press sends (CC#2, value 0, ch 5) again, etc.

In that case, you could try something like this:

#include <Control_Surface.h> // https://github.com/tttapa/Control-Surface
#include <AH/STL/utility>    // std::pair
#include <AH/STL/array>      // std::array

template <uint8_t NumVals>
class MyCCButton : public MIDIOutputElement {
 public:
  using addr_val_t = std::pair<MIDIAddress, uint8_t>;
  MyCCButton(pin_t pin, const std::array<addr_val_t, NumVals> &addr_vals)
    : button(pin), addr_vals(addr_vals) {}
 
  void begin() final override { button.begin(); }
  void update() final override {
    if (button.update() == AH::Button::Falling) {
      Control_Surface.sendControlChange(addr_vals[index].first,
                                        addr_vals[index].second);
      if (++index == NumVals)
        index = 0;
    }
  }

 private:
  AH::Button button;
  std::array<addr_val_t, NumVals> addr_vals;
  uint8_t index = 0;
};
USBMIDI_Interface midi;
 
MyCCButton<3> button {
  5, // Push button on pin 5
  {{ // List of address-value pairs
    {{0x02, CHANNEL_5}, 0x00},
    {{0x1F, CHANNEL_3}, 0x7F},
    {{0x04, CHANNEL_5}, 0x03},
  }},
};
 
void setup() { Control_Surface.begin(); }
void loop() { Control_Surface.loop(); }
1 Like

Hi Pieter,

Thank you for your help.

I don't need to cycle though the values.

I need all the info ( CC# 2, Value 0, Chanel 5) & (CC# 31, Value 127, Chanel 3 ) & (CC# 4, Value 3, Chanel 5) to be sent on the same push

I will then have other buttons (with the same setup) with different MIDI commands, that when sent will cancel out the previous button.

Also, I forgot to mention in my original post.

I am not using USB MIDI, I will be outputting from a standard MIDI OUT.

In what sense should it toggle then? What should happen when the button is released? Or when it is untoggled?

In that case you can use HardwareSerialMIDI_Interface midi {Serial};

1 Like

I don't need it to toggle or anything to happen when the button is released, as the commands sent from the button pressed should be the state that the controller stays in, until another button is pressed. E.G. A button press cancels out the the commands of the previous button.

I need the commands to stay on after a button is pressed (Like a toggle).
When I send a normal CC# it just stays on momentarily.
How can I get it to stay switched on?

Thanks for the HardwareSerialMIDI_Interface midi {Serial};

There's no such thing as commands staying on for MIDI CC. You send a CC message, and that sets the controller to a certain value. You don't need to do anything to keep it on.

You'll have to check the documentation of the hardware you're using, this is not a general MIDI thing AFAIK.

1 Like

Yes probably something silly I'm doing.

Ive just found the Control Surface library and I've started working my way through it. It looks amazing and I think it will allow me to do what I need, once I can get my head around it.

Thanks for all your help!!

Thanks John!

Hi Guys,

I'm really struggling with this.

I've spent a couple of afternoons reading through the Control surface "Getting Started Guide"

I really need some help with the basic structure.

I keep getting this error message
"sketch_CC_Forum_1:7:13: error: expected ')' before 'int'
exit status 1
expected unqualified-id before 'int'"

Here is my embarrassing example of code.
<
#include <Control_Surface.h> //this links to the Control Surface Library.

// Instantiate a hardware MIDI interface with Serial1 as its UART,
// using the default baud rate. If you want to specify a baud rete, Write it like this {Serial, 9600};
HardwareSerialMIDI_Interface midi {Serial};

MIDIAddress(int address, Channel channel = CHANNEL_1,);

void setup() {
// put your setup code here, to run once:

}

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

}

I have to agree with the compiler, it's not clear to me what you're trying to do here.

Please use code tags when posting code: How to get the best out of this forum

Im trying to setup a sketch with the proper Syntax that I'll need to make code for a MIDI Foot Controller Im building.

Description of the MIDI Controller
I need code for a MIDI Foot controller. It will be used to send CC# messages with Values to
control Guitar effect pedals.

It has Eight foot-switches (Buttons) each with an LED next to it.

The Buttons need to send specific CC messages when pressed (see CC# command example).

When a button is pressed I want the LED next to it, to light up.

The buttons are divided into three sections, Board, Stomp & Boost:
Board - [Has Two Buttons] and Controls a multi effect pedal.
Stomp - [Has Five Buttons] and Controls some other Effect pedals "Stomp Box's"
Boost - [Has One Button] and Controls the Boost.

Functions:
When One of the Five (Stomp) buttons is pressed, it should cancel out the other four.
The two "Board" buttons and the "Boost" Button should not be affected by the Stomp Buttons.

When One of the Two (Board) buttons is pressed, it should cancel out the other one.
The Five "Stomp" buttons and the "Boost" Button should not be affected by the Board Buttons.

The "Boost Button in a CC# Toggle to switch it on and off.
All the other buttons should not be affected by it.

CC# command example).
When Stomp button 1 is pressed, the following messages need to be sent all at the same time.

CC# CC Value MIDI Channel
2 0 5
31 0 3
1 127 5
3 2 5
4 4 5

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.