Super simple midi keyboard

Brief update, but I got mine all working. I had the same trouble using the d13 pin, so I just switched it to a4 and it works great now! Before I mess with a more permanent enclosure, I’m wanting to attempt adding a pot for mod wheel control. I found some code from Notes and Volts on YouTube that may allow me to do it (fingers crossed!)

What is the exact reason we are doing the note on/off backwards in this example. Can anyone clarify?

5 Likes

If you have any issues with handling analog inputs let us know, it can be a bit more fiddly. But if notes n volts code works for you, great!

3 Likes

I have been lurking and have gotten it all to work, but my analog buttons are triggering over and over again. I have no coding knowledge so I am not really sure what I can do to fix this. Any help is appreciated.

1 Like

Im pretty sure your buttons are digital, but are you meaning they are connected to an analog input? Can you share your code? Sounds like a simple matter. :slight_smile:

2 Likes

Hello yes, my buttons are digital, just standard pushbuttons.
The buttons connected to the A pins are sending a midi on message over and over when the button is pressed instead of a single on message.

//below is a code with slightly more complexity to only send midi on and off commands once for every button push
// this is quoting the code from the video https://youtu.be/wY1SRehZ9hM

#include <MIDI.h>
MIDI_CREATE_DEFAULT_INSTANCE();

int button1 = 2; //button1 on digital pin 2
int button2 = 3; //button2 on digital pin 3
int button3 = 4; //button3 on digital pin 4
int button4 = 5; //button4 on digital pin 5
int button5 = 6; //button5 on digital pin 6
int button6 = 7; //button6 on digital pin 7
int button7 = 8; //button7 on digital pin 8
int button8 = 9; //button8 on digital pin 9
int button9 = 10; //button9 on digital pin 10
int button10 = 11; //button10 on digital pin 11
int button11 = 12; //button11 on digital pin 12
int button12 = 14; 
int button13 = 15; 
int button14 = 16; 
int button15 = 17; 
int button16 = 18; 


int button1beans = 0;
int button2beans = 0;
int button3beans = 0;
int button4beans = 0;
int button5beans = 0;
int button6beans = 0;
int button7beans = 0;
int button8beans = 0;
int button9beans = 0;
int button10beans = 0;
int button11beans = 0;
int button12beans = 0;
int button13beans = 0;
int button14beans = 0;
int button15beans = 0;
int button16beans = 0;

int button1state = 0; //these state values help us only sendmidi commands once for every button put
int button2state = 0; //bear in mind this will only be a problem if you plan on having lots of midi things going on at once
int button3state = 0; //it just stops clogging up the midi feed with constant midi off commands.
int button4state = 0; //as themore keys you send the more midi off commands are constantly being sent
int button5state = 0; //so this just neatens the midi stream a bit to prevent mistakes. 
int button6state = 0;
int button7state = 0;
int button8state = 0;
int button9state = 0;
int button10state = 0;
int button11state = 0;
int button12state = 0;
int button13state = 0;
int button14state = 0;
int button15state = 0;
int button16state = 0;



