Converting a 37 key toy keyboard to a MIDI keyboard.

I saw some videos on youtube about converting toy keyboards to MIDI keyboard. I had a 37 key toy keyboard lying around, so I decided to make one too. After opening the keyboard, I found that the keys are multiplexed into a 5x8 (row x column) matrix. So I wrote a code which scans the rows one by one and save the number of the current row and the state of the columns to a 2D array. But I can’t understand how can I calculate the note number from the row and column number. Can anybody help me regarding this matter?

int numRow = 5, numCol = 8;
int columnPins [] = {2, 3, 4, 5, 6, 7, 9, 10};

int rowPins [] = {A0, A1, A2, A3, A4};

boolean keyState [5] [8];

void setup() {

  for (int i = 2; i <= 10; i++) {
    pinMode (i, OUTPUT);
  }
  Serial.begin(9600);

}

void loop() {
  int scanRow = 0;
  int scanColumn = 0;
  rowEnable(scanRow);
  for (int rowPin = 0; rowPin < numRow; rowPin++) {
    rowDisableAll();
    digitalWrite(rowPins[rowPin], HIGH);
    for (int colPin = 0; colPin < numCol; colPin++) {
      keyState [rowPin] [colPin] = digitalRead (columnPins [colPin]);
    }
  }
  /*for (int rp=0; rp<numRow; rp++){

    for( int cp = 0; cp<numCol; cp++){
      if (keyState [rowPin] [colPin]){
         noteOn(
        }


      }
    }



  */




}
void noteOn() {}
void noteOff() {}
void rowDisableAll() {
  digitalWrite (A0, LOW);
  digitalWrite (A1, LOW);
  digitalWrite (A2, LOW);
  digitalWrite (A3, LOW);
  digitalWrite (A4, LOW);

}
void rowEnable(int rowNumber) {
  rowDisableAll();
  digitalWrite (rowNumber, HIGH);

}

Why not use the Keypad library, with 5 rows and 8 columns? Let it handle all the work of determining which key(s) are pressed?

You could make a two-dimensional array of note numbers to map the row and column to note number.

boolean keyState [5] [8];
byte NoteNumbers[5][8] = {[color=#222222]
[/color]
   {1, 2, 3, 4, 5},
   {6, 7, 8, 9, 10),
...
   {36, 37, 38, 39, 40}
};

PaulS:
Why not use the Keypad library, with 5 rows and 8 columns? Let it handle all the work of determining which key(s) are pressed?

I've already tried that, works fine, but the problem is it can't detect more than one key press at a time. Multiple buttons are pressed for playing chords. Is there any way I can use the keypad library to detect more than key pressed at a time?

Is there any way I can use the keypad library to detect more than key pressed at a time?

The latest version does allow for multiple keys being pressed at the same time.

Note that although every example shows keypad keys being mapped to ascii characters you can map to any byte value other than 0. That means you can map directly to MIDI note numbers. Just put numbers in the keymap instead of the character constants like '0', '1', '2', 'A'...

You can shift octaves by adding or subtracting multiples of 12.

PaulS:
The latest version does allow for multiple keys being pressed at the same time.

Oh, I just found out I was using an old version of keypad library. I’ve downloaded the latest version, and it’s working good now.
But, I’m still facing some problems. Some of the buttons aren’t working. I pressed them, but didn’t get any output in the serial monitor. There are approx. 10 buttons like that as far as I remember. How can I fix it?
Here’s the code I’m using -

/* @file MultiKey.ino
|| @version 1.0
|| @author Mark Stanley
|| @contact mstanley@technologist.com
||
|| @description
|| | The latest version, 3.0, of the keypad library supports up to 10
|| | active keys all being pressed at the same time. This sketch is an
|| | example of how you can get multiple key presses from a keypad or
|| | keyboard.
|| #
*/

#include <Keypad.h>

const byte ROWS = 5; //four rows
const byte COLS = 8; //three columns
char keys[ROWS][COLS] = {
{'a','b','c','d','e','f','g','h'},
{'i','j','k','l','m','n','o','p'},
{'q','r','s','t','u','v','w','x'},
{'y','z','1','2','3','4','5','6'},
{'A','B','C','D','E','F','G','H'},

};
byte rowPins[ROWS] = {8,9,10,11,12}; //connect to the row pinouts of the kpd
byte colPins[COLS] = {A0,A1,A2,A3,A4,A5,A6,A7}; //connect to the column pinouts of the kpd

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

unsigned long loopCount;
unsigned long startTime;
String msg;


void setup() {
   Serial.begin(9600);
   loopCount = 0;
   startTime = millis();
   msg = "";
}


void loop() {
   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:
                   msg = " PRESSED.";
               break;
                 
                   case RELEASED:
                   msg = " RELEASED.";
               ;
                  
               }
               Serial.print("Key ");
               Serial.print(kpd.key[i].kchar);
               Serial.println(msg);
           }
       }
   }
}  // End loop

Okay, fixed that problem. I was using an Arduino Nano and I had connected the column pins to A0-A7, which might caused the problem. Now I have connected the row pins to A0-A4, and the column pins to D5-D12. Now most of the keys are working, but the last 5 keys are not working now. Anybody have any clue why is this happening? Is using analog pin a bad idea? Or some bug in my code causing this problem?

UPDATE - Solved it, a jumper wire was loose, that's why one of the column pins wasn't connected to the arduino. Now everything working fine. Thank you so much everyone! :smiley:

Shayon:
I was using an Arduino Nano and I had connected the column pins to A0-A7, which might caused the problem.

One strange thing about the SMD version of the ATmega328P: They added two more inputs to the A/D multiplexer but didn’t add new digital pins for them. That means A6 and A7 can only be used for analog input, not for digital I/O.