/*
Forum: https://forum.arduino.cc/t/midi-interface-help/1418834
Wokwi: https://wokwi.com/projects/450429364341969921
2025/12/15
ec2021
Midi notes: C0 = 24, C0# = 25, ... , C5 = 84
*/
#define DEBUG
constexpr unsigned long debounceTime{ 30 };
constexpr int LOWEST_NOTE{ 24 }; // C0 = 24
constexpr char noteNames[] = "C C#D D#E F F#G G#A A#B ";
void printNote(byte midiNote) {
byte key = (midiNote - LOWEST_NOTE) % 12;
byte octave = (midiNote - LOWEST_NOTE) / 12;
Serial.print(noteNames[key * 2]);
char c = noteNames[key * 2 + 1];
if (c > ' ') Serial.print(c);
Serial.print(octave);
}
//Keyboard Matrix
int keycol[] = { 7, 6, 5, 4, 3, 2 }; // (C to F) and (F# to B)
int keyrow[] = { 53, 51, 49, 47, 45, 43 }; // Octave 0 (C-F) , 0 (F#-B), Octave 1 (C-F), 1 (F#-B),...
int col_scan;
constexpr int noOfRows = sizeof(keyrow) / sizeof(keyrow[0]);
constexpr int noOfColumns = sizeof(keycol) / sizeof(keycol[0]);
constexpr int noOfKeys = noOfRows * noOfColumns;
void sendNote(byte note, byte velocity) {
Serial1.write(0x90);
Serial1.write(note);
Serial1.write(velocity);
#ifdef DEBUG
Serial.print("\nSend Note ");
Serial.print(velocity > 0 ? "ON " : "OFF ");
printNote(note);
#endif
};
class KeyClass {
private:
byte state = HIGH;
byte lastState = HIGH;
unsigned long lastChange = 0;
byte _midiNote = 0;
void (* _sendNote)(byte, byte) = &sendNote;
void _sendOff() {
_sendNote(_midiNote, 0x00);
}
void _sendOn() {
_sendNote(_midiNote, 0x45);
}
public:
void setMidiNote(byte note) {
_midiNote = note;
}
void checkKey(byte actState) {
if (actState != lastState) {
lastState = actState;
lastChange = millis();
}
if (state != lastState && millis() - lastChange > debounceTime) {
state = lastState;
if (state) {
_sendOff(); //noteOff
} else {
_sendOn(); // noteOn
}
}
};
};
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);
}
for (int i = 0; i < noOfKeys; i++) {
keyMatrix[i].setMidiNote(i + LOWEST_NOTE);
}
}
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;
keyMatrix[keyNo].checkKey(col_scan);
}
digitalWrite(keyrow[i], HIGH);
}
}
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
F
E
D#
D
C#
C
B
A#
A
G#
G
F#
Octave 2