turning keypad example into midi controller button matrix

Status
Not open for further replies.

nicnut

Well-known member
Hi everyone.

So I have been at it making a serious midi controller for a few months. There will be a lot of button switches on this controller and for my prototyping I am using some simple button switches to figure this out.

I am using a Teensy 3.6. I recently was informed about the keypad method of reading buttons switches using the keypad library , which would save me a lot of connections, and I'd like to implement this into my code, although I've never used it before.

I altered the HelloKeypad example for my design of 4X4 rows and columns of buttons. Using the serial monitor I can see that my buttons are working and when they are pressed I can see them listed in the serial monitor.

Here's my code for that

Code:
//4/26/20


#include <Bounce.h>
#include <Adafruit_NeoPixel.h>
#include <Keypad.h>
#include <Wire.h> // wire library for LED matrix


const byte ROWS = 4; //four rows
const byte COLS = 4; //three columns
char keys[ROWS][COLS] = {
  {'1', '2', '3', '4'},
  {'5', '6', '7', '8'},
  {'9', 'a', 'b', 'c'},
  {'d', 'e', 'f', 'g'}
};

byte rowPins[ROWS] = {32, 31, 30, 29}; //teensy pins to connect to the row pinouts of the keypad
byte colPins[COLS] = {28, 27, 12, 11,}; //connect to the column pinouts of the keypad

Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

void setup() {
  Serial.begin(9600);

}

void loop() {
  char key = keypad.getKey();

  if (key) {
    Serial.println(key);
  }
}


What I need is that when a button is pressed I get a 127 value for a particular midi controller, and when it is not pressed that value is a 0.
Below is the code I tried out.

Right now i am getting a 0 for midi controller number 20, and a 127 for every other midi controller( 21-35) no matter what button I press. And I see a lot of midi information streaming in.

Any suggestions on how to fix this?

I also looked at the EventKeypad example, where there is a switch and each case is accounted for in the code. I was thinking of trying that, but I wanted to ask if anyone has any suggestions first.

Also, I was previously incorporating a 5 millisecond bounce for my button switches. I want to implement that too eventually.

Thank you in advance for any help or suggestions.

Here is what I came up with.


Code:
//4/26/20


#include <Bounce.h>
#include <Adafruit_NeoPixel.h>
#include <Keypad.h>
#include <Wire.h> // wire library for LED matrix


const byte ROWS = 4; //four rows
const byte COLS = 4; //three columns
char keys[ROWS][COLS] = {
  {'1', '2', '3', '4'},
  {'5', '6', '7', '8'},
  {'9', 'a', 'b', 'c'},
  {'d', 'e', 'f', 'g'}
};

byte rowPins[ROWS] = {32, 31, 30, 29}; //teensy pins to connect to the row pinouts of the keypad
byte colPins[COLS] = {28, 27, 12, 11,}; //connect to the column pinouts of the keypad

Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

const int channel = 1;
const int MIDIchannel = 1;   // this will only apply to midi channel 1


const int controllerD20 = 20; // toggle, control change 14
const int controllerD21 = 21; //  Button, control change 15
const int controllerD22 = 22; //
const int controllerD23 = 23;
const int controllerD24 = 24;  //
const int controllerD25 = 25;
const int controllerD26 = 26;
const int controllerD27 = 27;
const int controllerD28 = 28;
const int controllerD29 = 29;
const int controllerD30 = 30;
const int controllerD31 = 31;
const int controllerD32 = 32;
const int controllerD33 = 33;
const int controllerD34 = 34;
const int controllerD35 = 35;

Bounce button0 = Bounce(0, 5);
Bounce button1 = Bounce(1, 5);  // 5 = 5 ms debounce time
Bounce button2 = Bounce(2, 5);  // which is appropriate for good
Bounce button3 = Bounce(3, 5);  // quality mechanical pushbuttons
Bounce button4 = Bounce(4, 5);
Bounce button5 = Bounce(5, 5);  // if a button is too "sensitive"
Bounce button6 = Bounce(6, 5);  // to rapid touch, you can
Bounce button7 = Bounce(7, 5);  // increase this time.
Bounce button8 = Bounce(8, 5);
Bounce button9 = Bounce(9, 5);
Bounce button10 = Bounce(10, 5);
Bounce button11 = Bounce(11, 5);
Bounce button12 = Bounce(12, 5);  // goes out of order because other pins double as analog inputs

Bounce button24 = Bounce(24, 5);
Bounce button25 = Bounce(25, 5);
Bounce button26 = Bounce(26, 5);

