/*
Forum:
Wokwi: https://wokwi.com/projects/450406372733697025
Midi notes: C0 = 24, C0# = 25, ... , C5 = 84
*/
constexpr unsigned long debounceTime {30};
constexpr int LOWESTNOTE {24}; // C0 = 24
constexpr char noteNames[] = "C C#D D#E F F#G G#A A#B ";
//Keyboard Matrix
int keycol[] = {7, 6, 5, 4, 3, 2 }; // (C to F) and (F# to B)
int keyrow[] = {53, 51, 49, 47}; // Octave 0 (C-F) , 0 (F#-B), Octave 1 (C-F), 1 (F#-B),...
int col_scan;
int last_scan = -1;
constexpr int noOfRows = sizeof(keyrow) / sizeof(keyrow[0]);
constexpr int noOfColumns = sizeof(keycol) / sizeof(keycol[0]);
constexpr int noOfKeys = noOfRows * noOfColumns;
enum class KeyMode {UNCHANGED, PRESSED, RELEASED};
struct KeyClass {
byte state = HIGH;
byte lastState = HIGH;
unsigned long lastChange = 0;
KeyMode mode = KeyMode::UNCHANGED;
boolean keyChanged(byte actState){
if (actState != lastState){
lastState = actState;
lastChange = millis();
}
if (state != lastState && millis()-lastChange > debounceTime){
state = lastState;
mode = state ? KeyMode::RELEASED : KeyMode::PRESSED;
return true;
}
return false;
};
};
KeyClass keyMatrix[noOfKeys];
void setup()
{
Serial.begin(115200);
Serial1.begin(31250);
for (int i = 0; i < noOfRows; i++){
digitalWrite(keyrow[i], HIGH);
pinMode(keyrow[i], OUTPUT);
}
for (int i = 0; i < noOfColumns; i++){
pinMode(keycol[i], INPUT_PULLUP);
}
}
void loop()
{
checkKeys();
}
void checkKeys() {
for (int i = 0; i < noOfRows; i++){
digitalWrite(keyrow[i], LOW);
for (int j = 0; j < noOfColumns; j++) {
col_scan = digitalRead(keycol[j]);
int keyNo = i * noOfColumns + j;
if (keyMatrix[keyNo].keyChanged(col_scan)) handleKey(keyNo);
}
digitalWrite(keyrow[i], HIGH);
}
}
void handleKey(int kNote){
switch (keyMatrix[kNote].mode){
case KeyMode::PRESSED:
noteOn(kNote+LOWESTNOTE);
break;
case KeyMode::RELEASED:
noteOff(kNote+LOWESTNOTE);
break;
}
}
void sendNote(int cmd, int pitch, int velocity) {
Serial1.write(cmd);
Serial1.write(pitch);
Serial1.write(velocity);
Serial.print("Send Note");
Serial.print(velocity > 0 ? "On " : "Off ");
Serial.print(pitch);
printNote(pitch-LOWESTNOTE);
Serial.println();
}
void noteOn(int pitch){
sendNote(0x90,pitch,0x45);
}
void noteOff(int pitch){
sendNote(0x90,pitch,0x00);
}
void printNote(int key){
byte note = key % 12;
byte octave = key/12;
Serial.print('\t');
Serial.print(noteNames[note*2]);
char c = noteNames[note*2+1];
if (c > ' ') Serial.print(c);
Serial.print(octave);
}F
E
D#
D
C#
C
B
A#
A
G#
G
F#
F
E
D#
D
C#
C
B
A#
A
G#
G
F#
Octave 1
Octave 0