void setup()
{
  MIDI.begin(); //BEINNINFG IDIU TGHUBGS

pinMode(button1, INPUT_PULLUP); //pinMode means the pin is in input mode with an internal pull up resistor, so it is waiting to receive ground to do something
pinMode(button2, INPUT_PULLUP); //pinMode means the pin is in input mode with an internal pull up resistor, so it is waiting to receive ground to do something
pinMode(button3, INPUT_PULLUP); //pinMode means the pin is in input mode with an internal pull up resistor, so it is waiting to receive ground to do something
pinMode(button4, INPUT_PULLUP); //pinMode means the pin is in input mode with an internal pull up resistor, so it is waiting to receive ground to do something
pinMode(button5, INPUT_PULLUP); //pinMode means the pin is in input mode with an internal pull up resistor, so it is waiting to receive ground to do something
pinMode(button6, INPUT_PULLUP); //pinMode means the pin is in input mode with an internal pull up resistor, so it is waiting to receive ground to do something
pinMode(button7, INPUT_PULLUP); //pinMode means the pin is in input mode with an internal pull up resistor, so it is waiting to receive ground to do something
pinMode(button8, INPUT_PULLUP); //pinMode means the pin is in input mode with an internal pull up resistor, so it is waiting to receive ground to do something
pinMode(button9, INPUT_PULLUP); //pinMode means the pin is in input mode with an internal pull up resistor, so it is waiting to receive ground to do something
pinMode(button10, INPUT_PULLUP);//pinMode means the pin is in input mode with an internal pull up resistor, so it is waiting to receive ground to do something
pinMode(button11, INPUT_PULLUP);//pinMode means the pin is in input mode with an internal pull up resistor, so it is waiting to receive ground to do something
pinMode(button12, INPUT_PULLUP);//pinMode means the pin is in input mode with an internal pull up resistor, so it is waiting to receive ground to do something
pinMode(button13, INPUT_PULLUP);//pinMode means the pin is in input mode with an internal pull up resistor, so it is waiting to receive ground to do something
pinMode(button14, INPUT_PULLUP);//pinMode means the pin is in input mode with an internal pull up resistor, so it is waiting to receive ground to do something
pinMode(button15, INPUT_PULLUP);//pinMode means the pin is in input mode with an internal pull up resistor, so it is waiting to receive ground to do something
pinMode(button16, INPUT_PULLUP);//pinMode means the pin is in input mode with an internal pull up resistor, so it is waiting to receive ground to do something

  
}



