Could not figure out midi receive - help!

Midi Foot Controller - Need help - Can not figure out Midi receive

I'm working on a Midi Foot Controller and use a Teensy 2.0 and arduino ide. I made a workable code (sorry for that I am a newbie and this is only from parts of other projects) for 3 buttons with toggle function and sending Midi from Button 1 and Button 2. This is working quite well. Tried to add a midi receive, but it did not work. I don't understand how to do that.

So if a software (via preset) sends an on message from control 85, the LED1 of the controller should go on (and vice versa). Here is the working code with Midi send and Buttons/LEDs.

Code:

//Buttons, LEDs
#include <ButtonSwitch.h>

int buttonPin1 = 0; // define Pin XXX as the input of the button signal
int LED1 = 11; // define Pin XXX as the input of the LED signal
int buttonPin2 = 1;
int LED2 = 12;
int buttonPin3 = 2;
int LED3 = 13;

// declare button as a data type of Button_Switch connected to the buttonPin (in this case pin xxx of the Arduino),
buttonSwitch button1(buttonPin1);
buttonSwitch button2(buttonPin2);
buttonSwitch button3(buttonPin3);

// the setup function runs once when you press reset or power the board

//Midi Send Bounce
#include <Bounce.h> // Bounce library makes button change detection easy
const int channel = 1;

Bounce switch1 = Bounce(buttonPin1, 5); // 5 = 5 ms debounce time
Bounce switch2 = Bounce(buttonPin2, 5); // which is appropriate for good

void setup() {

pinMode(LED1, OUTPUT); // initialize digital pin LED_BUILTIN as an output
pinMode(buttonPin1, INPUT_PULLUP); // initialize digital pin for the push button as an input

pinMode(LED2, OUTPUT);
pinMode(buttonPin2, INPUT_PULLUP);

pinMode(LED3, OUTPUT);
pinMode(buttonPin3, INPUT_PULLUP);
}

// the loop function runs over and over again forever
void loop() {
digitalWrite(LED1, button1.SwitchI()); // turns the builtin LED on or off if the button was pushed
digitalWrite(LED2, button2.SwitchI());
digitalWrite(LED3, button3.SwitchI());

delay(10); // little delay needed to debounce the push button

//Loop Midi Send
switch1.update();
switch2.update();

// Note On messages when each button is pressed
if (switch1.fallingEdge()) {
usbMIDI.sendControlChange(85, 127, 1);
}
if (switch2.fallingEdge()) {
usbMIDI.sendControlChange(86, 127, 1);
}

// MIDI Controllers should discard incoming MIDI messages.
while (usbMIDI.read()) {
}
}

Maybe someone could help me to write an add for this code to receive midi message as discribed. Thanks a lot!!!

You will need to provide links to the libraries used, and since there is no declaration for 'usbMIDI' your code does anyway not compile. Please post you code within </> code-tags

Here is the code again.

//Buttons, LEDs
#include <ButtonSwitch.h>

int buttonPin1 = 0; // define Pin XXX as the input of the button signal
int LED1 = 11; // define Pin XXX as the input of the LED signal
int buttonPin2 = 1;
int LED2 = 12;
int buttonPin3 = 2;
int LED3 = 13;

// declare button as a data type of Button_Switch connected to the buttonPin (in this case pin xxx of the Arduino),
buttonSwitch button1(buttonPin1);
buttonSwitch button2(buttonPin2);
buttonSwitch button3(buttonPin3);

// the setup function runs once when you press reset or power the board

//Midi Send Bounce
#include <Bounce.h> // Bounce library makes button change detection easy
const int channel = 1;

Bounce switch1 = Bounce(buttonPin1, 5); // 5 = 5 ms debounce time
Bounce switch2 = Bounce(buttonPin2, 5); // which is appropriate for good

void setup() {

pinMode(LED1, OUTPUT); // initialize digital pin LED_BUILTIN as an output
pinMode(buttonPin1, INPUT_PULLUP); // initialize digital pin for the push button as an input

pinMode(LED2, OUTPUT);
pinMode(buttonPin2, INPUT_PULLUP);

pinMode(LED3, OUTPUT);
pinMode(buttonPin3, INPUT_PULLUP);
}

