Midi Help

So I’m a total noob :o to coding. I could really use some help adding to the code I’m currently utilizing. Basically I’ve built a 13 key midi foot controller (non usb) using an arduino mega 2560, sparkfun midi shield, and some salvaged organ pedals. I would like to utilize the leds, buttons, and potentiometers on the sparkfun midi shield but I cant find much straightforward advice.

What I would like to do in order of priority:

  1. MAIN ISSUE Run D4 as octave up and D2 as octave down and D3 could be a return to home octave button or something else better i havent thought of yet.

  2. green led always on (i think i can possibly figure this one out. lol)

  3. run one potentiometer as a velocity control.

  4. the other potentiometer as resonance control.

  5. red led on when notes are on

Ive attached my current code that runs great but I will note I am not the author. ive only slightly modified variables to customize certain functions, but so far the keyboard alone functions great in the current bass octave i have it set to.

So here is the rundown of what I do know thanks to Sparkfun:

-The pushbuttons are on D2, D3, and D4. To use them, enable the corresponding pins as inputs with pullup pinMode(, INPUT_PULLUP); and read them with digitalRead();. The inputs are active low - they will normally read as a logic HIGH, going LOW while the button is pressed.

-The potentiometers are connected to A0 and A1. You can read them using analogRead().

-Finally, the LEDs are on D6 (Green) and D7 (Red). The outputs are enabled using pinMode(, OUTPUT), and set using digitalWrite(, ). Like the buttons, these are active low – writing HIGH turns the LED off.

Thank you guys for your time! I hope to learn more about arduino in the future.

BassPedals1.ino (2.38 KB)

That sketch is small enough to fit within your post

#define DEBOUNCE 1500

struct key
{
    int pin;
    int midiKey;
    int debounce;
    int keySent;
};

struct key keys[] =
{
  { 22, 25, 0, 0 },  // Db red
  { 24, 26, 0, 0 },  // D  red
  { 26, 27, 0, 0 },  // Eb orange
  { 28, 28, 0, 0 },  // E  orange
  { 30, 29, 0, 0 },  // F  yellow
  { 32, 30, 0, 0 },  // Gb green
  { 34, 31, 0, 0 },  // G  green
  { 36, 32, 0, 0 },  // Ab blue
  { 38, 33, 0, 0 },  // A  blue
  { 40, 34, 0, 0 },  // Bb violet
  { 42, 35, 0, 0 },  // B  violet
  { 44, 36, 0, 0 },  // C  brown
  { 48, 24, 0, 0 },  // C  brown
  { 0, 0, 0, 0 }     // end of list marker
};

int keyOffset = 0;
int keyVelocity = 100;

void setup() {
  // put your setup code here, to run once:
  for(int i = 0; keys[i].pin != 0; ++i)
  {
    pinMode(keys[i].pin, INPUT_PULLUP);
  }
  //start serial with midi baudrate 31250
  Serial.begin(31250);    
}

void Midi_Send(byte cmd, byte data1, byte data2) 
{
  Serial.write(cmd);
  Serial.write(data1);
  Serial.write(data2);
}

void noteOn(int midiKey)
{
  Midi_Send(0x90, midiKey, keyVelocity);
}

void noteOff(int midiKey)
{
  Midi_Send(0x80, midiKey, keyVelocity);
}

void loop() {
  // put your main code here, to run repeatedly:
  byte byte1;
  byte byte2;
  byte byte3;
  int value;

  //*************** MIDI THRU ******************//
  if(Serial.available() > 0)
  {
    byte1 = Serial.read();
    byte2 = Serial.read();
    byte3 = Serial.read();

    Midi_Send(byte1, byte2, byte3);
  }

  // Look for bass pedal key events
  for(int i = 0; keys[i].pin != 0; ++i)
  {
    value = digitalRead(keys[i].pin);
    if(keys[i].debounce == 0) // Key has been off
    {
      if(value == LOW)        // Key is now on
      {
        noteOn(keys[i].midiKey + keyOffset);      // Send the MIDI note on message
        keys[i].keySent = keys[i].midiKey + keyOffset;
        keys[i].debounce = DEBOUNCE;  // Set the note off debounce counter
      }
    }
    else                      // Key has been on
    {
      if(value == HIGH)       // Key has gone off
      {
        if(--keys[i].debounce == 0) // If Key has remained off for DEBOUNCE scans, 
          noteOff(keys[i].keySent); // In case the offset has changed, send MIDI off for the right note
      }
      else                    // Key has not gone off
        keys[i].debounce = DEBOUNCE;  // Reset debounce counter in case we got 
                                      // a small number of key off scans
    }
  } 
}

