MIDI Controller with 4x4 Analog Keypad

I'm trying to build a midi controller as a first Arduino UNO project, I want to add a 4x4 Analog Keypad as a MIDI Keyboard.

I want each button pressed to move up a note. Im using analogRead but it's getting values on a constant loop so it's sending the MIDI message repeatedly. I've tried other methods with scripts I've found that will stop the looping but messes with the keypad voltage.

This method causes the buttons to loop repeatedly


/////////////////////////////////////////////
// LIBRARIES
#include <MIDI.h> // by Francois Best
MIDI_CREATE_DEFAULT_INSTANCE();
MIDI_CREATE_INSTANCE(HardwareSerial,Serial, midiOut);


/////////////////////////////////////////////
// MIDI
byte midiCh = 1; //* MIDI channel to be used
byte note = 36; //* Lowest note to be used
byte cc = 1; //* Lowest MIDI CC to be used


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

void loop()
{
  matrix();
  
}


  void matrix() {
  int buttonValue;
  buttonValue = analogRead(A1); //Read analog value from A1 pin
  
  //For 1st button:
  if (buttonValue>=1000)
     midiOut.sendNoteOn(36,127,1);
      else if(buttonValue>900)
   midiOut.sendNoteOn(37,127,1);
 else if(buttonValue>820)
   midiOut.sendNoteOn(38,127,1);
 else if(buttonValue>750)
   midiOut.sendNoteOn(39,127,1);
 else if(buttonValue>660)
   midiOut.sendNoteOn(40,127,1);
 else if(buttonValue>620)
   midiOut.sendNoteOn(41,127,1);
 else if(buttonValue>585)
   midiOut.sendNoteOn(42,127,1);
 else if(buttonValue>540)
   midiOut.sendNoteOn(43,127,1);
 else if(buttonValue>500)
   midiOut.sendNoteOn(44,127,1);
 else if(buttonValue>475)
   midiOut.sendNoteOn(45,127,1);
 else if(buttonValue>455)
   midiOut.sendNoteOn(46,127,1);
 else if(buttonValue>425)
   midiOut.sendNoteOn(47,127,1);
 else if(buttonValue>370)
   midiOut.sendNoteOn(48,127,1);
 else if(buttonValue>300)
   midiOut.sendNoteOn(49,127,1);
 else if(buttonValue>260)
   midiOut.sendNoteOn(50,127,1);
 else if(buttonValue>200)
   midiOut.sendNoteOn(51,127,1);
 else if (buttonValue>=0)
   midiOut.sendNoteOn(36,0,0);
 
  delay(150);

}

Is it simple to get set up a MIDI keypad with an analog button matrix in a single analog pin or are the voltage reads too unpredictable to get it to run smoothly? Should I just use a digital keypad instead?

Thanks

You should anyway add some kind of 'debounce' to your function, and prevent sending a message twice.
The analog keypad has as a disadvantage that it can only register 1 button at a time.

try something like


#include <MIDI.h> // by Francois Best

#define DEBOUNCE 50

MIDI_CREATE_INSTANCE(HardwareSerial, Serial, midiOut);


byte midiCh = 1; //* MIDI channel to be used
byte note = 36; //* Lowest note to be used
byte cc = 1; //* Lowest MIDI CC to be used


void setup() {
  //Serial.begin(115250);
}

void loop() {
  matrix();
}


void matrix() {
  int newbutton, buttonValue;
  static int oldbutton, debbutton;
  static uint32_t debouncestart;
  buttonValue = analogRead(A1); //Read analog value from A1 pin

  if (buttonValue >= 1000)
    newbutton = 36;
  else if (buttonValue > 900)
    newbutton = 37;
  else if (buttonValue > 820)
    newbutton = 38;
  else if (buttonValue > 750)
    newbutton = 39;
  else if (buttonValue > 660)
    newbutton = 40;
  else if (buttonValue > 620)
    newbutton = 41;
  else if (buttonValue > 585)
    newbutton = 42;
  else if (buttonValue > 540)
    newbutton = 43;
  else if (buttonValue > 500)
    newbutton = 44;
  else if (buttonValue > 475)
    newbutton = 45;
  else if (buttonValue > 455)
    newbutton = 46;
  else if (buttonValue > 425)
    newbutton = 47;
  else if (buttonValue > 370)
    newbutton = 48;
  else if (buttonValue > 300)
    newbutton = 49;
  else if (buttonValue > 260)
    newbutton = 50;
  else if (buttonValue > 200)
    newbutton = 51;
  else if (buttonValue >= 0)
    newbutton = 52;
    
  if (newbutton != debbutton) {
    debouncestart = millis();
    debbutton = newbutton;
  }
  if (millis() - debouncestart < DEBOUNCE) return;
  
  if (newbutton != oldbutton) {
    midiOut.sendNoteOn(newbutton,127,1);
    oldbutton = newbutton;
  }
}

I removed the extra midi instance that you don't use, and commented out the 'Serial.begin()' since you've declared your serial port for the midiout object.

1 Like

Just a note to say that this is not an Analog keypad as there is no such thing. The web page says this keypad is assembled not analog.

it is analog

OK my bad.

1 Like

Okay one small issue sorry, every button press works perfectly except on release I want the MIDI note to be the same as what was pressed

 else if (buttonValue >= 0)
    newbutton = 52;

so "newbutton" on value 0 needs to be the same note as what button was pressed, this is so the MIDI recognises the button has been released. Other than that everything else perfect!

You have to keep a list of what buttons are currently pressed. Then when a button changes you have to remove that button from the list. When you remove it you can then send the appropriate note off message.

This will involve some new code, it is not a simple fix, unless you want it to only play one note at a time and not be able to press two keys at once. Then it is easy, just make a copy in a variable when you send a note on message of the note, and then before you send a note on message send the note off message of the note stored in this variable. Then it will act like a drone with a change in continuous note when you press a key. But for some instruments like a piano that naturally decay it will sound fine. Others like an organ you will get the drone effect.

1 Like

Since with this keyboard you can only recognize one 'press' of a button at a time this is not true.
I am going from the point of view that when newbutton == 52 you have released all buttons, in that case
just change the last part of the function to

  if (newbutton != oldbutton) {
    if (oldbutton != 52) midiOut.sendNoteOn(oldbutton,0,1);  // releases the oldbutton, and sends noteoff (noteOn velocity 0 == noteOff)
    if (newbutton != 52) midiOut.sendNoteOn(newbutton,127,1); // presses the newbutton and sends the noteOn
    oldbutton = newbutton;
  }
1 Like

Yep that fixed it, having the same note makes the MIDI program recognise that the button has been released. Appreciate the help! :smiley:

1 Like

Yes exactly what I suggested in the latter part of my last post.

Yes but there is no need to keep track of every button.

Never said there was for that last part.

You somehow forgot that the keypad only registers 1 key at a time (or none at all)