// the loop function runs over and over again forever
void loop() {
digitalWrite(LED1, button1.SwitchI()); // turns the builtin LED on or off if the button was pushed
digitalWrite(LED2, button2.SwitchI());
digitalWrite(LED3, button3.SwitchI());

delay(10); // little delay needed to debounce the push button

//Loop Midi Send
switch1.update();
switch2.update();

// Note On messages when each button is pressed
if (switch1.fallingEdge()) {
usbMIDI.sendControlChange(85, 127, 1);
}
if (switch2.fallingEdge()) {
usbMIDI.sendControlChange(86, 127, 1);
}

// MIDI Controllers should discard incoming MIDI messages.
while (usbMIDI.read()) {
}
}

I hope now the code is posted right. Sorry Newbie here.

I have installed teensyduino so the code is working. But I could not get it done to create a code for midi receive for example control 85 to turn on the led when the software sends on.

I could also figure out a code for Midi Receive. It works separatly but I am not able to combine these two codes please help me!!

Here is the code for Midi Receive!

int LED1 = 11;

void setup() {
 pinMode(LED1, OUTPUT);
 usbMIDI.setHandleControlChange(myControlChange);
}

void loop() {
 usbMIDI.read();
}
void myControlChange(byte channel, byte control, byte value) {
  if(channel == 1 && control == 86 && value == 127)
 digitalWrite(LED1, HIGH);

  if(channel == 1 && control == 86 && value == 0)
 digitalWrite(LED1, LOW);
}

You might be interested in the Control Surface library I maintain, your code would reduce down to the following:

#include <Control_Surface.h> // Include the Control Surface library
 
USBMIDI_Interface midi; // Instantiate a MIDI over USB interface.
 
// Instantiate an array of CCButton objects that send MIDI control
// change messages whenever the button is pressed/released
CCButton buttons[] {
  {0, 85}, // button pin number, controller number
  {1, 86},
  {2, 87},
};
// Create an array of CCValueLED objects that turn on/off an LED
// depending on the MIDI control change messages they receive
CCValueLED leds[] {
  {11, 85}, // led pin number, controller number
  {12, 86},
  {13, 87},
};

void setup() {
  Control_Surface.begin(); // Initialize Control Surface
}
 
void loop() {
  Control_Surface.loop(); // Update the Control Surface
}
1 Like

Hey this looks really cool. I have to try it. Thanks for the reply!

Hello there. Tried it and midi send and receive works. But the momentary buttons acts only momentary and it should act as a toogle switch. I am using the teensy 2.0 and therefore have done the wiring without a 10k ohm resistor for the switch. With teensy you don't need it when you write INPUT_PULLUP for the buttons. Maybe you can help me.

In that case you should use CCButtonLatched instead of CCButton.

That's not really related to the Teensy 2.0, you don't need an external resistor, the library will enable the INPUT_PULLUP for all buttons.

1 Like

Wow!!! That is very great. It works!!! Thanks so much.

I also wanted to implement two expression pedals, 3 banks and two lcd displays. Is this also possible with this library and is it also so easy. I am very impressed. Sitting here for a few hours and only had that noob code :slight_smile:

You can use Control Surface: Control-Change-Potentiometer.ino

What do you mean by a "bank"? Control Surface does support banking, is this what you're after? Control Surface: Bank.ino

What do you want to display on these LCD displays?

I have to try the expression pedal. Thanks for that.

I want to create a few midi banks. For example button1 on midi bank has the control 85. Button 1 on midi bank 2 the number 65. And so on.

For the moment the displays should only show a simple text. Maybe if a few midi banks are created it should show a different text for this bank.

Thanks in advice.

I have a question. Is the code stable, because I had to relink the teensy a few times. It stoped working. At the moment I testing Gig Performer with Asio4all and that could also be the problem.

Yes this is possible.

It should be, but I have never personally tested it on a Teensy 2.0. On the platforms that I did test (see the readme on GitHub), I didn't notice such issues.

Thanks a lot. I will look into the website of the library. I saw that there are a tons of examples. Will try it by myself, to learn how to use this great library. You helped me a lot to get my project Midi Foot Controller to work. Have a nice day and stay healthy!

P.S. May I ask you if I could come back to you if I get in some problems!?

So I got the expression pedal working. This was quite easy. Next step would be to integrate a LCD Display. There is no example for this at your website Control Surface, only for OLED. What would be the best way to do the coding. Is there an easy way with Control Surface too. I have a code that should work, but the codes with Control Surface library seems to be very good and short. Thanks for a short reply.