first note that 1500ms debounce is huge !
Looking further on since int keyVelocity = 100;is global, it shouldn’t be to hard to assign the result of analogRead() to it somewhere, keep in mind analogRead() returns a value 0-1023 and midi will want a value 0-127 (noteOn 0 actually == noteOff) and your fader may not go along the full range of 0-5v (mine doesn’t) so you may need to calibrate it.
If resonance is a specific CC then you’ll have to create a variable holding the current value and compare that to the fader position (analogRead() ) and if there is a change send the new value as a CC (you can find the specific midi command code online)
about the red LED, since there are functions for noteOn and noteOff, turning it on when a noteOn is executed is no issue, but how to make sure it doesn’t turn off when one key is held but another released may take some more effort. (you will have to keep track off all notes that are on)
For the matter of octave switching, you can create a variable that hold the current octave and multiply by 12 and add it to the midi note send.

Thanks for your quick insight! also thanks for posting the sketch in the forum so others can read. The debounce is so high because of the old spring switching mechanism in the pedals. It likes to double trigger notes if i lower it too much.

before soldering was all done photo. finishing up the outer casing soon.

UPDATE

lol....So I got the LEDs to work the way I wanted them to!......but then the midi notes wouldn't turn off... RIP

DAY 2 in Arduino IDE is very intense and many curse words have been said, but I'm starting to be able to read the language a bit better.

So show us what you did !

I’ll continue too debug and post later. in the mean time, I did find this code for someone who wants to go overboard with LCD and it supposedly reduces latency but I dont even experience latency.

#include <arduino2.h>

#include <pins2_arduino.h>

/* 4/2/16 this works with no delay

LiquidCrystal Library - setCursor

LiquidCrystal declaration:

LiquidCrystal lcd(RS,Enable,D4,D5,D6,D7)

The circuit:

1 Ground

2 5 Volts (VCC)

3 Display Contrast (VO) - to 10kohm potentiometer wiper (pin 2)

4 Register Select (RS) - controls whether writing to data register or instruction register. Command (0) or Character (1). Attached to digital pin (see above).

5 Read/Write (RW) - Selects reading mode or writing mode. optional, can attach to ground per LiquidCrystal() description on Arduino.cc and Wikipedia. Write (0) or Read (1). Attached to ground.

6 Enable (E) Attached to digital pin (see above).

7 Data Bit 0 (Not used in 4-bit operation) Open

8 Data Bit 1 (Not used in 4-bit operation) Open

9 Data Bit 2 (Not used in 4-bit operation) Open

10 Data Bit 3 (Not used in 4-bit operation) Open

11 Data Bit 4 attached to digital pin (see above)

12 Data Bit 5 attached to digital pin (see above)

13 Data Bit 6 attached to digital pin (see above)

14 Data Bit 7 attached to digital pin (see above)

15 LED Backlight Anode + to 220ohm resistor to 5 Volt

16 LED Backlight Cathode - to Ground

The Pot: (front view?)

O

1 2 3

1 goes to ground

2 (wiper) goes to VO

3 goes to 5V

(hopefully this is not reversed)

MIDI

Female output from inside:

O

14253

* MIDI jack pin 4 connected to +5V through 220-ohm resistor

* MIDI jack pin 2 connected to ground

* MIDI jack pin 5 to digital in 1 connected

*/

#include <LiquidCrystal.h>

//Pedals: Low C through High C

#define SWITCH1 30

#define SWITCH2 31

#define SWITCH3 32

#define SWITCH4 33

#define SWITCH5 34

#define SWITCH6 35

#define SWITCH7 36

#define SWITCH8 37

#define SWITCH9 38

#define SWITCH10 39