void setup() {

 // pinMode(latch, OUTPUT);
 // digitalWrite(latch, LOW);
 // pinMode(clock, OUTPUT);
 // digitalWrite(clock, LOW);
//  pinMode(data, OUTPUT);
//  digitalWrite(data, LOW);

  
//  Serial.begin(9600);

  

}

void loop() {
  char key = keypad.getKey();

  if (key == 1) {
     usbMIDI.sendControlChange(controllerD20, 127, channel);
  }

  if (key != 1) {
     usbMIDI.sendControlChange(controllerD20, 0, channel);
  }


  if (key = 2) {
     usbMIDI.sendControlChange(controllerD21, 127, channel);
  }

    if (key != 2) {
     usbMIDI.sendControlChange(controllerD21, 0, channel);
  }

    if (key = 3) {
     usbMIDI.sendControlChange(controllerD22, 127, channel);
  }

      if (key != 3) {
     usbMIDI.sendControlChange(controllerD22, 0, channel);
  }

  if (key = 4) {
     usbMIDI.sendControlChange(controllerD23, 127, channel);
  }

      if (key != 4) {
     usbMIDI.sendControlChange(controllerD24, 0, channel);
  }

  if (key = 5) {
     usbMIDI.sendControlChange(controllerD24, 127, channel);
  }

      if (key != 5) {
     usbMIDI.sendControlChange(controllerD24, 0, channel);
  }

    if (key = 6) {
     usbMIDI.sendControlChange(controllerD25, 127, channel);
  }

      if (key != 6) {
     usbMIDI.sendControlChange(controllerD25, 0, channel);
  }

      if (key = 7) {
     usbMIDI.sendControlChange(controllerD26, 127, channel);
  }

      if (key != 7) {
     usbMIDI.sendControlChange(controllerD26, 0, channel);
  }

    if (key = 8) {
     usbMIDI.sendControlChange(controllerD27, 127, channel);
  }

    if (key != 8) {
     usbMIDI.sendControlChange(controllerD27, 0, channel);
  }
      if (key = 9) {
     usbMIDI.sendControlChange(controllerD28, 127, channel);
  }

      if (key != 9) {
     usbMIDI.sendControlChange(controllerD28, 0, channel);
  }

      if (key = 'a') {
     usbMIDI.sendControlChange(controllerD29, 127, channel);
  }

    if (key != 'a') {
     usbMIDI.sendControlChange(controllerD29, 0, channel);
  }


  if (key = 'b') {
     usbMIDI.sendControlChange(controllerD30, 127, channel);
  }

    if (key != 'b') {
     usbMIDI.sendControlChange(controllerD30, 0, channel);
  }


  if (key = 'c') {
     usbMIDI.sendControlChange(controllerD31, 127, channel);
  }

      if (key != 'c') {
     usbMIDI.sendControlChange(controllerD31, 0, channel);
  }


    if (key = 'd') {
     usbMIDI.sendControlChange(controllerD32, 127, channel);
  }

      if (key != 'd') {
     usbMIDI.sendControlChange(controllerD32, 0, channel);
  }


      if (key = 'e') {
     usbMIDI.sendControlChange(controllerD33, 127, channel);
  }

      if (key != 'e') {
     usbMIDI.sendControlChange(controllerD33, 0, channel);
  }


    if (key = 'f') {
     usbMIDI.sendControlChange(controllerD34, 127, channel);
  }

    if (key != 'f') {
     usbMIDI.sendControlChange(controllerD34, 0, channel);
  }


      if (key = 'g') {
     usbMIDI.sendControlChange(controllerD35, 127, channel);
  }
  
    if (key != 'g') {
     usbMIDI.sendControlChange(controllerD35, 0, channel);
  }

  // MIDI Controllers should discard incoming MIDI messages.
  // http://forum.pjrc.com/threads/24179-Teensy-3-Ableton-Analog-CC-causes-midi-crash
  while (usbMIDI.read()) {
    // ignore incoming messages
  }
  
}
 