I need your help please. I could figure out how to implement a code for LCD, but now the expression pedals are moving very slow. Can't get what the problem is. Here is the code. Using control surface for buttons, midi, leds and expression pedals. The code for LCD is from another expample of an liquidcrystal i2c library. Here is the code.


//Control Surface
#include <Control_Surface.h> // Include the Control Surface library
 
USBMIDI_Interface midi; // Instantiate a MIDI over USB interface.
 
// Instantiate an array of CCButton objects that send MIDI control
// change messages whenever the button is pressed/released
CCButton buttons[] {
  {0, 85}, // button pin number, controller number
  {1, 86},
  {2, 87},
  {3, 88},
  {4, 89},
  {7, 90},
  {8, 91},
  {9, 92},
  {10, 93},
};
// Create an array of CCValueLED objects that turn on/off an LED
// depending on the MIDI control change messages they receive
CCValueLED leds[] {
  {11, 85}, // led pin number, controller number
  {12, 86},
  {13, 87},
  {14, 88},
  {15, 89},
  {16, 90},
  {17, 91},
  {18, 92},
  {19, 93},
};

// Instantiate a CCPotentiometer object
CCPotentiometer potentiometer[] = {
  {A0,0x10},                                   // Analog pin connected to potentiometer
  {MIDI_CC::Channel_Volume, CHANNEL_1}, // Channel volume of channel 1
  {A1,0x11},
  {MIDI_CC::Channel_Volume, CHANNEL_1}, // Channel volume of channel 1
};

//LCD Displays
#include <Wire.h>  // Wire Bibliothek hochladen
#include <LiquidCrystal_I2C.h> // Vorher hinzugefügte LiquidCrystal_I2C Bibliothek hochladen
LiquidCrystal_I2C lcd1(0x27, 16, 4);  //Hier wird das erste Display benannt (Adresse/Zeichen pro Zeile/Anzahl Zeilen). In unserem Fall „lcd1“. Die Adresse des I²C Displays kann je nach Modul variieren.
LiquidCrystal_I2C lcd2(0x26, 16, 4);  //Hier wird das zweite LCD benannt, hier "lcd2".


void setup() {
 
  Control_Surface.begin(); // Initialize Control Surface

//LCD Displays Setup
lcd1.init(); //Im Setup wird das LCD1 gestartet
lcd2.init(); //Im Setup wird das LCD2 gestartet
lcd1.backlight(); //Hintergrundbeleuchtung von LCD1 einschalten (0 schaltet die Beleuchtung aus).
lcd2.backlight(); //Hintergrundbeleuchtung von LCD2 einschalten (0 schaltet die Beleuchtung aus).
  
  
  
}
 
void loop() {
  
  Control_Surface.loop(); // Update the Control Surface

//LCD Displays Text
lcd1.setCursor(0,0); //Der folgende Text soll beim LCD1 beim ersten Zeichen in der ersten Zeile beginnen.
lcd1.print("CHORUS    PHASER"); //In der ersten Zeile soll der Text „Display1 Zeile 1“ angezeigt werden
lcd1.setCursor(0,1); 
lcd1.print("      BANK      "); 
lcd1.setCursor(-4,2); 
lcd1.print("        1       "); 
lcd1.setCursor(-4,3); 
lcd1.print("DELAY       ECHO"); 
lcd2.setCursor(0,0); //Der folgende Text soll beim LCD2 beim ersten Zeichen in der ersten Zeile beginnen.
lcd2.print("DIST         TAP"); //In der ersten Zeile soll der Text „Display2 Zeile 1“ angezeigt werden
lcd2.setCursor(0,1); 
lcd2.print(""); 
lcd2.setCursor(-4,2); 
lcd2.print(""); 
lcd2.setCursor(-4,3); 
lcd2.print("FLANGER  OVERDRV");  
  
}


Printing to the display might take some time, you can benchmark it using something like this:

auto t0 = micros();
lcd1.setCursor(0,0); 
// ...
auto t1 = micros();
Serial.print("Updating the display took: ");
Serial.print(t1 - t0);
Serial.println("µs");

The first step is to move the LCD code out of the main loop, and only update the display if any of the contents changed.