#define SWITCH11 40

#define SWITCH12 41

#define SWITCH13 42

#define PEDALBOUNCE 20

//Buttons will be: Select_Panic, SELECT_RIGHT, SELECT_UP, SELECT_DOWN

#define Select_Panic A0

#define Select_Right A1

#define Select_Up A2

#define Select_Down A3

#define BUTTONBOUNCE 300

int Buttons[17] = {SWITCH1, SWITCH2, SWITCH3, SWITCH4, SWITCH5, SWITCH6, SWITCH7, SWITCH8, SWITCH9, SWITCH10, SWITCH11, SWITCH12, SWITCH13, Select_Panic, Select_Right, Select_Up, Select_Down};

int ButtonState[17] = {HIGH, HIGH, HIGH, HIGH, HIGH, HIGH, HIGH, HIGH, HIGH, HIGH, HIGH, HIGH, HIGH, HIGH, HIGH, HIGH, HIGH};

int currentButton = 0;

int currentButtonState;

int TriggeredNote[13] = {36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48};

unsigned long stopTime;

boolean breakLoop;

//string arrays

const String LCDNoteName[12] = {"C ", "C#", "D ", "D#", "E ", "F ", "F#", "G ", "G#", "A ", "A#", "B "};

const String LCDNoteOctave[11] = {" 0", "1 ", "2 ", "3 ", "4 ", "5 ", "6 ", "7 ", "8 ", "9 ", "10"};

//LCD Initial Values: Volume - 0-127, Program - 0-127, Channel - 1-16, LowNote - 000(C0)-127(GC10)

byte Volume = 100;

byte Program = 0;

byte Channel = 0;

byte LowNote = 24; //C2

byte LowNoteName = 0; //C or LowNote%12

byte LowNoteOctave = 2; //Octave 2 or LowNote/12

// LCD dimensions

const int numRows = 2;

const int numCols = 16;

//Cursor Position: 1-Volume 2-Program 3-Channel 4-Low Note

int CursorPosition = 1;

// initialize the LCD library with the numbers of the interface pins

LiquidCrystal lcd(14,15,16,17,18,19);

void Right() {

switch (CursorPosition) {

case 1:

lcd.setCursor(4, 1);

CursorPosition = 2;

break;

case 2:

lcd.setCursor(8, 1);

CursorPosition = 3;

break;

case 3:

lcd.setCursor(12, 1);

CursorPosition = 4;

break;

case 4:

lcd.setCursor(0, 1);

CursorPosition = 1;

break;

}

}

void Up() {

switch (CursorPosition) {

case 1:

if (Volume < 127)

Volume += 1;

if (Volume < 10) {

lcd.print("00");

}

else {

if (Volume < 100) {

lcd.print("0");

}

}

lcd.print(Volume, DEC);

lcd.setCursor(0, 1);

break;

case 2:

if (Program < 127)

Program += 1;

if (Program < 10) {

lcd.print("00");

}

else {

if (Program < 100) {

lcd.print("0");

}

}

lcd.print(Program, DEC);

lcd.setCursor(4, 1);

Serial.write(0xc0 + Channel);

Serial.write(Program);

break;

case 3:

if (Channel < 15)

Channel += 1;

lcd.print("0");

if (Channel < 9) {

lcd.print("0");

}

lcd.print(Channel + 1, DEC);

lcd.setCursor(8, 1);

break;

case 4:

if (LowNote < 127)

LowNote += 1;

for (int Counter = 0; Counter <= 13; Counter++) {

TriggeredNote[Counter]++;

}

LowNoteName = LowNote % 12;

LowNoteOctave = LowNote / 12;

lcd.print (LCDNoteName[LowNoteName] + LCDNoteOctave[LowNoteOctave]);

lcd.setCursor(12, 1);

break;

}

}

