#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <math.h>
// === OLED Setup ===
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
// === Speaker Pin ===
#define SPEAKER_PIN 13
// === Matrix Setup ===
const uint8_t rowPins[5] = {A0, A1, A2, A3, A4}; // Octaves
const uint8_t colPins[8] = {2, 3, 4, 5, 6, 7, 8, 9}; // Notes
// Note names for MIDI
const char* noteNames[] = {
"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"
};
// Convert MIDI note to frequency
float midiToFreq(int midiNote) {
return 440.0 * pow(2.0, (midiNote - 69) / 12.0);
}
void setup() {
// Row (octave) outputs
for (uint8_t i = 0; i < 5; i++) {
pinMode(rowPins[i], OUTPUT);
digitalWrite(rowPins[i], HIGH); // Inactive
}
// Column (note) inputs with pullups
for (uint8_t j = 0; j < 8; j++) {
pinMode(colPins[j], INPUT_PULLUP);
}
pinMode(SPEAKER_PIN, OUTPUT);
// OLED init
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
while (true); // OLED failed
}
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
}
void showNote(int row, int col, int midiNote) {
int noteIndex = midiNote % 12;
int octave = (midiNote / 12) - 1;
display.clearDisplay();
display.setCursor(0, 0);
display.print("Note: ");
display.print(noteNames[noteIndex]);
display.println(octave);
display.print("MIDI: ");
display.println(midiNote);
display.print("Row: ");
display.println(row + 1);
display.print("Col: ");
display.println(col + 1);
display.display();
}
void loop() {
bool keyPressed = false;
for (uint8_t row = 0; row < 5; row++) {
digitalWrite(rowPins[row], LOW); // Enable row
for (uint8_t col = 0; col < 8; col++) {
if (digitalRead(colPins[col]) == LOW) {
int baseNote = 60; // Middle C
int midiNote = baseNote + col + (row * 12);
float freq = midiToFreq(midiNote);
tone(SPEAKER_PIN, freq);
showNote(row, col, midiNote);
keyPressed = true;
delay(100); // debounce and sustain
break; // only one note at a time
}
}
digitalWrite(rowPins[row], HIGH); // Disable row
if (keyPressed) break;
}
if (!keyPressed) {
noTone(SPEAKER_PIN);
display.clearDisplay();
display.setCursor(0, 0);
display.println("No key pressed");
display.display();
}
delay(50);
}