If that's not enough, you can try to increase the I²C speed.

It should be only a static text on display. Because I use the controller as an effect on off pedal. The display should only show the effect type.

I can leave the code in the loop and complete it with your benchmark example. Is this right?

Yes.

Then move the static text to the setup, and only write to the display in the loop if you have to update the text.

Sorry this is to high for me. I don't know where to put which code now! Or is there a better easier way with control surface library?

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

USBMIDI_Interface midi; // Instantiate a MIDI over USB interface.

// Instantiate an array of CCButton objects that send MIDI control
// change messages whenever the button is pressed/released
CCButton buttons[] {
  {0, 85}, // button pin number, controller number
  {1, 86},
  {2, 87},
  {3, 88},
  {4, 89},
  {7, 90},
  {8, 91},
  {9, 92},
  {10, 93},
};
// Create an array of CCValueLED objects that turn on/off an LED
// depending on the MIDI control change messages they receive
CCValueLED leds[] {
  {11, 85}, // led pin number, controller number
  {12, 86},
  {13, 87},
  {14, 88},
  {15, 89},
  {16, 90},
  {17, 91},
  {18, 92},
  {19, 93},
};

// Instantiate a CCPotentiometer object
CCPotentiometer potentiometer[] = {
  {A0, 0x10},                                  // Analog pin connected to potentiometer
  {MIDI_CC::Channel_Volume, CHANNEL_1}, // Channel volume of channel 1
  {A1, 0x11},
  {MIDI_CC::Channel_Volume, CHANNEL_1}, // Channel volume of channel 1
};

//LCD Displays
#include <Wire.h>  // Wire Bibliothek hochladen
#include <LiquidCrystal_I2C.h> // Vorher hinzugefügte LiquidCrystal_I2C Bibliothek hochladen
LiquidCrystal_I2C lcd1(0x27, 16, 4);  //Hier wird das erste Display benannt (Adresse/Zeichen pro Zeile/Anzahl Zeilen). In unserem Fall „lcd1“. Die Adresse des I²C Displays kann je nach Modul variieren.
LiquidCrystal_I2C lcd2(0x26, 16, 4);  //Hier wird das zweite LCD benannt, hier "lcd2".


void setup() {
  Control_Surface.begin(); // Initialize Control Surface
  Serial.begin(115200);

  //LCD Displays Setup
  lcd1.init(); //Im Setup wird das LCD1 gestartet
  lcd2.init(); //Im Setup wird das LCD2 gestartet
  lcd1.backlight(); //Hintergrundbeleuchtung von LCD1 einschalten (0 schaltet die Beleuchtung aus).
  lcd2.backlight(); //Hintergrundbeleuchtung von LCD2 einschalten (0 schaltet die Beleuchtung aus).
}

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

  auto t0 = micros();
  //LCD Displays Text
  lcd1.setCursor(0, 0); //Der folgende Text soll beim LCD1 beim ersten Zeichen in der ersten Zeile beginnen.
  lcd1.print("CHORUS    PHASER"); //In der ersten Zeile soll der Text „Display1 Zeile 1“ angezeigt werden
  lcd1.setCursor(0, 1);
  lcd1.print("      BANK      ");
  lcd1.setCursor(-4, 2);
  lcd1.print("        1       ");
  lcd1.setCursor(-4, 3);
  lcd1.print("DELAY       ECHO");
  lcd2.setCursor(0, 0); //Der folgende Text soll beim LCD2 beim ersten Zeichen in der ersten Zeile beginnen.
  lcd2.print("DIST         TAP"); //In der ersten Zeile soll der Text „Display2 Zeile 1“ angezeigt werden
  lcd2.setCursor(0, 1);
  lcd2.print("");
  lcd2.setCursor(-4, 2);
  lcd2.print("");
  lcd2.setCursor(-4, 3);
  lcd2.print("FLANGER  OVERDRV");
  auto t1 = micros();
  Serial.print("Updating the display took: ");
  Serial.print(t1 - t0);
  Serial.println("µs");
}

Then open the Serial Monitor, and select a baud rate of 115200.

No, updating the LCD is independent from Control Surface.

1 Like

Ok thanks again. If this works, I am quite happy. By now... I have to go deeper by starting at the very beginning of c++. This is a little bit confusing right now. But the possibilitys are great!