void loop()
{

  button1beans = digitalRead(button1); //read status of button
  button2beans = digitalRead(button2); //read status of button
  button3beans = digitalRead(button3); //read status of button
  button4beans = digitalRead(button4); //read status of button
  button5beans = digitalRead(button5); //read status of button
  button6beans = digitalRead(button6); //read status of button
  button7beans = digitalRead(button7); //read status of button
  button8beans = digitalRead(button8); //read status of button
  button9beans = digitalRead(button9); //read status of button
  button10beans = digitalRead(button10); //read status of button
  button11beans = digitalRead(button11); //read status of button
  button12beans = digitalRead(button12); //read status of button
  button13beans = digitalRead(button13); //read status of button
  button14beans = digitalRead(button14); //read status of button
  button15beans = digitalRead(button15); //read status of button
  button16beans = digitalRead(button16); //read status of button


  if ((button1beans == LOW) && (button1state == 0))
  { MIDI.sendNoteOn(36,127,1); //turn midi note on 36 velocity 127, midi channel 1. 
    button1state = 1;}  
  if ((button1beans == HIGH) && (button1state == 1))
  { MIDI.sendNoteOff(36,0,1);  //turn midi note off 36 velocity 127, midi channel 1. 
    button1state = 0;
  }  


  if ((button2beans == LOW) && (button2state == 0))
  { MIDI.sendNoteOn(37,127,1); //turn midi note on 38 velocity 127, midi channel 1. 
    button2state = 1;}  
  if ((button2beans == HIGH) && (button2state == 1))
  { MIDI.sendNoteOff(37,0,1);  //turn midi note off 38 velocity 127, midi channel 1. 
    button2state = 0;
  }  
  
  if ((button3beans == LOW) && (button3state == 0))
  { MIDI.sendNoteOn(38,127,1); //turn midi note on 40 velocity 127, midi channel 1. 
    button3state = 1;}  
  if ((button3beans == HIGH) && (button3state == 1))
  { MIDI.sendNoteOff(38,0,1);  //turn midi note off 40 velocity 127, midi channel 1. 
    button3state = 0;
  }  
  
  if ((button4beans == LOW) && (button4state == 0))
  { MIDI.sendNoteOn(39,127,1); //turn midi note on 41 velocity 127, midi channel 1. 
    button4state = 1;}  
  if ((button4beans == HIGH) && (button4state == 1))
  { MIDI.sendNoteOff(39,0,1);  //turn midi note off 41 velocity 127, midi channel 1. 
    button4state = 0;
  }  
  
  if ((button5beans == LOW) && (button5state == 0))
  { MIDI.sendNoteOn(40,127,1); //turn midi note on 43 velocity 127, midi channel 1. 
    button5state = 1;}  
  if ((button5beans == HIGH) && (button5state == 1))
  { MIDI.sendNoteOff(40,0,1);  //turn midi note off 43 velocity 127, midi channel 1. 
    button5state = 0;
  }  
  
  if ((button6beans == LOW) && (button6state == 0))
  { MIDI.sendNoteOn(41,127,1); //turn midi note on 45 velocity 127, midi channel 1. 
    button6state = 1;}  
  if ((button6beans == HIGH) && (button6state == 1))
  { MIDI.sendNoteOff(41,0,1);  //turn midi note off 45 velocity 127, midi channel 1. 
    button6state = 0;
  }  
  
  if ((button7beans == LOW) && (button7state == 0))
  { MIDI.sendNoteOn(42,127,1); //turn midi note on 47 velocity 127, midi channel 1. 
    button7state = 1;}  
  if ((button7beans == HIGH) && (button7state == 1))
  { MIDI.sendNoteOff(42,0,1);  //turn midi note off 47 velocity 127, midi channel 1. 
    button7state = 0;
  }  
  
  if ((button8beans == LOW) && (button8state == 0))
  { MIDI.sendNoteOn(43,127,1); //turn midi note on 48 velocity 127, midi channel 1. 
    button8state = 1;}  
  if ((button8beans == HIGH) && (button8state == 1))
  { MIDI.sendNoteOff(43,0,1);  //turn midi note off 48 velocity 127, midi channel 1. 
    button8state = 0;
  }  
  
  if ((button9beans == LOW) && (button9state == 0))
  { MIDI.sendNoteOn(44,127,1); //turn midi note on 50 velocity 127, midi channel 1. 
    button9state = 1;}  
  if ((button9beans == HIGH) && (button9state == 1))
  { MIDI.sendNoteOff(44,0,1);  //turn midi note off 50 velocity 127, midi channel 1. 
    button9state = 0;
  }  

  if ((button10beans == LOW) && (button10state == 0))
  { MIDI.sendNoteOn(45,127,1); //turn midi note on 52 velocity 127, midi channel 1. 
    button10state = 1;}  
  if ((button10beans == HIGH) && (button10state == 1))
  { MIDI.sendNoteOff(45,0,1);  //turn midi note off 52 velocity 127, midi channel 1. 
    button10state = 0;
  } 
  
  if ((button11beans == LOW) && (button11state == 0))
  { MIDI.sendNoteOn(46,127,1); //turn midi note on 53 velocity 127, midi channel 1. 
    button11state = 1;}  
  if ((button11beans == HIGH) && (button11state == 1))
  { MIDI.sendNoteOff(46,0,1);  //turn midi note off 53 velocity 127, midi channel 1. 
    button11state = 0;
  }   

  if ((button12beans == LOW) && (button12state == 0))
  { MIDI.sendNoteOn(47,127,1); //turn midi note on 53 velocity 127, midi channel 1. 
    button11state = 1;}  
  if ((button12beans == HIGH) && (button12state == 1))
  { MIDI.sendNoteOff(47,0,1);  //turn midi note off 53 velocity 127, midi channel 1. 
    button11state = 0;
  }   
      if ((button13beans == LOW) && (button13state == 0))
  { MIDI.sendNoteOn(48,127,1); //turn midi note on 53 velocity 127, midi channel 1. 
    button11state = 1;}  
  if ((button13beans == HIGH) && (button13state == 1))
  { MIDI.sendNoteOff(48,0,1);  //turn midi note off 53 velocity 127, midi channel 1. 
    button11state = 0;
  }   
   if ((button14beans == LOW) && (button14state == 0))
  { MIDI.sendNoteOn(49,127,1); //turn midi note on 53 velocity 127, midi channel 1. 
    button11state = 1;}  
  if ((button14beans == HIGH) && (button14state == 1))
  { MIDI.sendNoteOff(49,0,1);  //turn midi note off 53 velocity 127, midi channel 1. 
    button11state = 0;
  }   
     if ((button15beans == LOW) && (button15state == 0))
  { MIDI.sendNoteOn(50,127,1); //turn midi note on 53 velocity 127, midi channel 1. 
    button11state = 1;}  
  if ((button15beans == HIGH) && (button15state == 1))
  { MIDI.sendNoteOff(50,0,1);  //turn midi note off 53 velocity 127, midi channel 1. 
    button11state = 0;
  }   
     if ((button16beans == LOW) && (button16state == 0))
  { MIDI.sendNoteOn(51,127,1); //turn midi note on 53 velocity 127, midi channel 1. 
    button11state = 1;}  
  if ((button16beans == HIGH) && (button16state == 1))
  { MIDI.sendNoteOff(51,0,1);  //turn midi note off 53 velocity 127, midi channel 1. 
    button11state = 0;
  }   
    

  }