void Down() {

switch (CursorPosition) {

case 1:

if (Volume > 0)

Volume -= 1;

if (Volume < 10) {

lcd.print("00");

}

else {

if (Volume < 100) {

lcd.print("0");

}

}

lcd.print(Volume, DEC);

lcd.setCursor(0, 1);

break;

case 2:

if (Program > 0)

Program -= 1;

if (Program < 10) {

lcd.print("00");

}

else {

if (Program < 100) {

lcd.print("0");

}

}

lcd.print(Program, DEC);

lcd.setCursor(4, 1);

Serial.write(0xc0 + Channel);

Serial.write(Program);

break;

case 3:

if (Channel > 0)

Channel -= 1;

lcd.print("0");

if (Channel < 9) {

lcd.print("0");

}

lcd.print(Channel + 1, DEC);

lcd.setCursor(8, 1);

break;

case 4:

if (LowNote > 0)

LowNote -= 1;

for (int Counter = 0; Counter <= 13; Counter++) {

TriggeredNote[Counter]--;

}

LowNoteName = LowNote % 12;

LowNoteOctave = LowNote / 12;

lcd.print (LCDNoteName[LowNoteName] + LCDNoteOctave[LowNoteOctave]);

lcd.setCursor(12, 1);

break;

}

}

void Panic()

{ for (int Counter = 0; Counter <= 15; Counter++) {

Serial.write(176 + Counter);

Serial.write(123);

Serial.write(0);

}

}

void noteOn(int cmd, int pitch, int velocity) {

Serial.write(cmd);

Serial.write(pitch);

Serial.write(velocity);

}

void setup() {

// Set MIDI baud rate:

Serial.begin(31250);

// set up the LCD's number of columns and rows:

lcd.begin(numCols, numRows);

lcd.setCursor(0, 0);

lcd.print("VOL PRG CHN LOW");

lcd.setCursor(0, 1);

lcd.print("100 000 001 C 2");

lcd.setCursor(0, 1);

lcd.cursor();

//set up buttons

for ( currentButton = 0; currentButton < 17; currentButton++ ) {

pinMode2( Buttons[currentButton], INPUT ); // Set pin for switch

digitalWrite2( Buttons[currentButton], HIGH ); // Turn on internal pullup

}

}

void loop() {

while (true) {

breakLoop = false;

while (breakLoop == false) {

for ( currentButton = 0; currentButton < 17; currentButton++ ) {

currentButtonState = digitalRead2(Buttons[currentButton]);

if (currentButton < 13) {

{

if (currentButtonState != ButtonState[currentButton] ) {

if ( ButtonState[currentButton] == LOW ) {

noteOn(0x80 + Channel, TriggeredNote[currentButton], 0x00);

ButtonState[currentButton] = HIGH;

}

else

{ noteOn(0x90 + Channel, TriggeredNote[currentButton], Volume);

ButtonState[currentButton] = LOW;

}

stopTime = millis() + PEDALBOUNCE;

while (millis() < stopTime) {};

}

}

if (currentButton == 13 && currentButtonState == LOW) {

Panic();

stopTime = millis() + BUTTONBOUNCE;

while (millis() < stopTime) {};

}

if (currentButton > 13 && currentButtonState == LOW) {

breakLoop = true;

stopTime = millis() + BUTTONBOUNCE;

while (millis() < stopTime) {};

}

}

}

breakLoop = false;

while (breakLoop == false) {

for ( currentButton = 0; currentButton < 17; currentButton++ ) {

currentButtonState = digitalRead2(Buttons[currentButton]);

if (currentButton < 13 && currentButtonState == LOW) {

breakLoop = true;

stopTime = millis() + PEDALBOUNCE;

while (millis() < stopTime) {};

}

if (currentButton == 13 && currentButtonState == LOW) {

Panic();

stopTime = millis() + BUTTONBOUNCE;

while (millis() < stopTime) {};

}

if (currentButton == 14 && currentButtonState == LOW) {

Right();

stopTime = millis() + BUTTONBOUNCE;

while (millis() < stopTime) {};

}

if (currentButton == 15 && currentButtonState == LOW) {

Up();

stopTime = millis() + BUTTONBOUNCE;

while (millis() < stopTime) {};

}

if (currentButton == 16 && currentButtonState == LOW) {

Down();

stopTime = millis() + BUTTONBOUNCE;

while (millis() < stopTime) {};

}

}

}

}

}

}

I never experience latency either, and eh, i know it's not your code, but format it using ctrl-t and remove all excess empty lines will make it a lot more readable.