This and all the others that follow are wrong:
Code:
  if (key = 2) {
It should be ==

But IIRC, the library returns the character '1' etc., not the integer 1.
You could make the code much shorter by either using an array of controller numbers, or in your case they are contiguous so you just map the keypad into an index.

You also do not check for the case where no key was pressed. The library returns the pre-defined value NO_KEY in this case and you should check for this before anything else and ignore it.

Pete
 
Hi @el_supremo

Thank you for taking a look. Damn, I knew it was ==, just didn't check that.

I corrected some of the things you pointed out and I am getting way better results.

Now when I press a button I get a 127, but when I release it the value stays at 127. When I press another button that new button's value becomes 127 and the previous button that I already released goes to 0.

What I want to happen is when I press a button it goes to 127 and when I release it, it goes to 0. Also I want to be able to press more than one button at a time.I hope that is achievable. Let me know if you have any suggestions. I'm glad I am getting some results now at least.

Thanks, Nick

Code:
//4/26/20


#include <Bounce.h>
#include <Adafruit_NeoPixel.h>
#include <Keypad.h>
#include <Wire.h> // wire library for LED matrix


const byte ROWS = 4; //four rows
const byte COLS = 4; //three columns
char keys[ROWS][COLS] = {
  {'1', '2', '3', '4'},
  {'5', '6', '7', '8'},
  {'9', 'a', 'b', 'c'},
  {'d', 'e', 'f', 'g'}
};

byte rowPins[ROWS] = {32, 31, 30, 29}; //teensy pins to connect to the row pinouts of the keypad
byte colPins[COLS] = {28, 27, 12, 11,}; //connect to the column pinouts of the keypad

Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

const int channel = 1;
const int MIDIchannel = 1;   // this will only apply to midi channel 1


const int controllerD20 = 20; // toggle, control change 14
const int controllerD21 = 21; //  Button, control change 15
const int controllerD22 = 22; //
const int controllerD23 = 23;
const int controllerD24 = 24;  //
const int controllerD25 = 25;
const int controllerD26 = 26;
const int controllerD27 = 27;
const int controllerD28 = 28;
const int controllerD29 = 29;
const int controllerD30 = 30;
const int controllerD31 = 31;
const int controllerD32 = 32;
const int controllerD33 = 33;
const int controllerD34 = 34;
const int controllerD35 = 35;

Bounce button0 = Bounce(0, 5);
Bounce button1 = Bounce(1, 5);  // 5 = 5 ms debounce time
Bounce button2 = Bounce(2, 5);  // which is appropriate for good
Bounce button3 = Bounce(3, 5);  // quality mechanical pushbuttons
Bounce button4 = Bounce(4, 5);
Bounce button5 = Bounce(5, 5);  // if a button is too "sensitive"
Bounce button6 = Bounce(6, 5);  // to rapid touch, you can
Bounce button7 = Bounce(7, 5);  // increase this time.
Bounce button8 = Bounce(8, 5);
Bounce button9 = Bounce(9, 5);
Bounce button10 = Bounce(10, 5);
Bounce button11 = Bounce(11, 5);
Bounce button12 = Bounce(12, 5);  // goes out of order because other pins double as analog inputs

Bounce button24 = Bounce(24, 5);
Bounce button25 = Bounce(25, 5);
Bounce button26 = Bounce(26, 5);

void setup() {

  // pinMode(latch, OUTPUT);
  // digitalWrite(latch, LOW);
  // pinMode(clock, OUTPUT);
  // digitalWrite(clock, LOW);
  //  pinMode(data, OUTPUT);
  //  digitalWrite(data, LOW);


  //  Serial.begin(9600);



}

void loop() {

  char key = keypad.getKey();

  if (key != NO_KEY)
  {

    if (key == '1') {
      usbMIDI.sendControlChange(controllerD20, 127, channel);
    }

    if (key != '1') {
      usbMIDI.sendControlChange(controllerD20, 0, channel);
    }


    if (key == '2') {
      usbMIDI.sendControlChange(controllerD21, 127, channel);
    }

    if (key != '2') {
      usbMIDI.sendControlChange(controllerD21, 0, channel);
    }

    if (key == '3') {
      usbMIDI.sendControlChange(controllerD22, 127, channel);
    }

    if (key != '3') {
      usbMIDI.sendControlChange(controllerD22, 0, channel);
    }

    if (key == '4') {
      usbMIDI.sendControlChange(controllerD23, 127, channel);
    }

    if (key != '4') {
      usbMIDI.sendControlChange(controllerD24, 0, channel);
    }

    if (key == '5') {
      usbMIDI.sendControlChange(controllerD24, 127, channel);
    }

    if (key != '5') {
      usbMIDI.sendControlChange(controllerD24, 0, channel);
    }

    if (key == '6') {
      usbMIDI.sendControlChange(controllerD25, 127, channel);
    }

    if (key != '6') {
      usbMIDI.sendControlChange(controllerD25, 0, channel);
    }

    if (key == '7') {
      usbMIDI.sendControlChange(controllerD26, 127, channel);
    }

    if (key != '7') {
      usbMIDI.sendControlChange(controllerD26, 0, channel);
    }

    if (key == '8') {
      usbMIDI.sendControlChange(controllerD27, 127, channel);
    }

    if (key != '8') {
      usbMIDI.sendControlChange(controllerD27, 0, channel);
    }
    if (key == '9') {
      usbMIDI.sendControlChange(controllerD28, 127, channel);
    }

    if (key != '9') {
      usbMIDI.sendControlChange(controllerD28, 0, channel);
    }

    if (key == 'a') {
      usbMIDI.sendControlChange(controllerD29, 127, channel);
    }

    if (key != 'a') {
      usbMIDI.sendControlChange(controllerD29, 0, channel);
    }


    if (key == 'b') {
      usbMIDI.sendControlChange(controllerD30, 127, channel);
    }

    if (key != 'b') {
      usbMIDI.sendControlChange(controllerD30, 0, channel);
    }


    if (key == 'c') {
      usbMIDI.sendControlChange(controllerD31, 127, channel);
    }

    if (key != 'c') {
      usbMIDI.sendControlChange(controllerD31, 0, channel);
    }


    if (key == 'd') {
      usbMIDI.sendControlChange(controllerD32, 127, channel);
    }

    if (key != 'd') {
      usbMIDI.sendControlChange(controllerD32, 0, channel);
    }


    if (key == 'e') {
      usbMIDI.sendControlChange(controllerD33, 127, channel);
    }

    if (key != 'e') {
      usbMIDI.sendControlChange(controllerD33, 0, channel);
    }


    if (key == 'f') {
      usbMIDI.sendControlChange(controllerD34, 127, channel);
    }

    if (key != 'f') {
      usbMIDI.sendControlChange(controllerD34, 0, channel);
    }


    if (key == 'g') {
      usbMIDI.sendControlChange(controllerD35, 127, channel);
    }

    if (key != 'g') {
      usbMIDI.sendControlChange(controllerD35, 0, channel);
    }
  }

  // MIDI Controllers should discard incoming MIDI messages.
  // http://forum.pjrc.com/threads/24179-Teensy-3-Ableton-Analog-CC-causes-midi-crash
  while (usbMIDI.read()) {
    // ignore incoming messages
  }

}
 
I also tried this out. I thought this might work to get a 0 value when you are not pressing a key, but didn't work
Code:
void loop() {

  char key = keypad.getKey();

  if (key != NO_KEY)
  {

    if (key == '1') {
      usbMIDI.sendControlChange(controllerD20, 127, channel);
    }

    if (key != '1') {
      usbMIDI.sendControlChange(controllerD20, 0, channel);
    }
  }
  
 if (key != NO_KEY)
  {

    if (key == '2') {
      usbMIDI.sendControlChange(controllerD21, 127, channel);
    }

    if (key != '2') {
      usbMIDI.sendControlChange(controllerD21, 0, channel);
    }

  }

 if (key != NO_KEY)
  {
  
    if (key == '3') {
      usbMIDI.sendControlChange(controllerD22, 127, channel);
    }

    if (key != '3') {
      usbMIDI.sendControlChange(controllerD22, 0, channel);
    }

  }
}
 
When you press a key, getKey returns the value of the key. But when you release the key, you don't get any notification that the key has been released so your code never sends a zero to a controller.
But, that information is available when you use the addEventListener() function in the keypad library. Have a look at the EventKeypad sketch in the Keypad examples.

Pete
 
OK now I know why you are named el_supremo. Your suggestions have totally worked.

I added a function "void keypadEvent" from the EventKeypad example. It has a switch in it. I basically added my midi control change stuff in there. Now this code will let you know if someone presses, holds, or releases a button.

But there is one other issue. I can only press one button at a time. Is there a way I can press multiple buttons? And have them both as pressed? Maybe I need a new switch for each button with 3 different states. I am going to look into that.


Thank you so much for the help.

Here is the code

Code:
//4/26/20


#include <Bounce.h>
#include <Adafruit_NeoPixel.h>
#include <Keypad.h>
#include <Wire.h> // wire library for LED matrix


const byte ROWS = 4; //four rows
const byte COLS = 4; //three columns
char keys[ROWS][COLS] = {
  {'1', '2', '3', '4'},
  {'5', '6', '7', '8'},
  {'9', 'a', 'b', 'c'},
  {'d', 'e', 'f', 'g'}
};

byte rowPins[ROWS] = {32, 31, 30, 29}; //teensy pins to connect to the row pinouts of the keypad
byte colPins[COLS] = {28, 27, 12, 11,}; //connect to the column pinouts of the keypad

Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

const int channel = 1;
const int MIDIchannel = 1;   // this will only apply to midi channel 1


const int controllerD20 = 20; // toggle, control change 14
const int controllerD21 = 21; //  Button, control change 15
const int controllerD22 = 22; //
const int controllerD23 = 23;
const int controllerD24 = 24;  //
const int controllerD25 = 25;
const int controllerD26 = 26;
const int controllerD27 = 27;
const int controllerD28 = 28;
const int controllerD29 = 29;
const int controllerD30 = 30;
const int controllerD31 = 31;
const int controllerD32 = 32;
const int controllerD33 = 33;
const int controllerD34 = 34;
const int controllerD35 = 35;

Bounce button0 = Bounce(0, 5);
Bounce button1 = Bounce(1, 5);  // 5 = 5 ms debounce time
Bounce button2 = Bounce(2, 5);  // which is appropriate for good
Bounce button3 = Bounce(3, 5);  // quality mechanical pushbuttons
Bounce button4 = Bounce(4, 5);
Bounce button5 = Bounce(5, 5);  // if a button is too "sensitive"
Bounce button6 = Bounce(6, 5);  // to rapid touch, you can
Bounce button7 = Bounce(7, 5);  // increase this time.
Bounce button8 = Bounce(8, 5);
Bounce button9 = Bounce(9, 5);
Bounce button10 = Bounce(10, 5);
Bounce button11 = Bounce(11, 5);
Bounce button12 = Bounce(12, 5);  // goes out of order because other pins double as analog inputs

Bounce button24 = Bounce(24, 5);
Bounce button25 = Bounce(25, 5);
Bounce button26 = Bounce(26, 5);

void setup() {

  // pinMode(latch, OUTPUT);
  // digitalWrite(latch, LOW);
  // pinMode(clock, OUTPUT);
  // digitalWrite(clock, LOW);
  //  pinMode(data, OUTPUT);
  //  digitalWrite(data, LOW);


  //  Serial.begin(9600);

  keypad.addEventListener(keypadEvent); // Add an event listener for this keypad


}

void loop() {

  char key = keypad.getKey();

 

  // MIDI Controllers should discard incoming MIDI messages.
  // http://forum.pjrc.com/threads/24179-Teensy-3-Ableton-Analog-CC-causes-midi-crash
  while (usbMIDI.read()) {
    // ignore incoming messages
  }

}


void keypadEvent(KeypadEvent key) {
  switch (keypad.getState()) {
    case PRESSED:
      if (key == '1') {
        usbMIDI.sendControlChange(controllerD20, 127, channel);
      }
      if (key == '2') {
        usbMIDI.sendControlChange(controllerD21, 127, channel);
      }
      if (key == '3') {
        usbMIDI.sendControlChange(controllerD22, 127, channel);
      }
      if (key == '4') {
        usbMIDI.sendControlChange(controllerD23, 127, channel);
      }
      if (key == '5') {
        usbMIDI.sendControlChange(controllerD24, 127, channel);
      }
      if (key == '6') {
        usbMIDI.sendControlChange(controllerD25, 127, channel);
      }
      if (key == '7') {
        usbMIDI.sendControlChange(controllerD26, 127, channel);
      }
      if (key == '8') {
        usbMIDI.sendControlChange(controllerD27, 127, channel);
      }
      if (key == '9') {
        usbMIDI.sendControlChange(controllerD28, 127, channel);
      }
      if (key == 'a') {
        usbMIDI.sendControlChange(controllerD29, 127, channel);
      }
      if (key == 'b') {
        usbMIDI.sendControlChange(controllerD30, 127, channel);
      }
      if (key == 'c') {
        usbMIDI.sendControlChange(controllerD31, 127, channel);
      }
      if (key == 'd') {
        usbMIDI.sendControlChange(controllerD32, 127, channel);
      }
      if (key == 'e') {
        usbMIDI.sendControlChange(controllerD33, 127, channel);
      }
      if (key == 'f') {
        usbMIDI.sendControlChange(controllerD34, 127, channel);
      }
      if (key == 'g') {
        usbMIDI.sendControlChange(controllerD35, 127, channel);
      }
      break;

    case RELEASED:
      if (key == '1') {
        usbMIDI.sendControlChange(controllerD20, 0, channel);
      }
      if (key == '2') {
        usbMIDI.sendControlChange(controllerD21, 0, channel);
      }
      if (key == '3') {
        usbMIDI.sendControlChange(controllerD22, 0, channel);
      }
      if (key == '4') {
        usbMIDI.sendControlChange(controllerD23, 0, channel);
      }
      if (key == '5') {
        usbMIDI.sendControlChange(controllerD24, 0, channel);
      }
      if (key == '6') {
        usbMIDI.sendControlChange(controllerD25, 0, channel);
      }
      if (key == '7') {
        usbMIDI.sendControlChange(controllerD26, 0, channel);
      }
      if (key == '8') {
        usbMIDI.sendControlChange(controllerD27, 0, channel);
      }
      if (key == '9') {
        usbMIDI.sendControlChange(controllerD28, 0, channel);
      }
      if (key == 'a') {
        usbMIDI.sendControlChange(controllerD29, 0, channel);
      }
      if (key == 'b') {
        usbMIDI.sendControlChange(controllerD30, 0, channel);
      }
      if (key == 'c') {
        usbMIDI.sendControlChange(controllerD31, 0, channel);
      }
      if (key == 'd') {
        usbMIDI.sendControlChange(controllerD32, 0, channel);
      }
      if (key == 'e') {
        usbMIDI.sendControlChange(controllerD33, 0, channel);
      }
      if (key == 'f') {
        usbMIDI.sendControlChange(controllerD34, 0, channel);
      }
      if (key == 'g') {
        usbMIDI.sendControlChange(controllerD35, 0, channel);
      }
      break;

    case HOLD:
      if (key == '1') {
        usbMIDI.sendControlChange(controllerD20, 127, channel);
      }
      if (key == '2') {
        usbMIDI.sendControlChange(controllerD21, 127, channel);
      }
      if (key == '3') {
        usbMIDI.sendControlChange(controllerD22, 127, channel);
      }
      if (key == '4') {
        usbMIDI.sendControlChange(controllerD23, 127, channel);
      }
      if (key == '5') {
        usbMIDI.sendControlChange(controllerD24, 127, channel);
      }
      if (key == '6') {
        usbMIDI.sendControlChange(controllerD25, 127, channel);
      }
      if (key == '7') {
        usbMIDI.sendControlChange(controllerD26, 127, channel);
      }
      if (key == '8') {
        usbMIDI.sendControlChange(controllerD27, 127, channel);
      }
      if (key == '9') {
        usbMIDI.sendControlChange(controllerD28, 127, channel);
      }
      if (key == 'a') {
        usbMIDI.sendControlChange(controllerD29, 127, channel);
      }
      if (key == 'b') {
        usbMIDI.sendControlChange(controllerD30, 127, channel);
      }
      if (key == 'c') {
        usbMIDI.sendControlChange(controllerD31, 127, channel);
      }
      if (key == 'd') {
        usbMIDI.sendControlChange(controllerD32, 127, channel);
      }
      if (key == 'e') {
        usbMIDI.sendControlChange(controllerD33, 127, channel);
      }
      if (key == 'f') {
        usbMIDI.sendControlChange(controllerD34, 127, channel);
      }
      if (key == 'g') {
        usbMIDI.sendControlChange(controllerD35, 127, channel);
      }
      break;

  }
}
 
OK now I'm taking a look at the multi key example in Keypad. I think that will do what I need. I'll try and figure this out.
 
Hi,

OK I'm trying to modify the Multikey Keypad example.

With the code I came up with, If I press the 1st button I get a result. But If I press the 2nd button I only get a result if the 1st button is also pressed. So it's not working as desired.

I thought using if else statements in the switch would work, but it doesn't seem to work.

Any suggestions?

Here's the code

Code:
//4/26/20 trying to incorporate multi keypad


#include <Bounce.h>
#include <Adafruit_NeoPixel.h>
#include <Keypad.h>
#include <Wire.h> // wire library for LED matrix


const byte ROWS = 4; //four rows
const byte COLS = 4; //three columns
char keys[ROWS][COLS] = {
  {'1', '2', '3', '4'},
  {'5', '6', '7', '8'},
  {'9', 'a', 'b', 'c'},
  {'d', 'e', 'f', 'g'}
};

byte rowPins[ROWS] = {32, 31, 30, 29}; //teensy pins to connect to the row pinouts of the keypad
byte colPins[COLS] = {28, 27, 12, 11,}; //connect to the column pinouts of the keypad

//Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
Keypad kpd = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

unsigned long loopCount;
unsigned long startTime;
String msg;

const int channel = 1;
const int MIDIchannel = 1;   // this will only apply to midi channel 1


const int controllerD20 = 20; // toggle, control change 14
const int controllerD21 = 21; //  Button, control change 15
const int controllerD22 = 22; //
const int controllerD23 = 23;
const int controllerD24 = 24;  //
const int controllerD25 = 25;
const int controllerD26 = 26;
const int controllerD27 = 27;
const int controllerD28 = 28;
const int controllerD29 = 29;
const int controllerD30 = 30;
const int controllerD31 = 31;
const int controllerD32 = 32;
const int controllerD33 = 33;
const int controllerD34 = 34;
const int controllerD35 = 35;

Bounce button0 = Bounce(0, 5);
Bounce button1 = Bounce(1, 5);  // 5 = 5 ms debounce time
Bounce button2 = Bounce(2, 5);  // which is appropriate for good
Bounce button3 = Bounce(3, 5);  // quality mechanical pushbuttons
Bounce button4 = Bounce(4, 5);
Bounce button5 = Bounce(5, 5);  // if a button is too "sensitive"
Bounce button6 = Bounce(6, 5);  // to rapid touch, you can
Bounce button7 = Bounce(7, 5);  // increase this time.
Bounce button8 = Bounce(8, 5);
Bounce button9 = Bounce(9, 5);
Bounce button10 = Bounce(10, 5);
Bounce button11 = Bounce(11, 5);
Bounce button12 = Bounce(12, 5);  // goes out of order because other pins double as analog inputs

Bounce button24 = Bounce(24, 5);
Bounce button25 = Bounce(25, 5);
Bounce button26 = Bounce(26, 5);

void setup() {

  // pinMode(latch, OUTPUT);
  // digitalWrite(latch, LOW);
  // pinMode(clock, OUTPUT);
  // digitalWrite(clock, LOW);
  //  pinMode(data, OUTPUT);
  //  digitalWrite(data, LOW);

  Serial.begin(9600);
  loopCount = 0;
  startTime = millis();
  msg = "";




  //  keypad.addEventListener(keypadEvent); // Add an event listener for this keypad


}

void loop() {

  //  char key = keypad.getKey();



  loopCount++;
  if ( (millis() - startTime) > 5000 ) {
    //Serial.print("Average loops per second = ");
    // Serial.println(loopCount / 5);
    startTime = millis();
    loopCount = 0;
  }

  // Fills kpd.key[ ] array with up-to 10 active keys.
  // Returns true if there are ANY active keys.
  if (kpd.getKeys())
  {
    for (int i = 0; i < LIST_MAX; i++) // Scan the whole key list.
    {
      if ( kpd.key[i].stateChanged )   // Only find keys that have changed state.
      {
        switch (kpd.key[i].kstate) {  // Report active key state : IDLE, PRESSED, HOLD, or RELEASED
          case PRESSED:

            if (kpd.key[0].kstate == PRESSED) {
              usbMIDI.sendControlChange(controllerD20, 127, channel);
            }
          else  if (kpd.key[1].kstate == PRESSED) {
              usbMIDI.sendControlChange(controllerD21, 127, channel);
            }
         else   if (kpd.key[2].kstate == PRESSED) {
              usbMIDI.sendControlChange(controllerD22, 127, channel);
            }

            break;

          case HOLD:


            if (kpd.key[0].kstate == HOLD) {
              usbMIDI.sendControlChange(controllerD20, 127, channel);
            }
         else   if (kpd.key[1].kstate == HOLD) {
              usbMIDI.sendControlChange(controllerD21, 127, channel);
            }
         else   if (kpd.key[2].kstate == HOLD) {
              usbMIDI.sendControlChange(controllerD22, 127, channel);
            }

            break;
          case RELEASED:

            if (kpd.key[0].kstate == RELEASED) {
              usbMIDI.sendControlChange(controllerD20, 0, channel);
            }
        else    if (kpd.key[1].kstate == RELEASED) {
              usbMIDI.sendControlChange(controllerD21, 0, channel);
            }
       else     if (kpd.key[2].kstate == RELEASED) {
              usbMIDI.sendControlChange(controllerD22, 0, channel);
            }

        }

      }


    }
  }


  // MIDI Controllers should discard incoming MIDI messages.
  // http://forum.pjrc.com/threads/24179-Teensy-3-Ableton-Analog-CC-causes-midi-crash
  while (usbMIDI.read()) {
    // ignore incoming messages
  }

}
 
Code:
            if (kpd.key[0].kstate == PRESSED) {
              usbMIDI.sendControlChange(controllerD20, 127, channel);
            }
          else  if (kpd.key[1].kstate == PRESSED) {
              usbMIDI.sendControlChange(controllerD21, 127, channel);
            }
         else   if (kpd.key[2].kstate == PRESSED) {
              usbMIDI.sendControlChange(controllerD22, 127, channel);
            }

The problem here is that kpd.key[0].kstate is not the state of button '0'. It is the first button in the key[] array, which is not the same thing. In the MultiKey example, the actual button that has been pressed is determined by looking at kpd.key.kchar - so this might have a value of '2' if it relates to button 2.

You really need to use an index to handle the buttons, otherwise your code is going to get very unwieldy.
First get the button which has changed state:
Code:
      uint8_t btn = kpd.key[i].kchar;[code]
and now you can map this into a number from zero to fifteen:
[code]        uint8_t idx;
        // Map the character into an index from zero to fifteen
        if(btn >= '1' && btn <= '9') idx = btn - '1';
        else idx = btn - 'a' + 9;
[code]
That number can then be easily mapped into the corresponding controller number because you use sequential controller numbers starting at twenty. So the controller number corresponding to button at index idx is simply 20+idx. If the controller indices weren't sequential you could list them in an array and use that to map from the index to the controller number.

The if statement inside the for loop would become this:
[code]      if ( kpd.key[i].stateChanged ) { // Only find keys that have changed state.
        // get the character corresponding to this button
        uint8_t btn = kpd.key[i].kchar;
        uint8_t idx;
        // Map the character into an index from zero to fifteen
        if(btn >= '1' && btn <= '9') idx = btn - '1';
        else idx = btn - 'a' + 9;
        switch (kpd.key[i].kstate) {  // Report active key state : IDLE, PRESSED, HOLD, or RELEASED
        case PRESSED:
          usbMIDI.sendControlChange(idx+20, 127, channel);
          break;
    
        case HOLD:
          usbMIDI.sendControlChange(idx+20, 127, channel);
          break;
          
        case RELEASED:
          usbMIDI.sendControlChange(idx+20, 0, channel);
          break;
        }
      }

Pete
 
Thank you el_supremo / Pete,

I think I understand. At least the logic you explained makes sense. I'll try and express that in some code. My weaknesses in coding are arrays. And I just learned about switches, but that seems straight forward at least. I'll try and figure this out and post something.

Thank you again for your input.

Nick
 
Replace the if statement with the code I've posted in #9. It should work as-is - give it a try.

At the moment you don't need arrays.

Pete
 
Hey el_supremo,

I had to put this project down for a week as I had a lot of work, but just got back on it.

So I copied your if statement and put it into my code and it totally works!

Thank you for your help.

I do have a question however, as I want to understand what's happening here.

First of all, what is the uint8_t data type?

I googled it and it looks like an 8 bit number, going up to 255. Did you select this because we don't need a large range of number and this would save memory? Would an int also work in this case?

So kpd.key.kchar is changed into a number with : btn = kpd.key.kchar

and then we take the number of btn and move it into an index, and the index number gets sent out of :

usbMIDI.sendControlChange

If you didn't use this method, then I would have had to specify what each state of each button does right? Like what happens if button 1 is pressed, released, and held, and do that for each button (which would be a ton of code). Am I understanding this correctly?

Anyways thanks a bunch for the guidance. Now I'm going to incorporate this into the rest of my code.

take care, Nick
 
uint8_t is the same as "unsigned char". It can hold numbers in the range zero to 255 or it can hold a single character. The index of the array doesn't exceed 255 so I store the index in a uint8_t. Saves a bit of space but that may not be critical in your program.
The value of kpd.key.kchar can be a character from '1' to '9' or 'a' to 'g'. First, map the numbers '1' to '9' into the integers zero to 8. Also map the letters 'a' to 'g' into the integers from 9 to 15. Now that integer is a number from zero to 15 which we can turn into a controller number by simply adding 20 to it.
Calculating it this way means that you don't have to test if the key is '1' and send controllerD20, otherwise if it is '2' send controllerD21, otherwise if it is '3' etc.

Pete
 
Status
Not open for further replies.
Back
Top