Hey, try this:

int button1 = 2; //button1 on digital pin 2
int button2 = 3; //button2 on digital pin 3
int button3 = 4; //button3 on digital pin 4
int button4 = 5; //button4 on digital pin 5
int button5 = 6; //button5 on digital pin 6
int button6 = 7; //button6 on digital pin 7
int button7 = 8; //button7 on digital pin 8
int button8 = 9; //button8 on digital pin 9
int button9 = 10; //button9 on digital pin 10
int button10 = 11; //button10 on digital pin 11
int button11 = 12; //button11 on digital pin 12

// use the analog pins as digital inputs by their reference like: A0...A5
int button12 = A0;
int button13 = A1; 
int button14 = A2; 
int button15 = A3; 
int button16 = A4; 

If you were trying to hook to the analog pins and use them as digital inputs, you can, but you should reference them like that!

per doc:

So you get the A0-A5 as digital pins, but you got to refer to them as such!

2 Likes

I think you might have a cut-and-paste error here - your button12-16 code are all setting button11state rather than button12-16state…

This is why I’d go for loops for this kind of thing.

I know Sam argues that cut-and-paste code like this is more obvious, but I personally think it obscures what is really going on and whilst a loop might be harder to write, it is easier to read once you know what is going on :slight_smile:

You can see the basic idea here (Arduino Nano MIDI Keyboard – Simple DIY Electronic Music Projects), but note that this is monophonic - it isn’t managing state for every key, just for the “last key”, so it isn’t an ideal example. I have some other examples that manage key state better, but not to hand (I ought to update this one tbh - maybe I’ll do that later!!). Anyway it shows how you can use a loop to initialise a range of inputs from pins.

Another Update: I’ve just updated the code for polyphonic use regardless :slight_smile: For a more detailed explanation of how it works, see the now updated blog post.

Kevin

7 Likes

As a software engineer, I can confirm that copy/paste is a major source of bugs, and a maintenance nightmare…

4 Likes

So that was it, I appreciate the help!

3 Likes

Great! No problem :slight_smile:

1 Like

I was just setting up for a spot of soldering, went to get my 220R’s out, to find I only have one. So which line is it best to use it on while I wait on more arriving…? The 5V line, or the UART tx line…?

Also, this figure from the MIDI Spec website appears to show pin 2 connected to ground. No mention of doing this though. Is it not required then…?

I’d put it on the tx line to protect the transmitter against shorts.

But, do you have any other resistors?
You could put a 180 and a 270, instead of the two 220s.
Or your 220 on the tx and a 180, or two 110s in series, instead of the other 220.
Doesn’t have to be exactly 220, any small resistor is better than none.

2 Likes

I have a dearth of small resistors, but have ordered more 220R, which will hopefully be here soon.

1 Like

Look at the image from the MIDI spec, look at the image on the project page, look at the image from the MIDI spec, look at the image on the project page, look at the image from the MIDI spec, look at the image on the project page. Solder the leads on the wrong tabs anyway, don’t notice till they’re all nicely heat shrinked… :person_facepalming:

I made a version out of an old arcade stick with 8 face buttons for playing notes, two buttons on the back for changing active octave range, and joystick octave changing. The joystick up and down directions are mapped so they change the current octave when you’re holding up or down, while the two buttons on the back shift the 3 octaves available out of a total of 7. The octave controls are easier to understand if you read the source code (hopefully). It’s powered via the original usb cable from the arcade stick. I also limited the notes to white keys so it’s a little harder to play off sounding notes.

// inspired by https://youtu.be/wY1SRehZ9hM

#include <MIDI.h>

MIDI_CREATE_DEFAULT_INSTANCE();

