/*
==== Task 7 - Electronic Music Box (Capstone) ====
Author: Roberto Palozzo
==================================================
*/
#include <Wire.h> // I2C communication library
#include <Adafruit_GFX.h> // graphics library for the OLED
#include <Adafruit_SSD1306.h> // driver library for the OLED display
#define SCREEN_WIDTH 128 // OLED width in pixels
#define SCREEN_HEIGHT 64 // OLED height in pixels
const int buzzerPin = 4; // active buzzer, plays each note
const int noteledPin = 5; // note LED (lit while a note is playing)
const int oledsdaPin = 8; // OLED I2C data pin
const int oledsclPin = 9; // OLED I2C clock pin
const int rgbPin_R = 14; // RGB LED - red channel
const int rgbPin_B = 17; // RGB LED - blue channel
const int rgbPin_G = 18; // RGB LED - green channel
const int NOTE_COUNT = 8; // total number of notes in the melody
int currentNote = 0; // global: tracks which note is currently playing
// Simple melody - each array below is "aligned" by index:
// melody[i], durations[i] and noteNames[i] all describe the SAME note i
int melody[NOTE_COUNT] = {
262, 294, 330, 349, 392, 440, 494, 523 // frequency (Hz) of each note
};
int durations[NOTE_COUNT] = {
400, 400, 400, 400, 400, 400, 400, 800 // how long each note should play (ms)
};
const char* noteNames[NOTE_COUNT] = {
"C", "D", "E", "F", "G", "A", "B", "High C" // name shown on the OLED for each note
};
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1); // OLED display object
void setup() {
Serial.begin(115200);
Serial.println("Hello, ESP32-S3!");
pinMode(buzzerPin, OUTPUT);
pinMode(noteledPin, OUTPUT);
pinMode(rgbPin_R, OUTPUT);
pinMode(rgbPin_B, OUTPUT);
pinMode(rgbPin_G, OUTPUT);
Wire.begin(oledsdaPin, oledsclPin); // start I2C on custom pins
display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // initialize OLED at I2C address 0x3C
display.clearDisplay(); // clear display buffer
display.setTextColor(SSD1306_WHITE); // set text color
display.display(); // apply initial blank screen
startMelody(); // run the intro once, before the song starts
}
// ===== Function WITHOUT parameters =====
// Shows a "Now Playing!" message on the OLED and briefly cycles
// the RGB LED through red, green and blue before the song begins.
void startMelody() {
display.clearDisplay();
display.setTextSize(2);
display.setCursor(0, 20);
display.println("Now Playing!"); // step 1: show the intro message
display.display();
digitalWrite(rgbPin_R, HIGH); // step 2: cycle through all three colours
delay(200);
digitalWrite(rgbPin_R, LOW);
digitalWrite(rgbPin_G, HIGH);
delay(200);
digitalWrite(rgbPin_G, LOW);
digitalWrite(rgbPin_B, HIGH);
delay(200);
digitalWrite(rgbPin_B, LOW); // turn everything off before returning
}
// ===== Function WITH parameters =====
// Plays a single note on the buzzer at "frequency" for "duration" ms,
// flashing the note LED for the same length of time.
void playNote(int frequency, int duration) {
tone(buzzerPin, frequency); // start playing the tone
digitalWrite(noteledPin, HIGH); // turn on the note LED
delay(duration); // keep the tone/LED on for "duration" ms
noTone(buzzerPin); // stop the tone
digitalWrite(noteledPin, LOW); // turn off the note LED
}
// ===== Function WITH a return value (no parameters) =====
// Looks up how long the CURRENT note (given by currentNote) should last,
// by reading the matching value from the durations[] array.
int getNoteDuration() {
return durations[currentNote];
}
void loop() {
// Play through the whole melody, one note per iteration
for (int noteCount = 0; noteCount < NOTE_COUNT; noteCount++) {
int duration = getNoteDuration(); // duration of the current note
// ---- update the OLED with the current note's name ----
display.clearDisplay();
display.setTextSize(2);
display.setCursor(0, 20);
display.println(noteNames[currentNote]); // show the note name (e.g. "C", "D"...)
display.display();
// ---- change the RGB LED colour every note (cycles R -> G -> B) ----
// "% 3" gives a remainder of 0, 1 or 2, so the colour rotates through
// all three channels as currentNote increases
if (currentNote % 3 == 0) {
digitalWrite(rgbPin_R, HIGH);
digitalWrite(rgbPin_G, LOW);
digitalWrite(rgbPin_B, LOW);
} else if (currentNote % 3 == 1) {
digitalWrite(rgbPin_R, LOW);
digitalWrite(rgbPin_G, HIGH);
digitalWrite(rgbPin_B, LOW);
} else {
digitalWrite(rgbPin_R, LOW);
digitalWrite(rgbPin_G, LOW);
digitalWrite(rgbPin_B, HIGH);
}
playNote(melody[currentNote], duration); // play the note's frequency for its duration
currentNote++; // move on to the next note
}
currentNote = 0; // reset so the melody restarts from the beginning
}