// note buttons
const int firstPin = 2;
const int numNotePins = 8;  // 8 face buttons of arcade stick
const int numTotalOctaves = 7;
const int numActiveOctaves = 3;  // middle octave when joystick is untouched, increase and decrease octave when UP or DOWN are held
int myButtons[numNotePins];
int myButtonVals[numNotePins];
int myButtonStates[numNotePins];

// UP and DOWN buttons for octave control
const int upPin = 12;
const int downPin = 13;
int upVal = 0;
int downVal = 0;
int upState = 0;
int downState = 0;

// START and BACK buttons for octave range control
const int startPin = 11;
const int backPin = 10;
int startVal = 0;
int backVal = 0;
int startState = 0;
int backState = 0;

int octave = 0;
int octaveRangeCursor = 2;
const int minOctaveRangeCursor = 0;
const int maxOctaveRangeCursor = 4;

const int whiteKeys[numTotalOctaves][numNotePins] = {
  { 12, 14, 16, 17, 19, 21, 23, 24 },
  { 24, 26, 28, 29, 31, 33, 35, 36 },
  { 36, 38, 40, 41, 43, 45, 47, 48 },  // default octave
  { 48, 50, 52, 53, 55, 57, 59, 60 },  // default octave
  { 60, 62, 64, 65, 67, 69, 71, 72 },  // default octave
  { 72, 74, 76, 77, 79, 81, 83, 84 },
  { 84, 86, 88, 89, 91, 93, 95, 96 },
};

void setup() {
  MIDI.begin();
  // comment the line above and uncomment the line below if you need to console log with Serial.println();
  // Serial.begin(9600);

  pinMode(upPin, INPUT_PULLUP);
  pinMode(downPin, INPUT_PULLUP);
  pinMode(startPin, INPUT_PULLUP);
  pinMode(backPin, INPUT_PULLUP);

  for (int i = 0; i < numNotePins; i++) {
    myButtons[i] = firstPin + i;
    myButtonVals[i] = 0;
    myButtonStates[i] = 0;phot
    pinMode(myButtons[i], INPUT_PULLUP);
  }
}

void loop() {
  upVal = digitalRead(upPin);
  downVal = digitalRead(downPin);
  startVal = digitalRead(startPin);
  backVal = digitalRead(backPin);

  // increase octave range cursor when START pressed
  if ((startVal == LOW) && (startState == 0)) {
    startState = 1;
  } else if ((startVal == HIGH) && (startState == 1)) {
    startState = 0;
    octaveRangeCursor++;
    if (octaveRangeCursor > maxOctaveRangeCursor) {
      octaveRangeCursor = maxOctaveRangeCursor;
    }
  }
  // decrease octave range cursor when BACK pressed
  if ((backVal == LOW) && (backState == 0)) {
    backState = 1;
  } else if ((backVal == HIGH) && (backState == 1)) {
    backState = 0;
    octaveRangeCursor--;
    if (octaveRangeCursor < minOctaveRangeCursor) {
      octaveRangeCursor = minOctaveRangeCursor;
    }
  }

  // increase octave when UP held
  if ((upVal == LOW) && (upState == 0)) {
    octave = 1;
    upState = 1;
  } else if ((upVal == HIGH) && (upState == 1)) {
    octave = 0;
    upState = 0;
  }
  // decrease octave when DOWN held
  if ((downVal == LOW) && (downState == 0)) {
    octave = -1;
    downState = 1;
  } else if ((downVal == HIGH) && (downState == 1)) {
    octave = 0;
    downState = 0;
  }

  // play notes when note buttons are held
  for (int i = 0; i < numNotePins; i++) {
    myButtonVals[i] = digitalRead(myButtons[i]);

    if ((myButtonVals[i] == LOW) && (myButtonStates[i] == 0)) {
      MIDI.sendNoteOn(whiteKeys[octaveRangeCursor + (octave + 1)][i], 127, 1);
      myButtonStates[i] = 1;
    } else if ((myButtonVals[i] == HIGH) && (myButtonStates[i] == 1)) {
      MIDI.sendNoteOff(whiteKeys[octaveRangeCursor + (octave + 1)][i], 0, 1);
      myButtonStates[i] = 0;
    }
  }
}
4 Likes

the BRAWLSTICK MIDI CONTROLLER!

maybe you can try a breath controller next!

4 Likes