/*
==== Task 7 - Electronic Music Box (Capstone) ====
Author: Roberto Palozzo
==================================================
*/
#include <Wire.h> // libreria per la comunicazione I2C
#include <Adafruit_GFX.h> // libreria grafica per l'OLED
#include <Adafruit_SSD1306.h> // libreria driver per il display OLED
#define SCREEN_WIDTH 128 // larghezza dell'OLED in pixel
#define SCREEN_HEIGHT 64 // altezza dell'OLED in pixel
const int buzzerPin = 4; // buzzer attivo, suona ogni nota
const int noteledPin = 5; // LED della nota (acceso mentre suona)
const int oledsdaPin = 8; // pin dati I2C dell'OLED
const int oledsclPin = 9; // pin clock I2C dell'OLED
const int rgbPin_R = 14; // RGB LED - canale rosso
const int rgbPin_B = 17; // RGB LED - canale blu
const int rgbPin_G = 18; // RGB LED - canale verde
const int NOTE_COUNT = 8; // numero totale di note nella melodia
int currentNote = 0; // globale: tiene traccia di quale nota sta suonando
// Melodia semplice - ogni array sotto è "allineato" per indice:
// melody[i], durations[i] e noteNames[i] descrivono tutti la STESSA nota i
int melody[NOTE_COUNT] = {
262, 294, 330, 349, 392, 440, 494, 523 // frequenza (Hz) di ogni nota
};
int durations[NOTE_COUNT] = {
400, 400, 400, 400, 400, 400, 400, 800 // quanto dura ogni nota (ms)
};
const char* noteNames[NOTE_COUNT] = {
"C", "D", "E", "F", "G", "A", "B", "High C" // nome mostrato sull'OLED per ogni nota
};
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1); // oggetto display OLED
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); // avvia l'I2C sui pin scelti
display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // inizializza l'OLED all'indirizzo I2C 0x3C
display.clearDisplay(); // pulisce il buffer del display
display.setTextColor(SSD1306_WHITE); // imposta il colore del testo
display.display(); // applica lo schermo vuoto iniziale
startMelody(); // avvia l'intro una sola volta, prima della canzone
}
// ===== Funzione SENZA parametri =====
// Mostra "Now Playing!" sull'OLED e fa ciclare brevemente
// l'RGB LED tra rosso, verde e blu prima che inizi la canzone.
void startMelody() {
display.clearDisplay();
display.setTextSize(2);
display.setCursor(0, 20);
display.println("Now Playing!"); // passo 1: mostra il messaggio di intro
display.display();
digitalWrite(rgbPin_R, HIGH); // passo 2: cicla tutti e tre i colori
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); // spegne tutto prima di uscire dalla funzione
}
// ===== Funzione CON parametri =====
// Suona una singola nota sul buzzer a "frequency" per "duration" ms,
// facendo lampeggiare il LED della nota per la stessa durata.
void playNote(int frequency, int duration) {
tone(buzzerPin, frequency); // inizia a suonare il tono
digitalWrite(noteledPin, HIGH); // accende il LED della nota
delay(duration); // mantiene tono/LED accesi per "duration" ms
noTone(buzzerPin); // ferma il tono
digitalWrite(noteledPin, LOW); // spegne il LED della nota
}
// ===== Funzione CON valore di ritorno (senza parametri) =====
// Cerca quanto deve durare la nota ATTUALE (indicata da currentNote),
// leggendo il valore corrispondente dall'array durations[].
int getNoteDuration() {
return durations[currentNote];
}
void loop() {
// Suona tutta la melodia, una nota per ogni giro del ciclo
for (int noteCount = 0; noteCount < NOTE_COUNT; noteCount++) {
int duration = getNoteDuration(); // durata della nota attuale
// ---- aggiorna l'OLED con il nome della nota attuale ----
display.clearDisplay();
display.setTextSize(2);
display.setCursor(0, 20);
display.println(noteNames[currentNote]); // mostra il nome della nota (es. "C", "D"...)
display.display();
// ---- cambia colore dell'RGB ad ogni nota (cicla R -> G -> B) ----
// "% 3" restituisce un resto di 0, 1 o 2, quindi il colore ruota
// tra tutti e tre i canali man mano che currentNote aumenta
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); // suona la frequenza della nota per la sua durata
currentNote++; // passa alla nota successiva
}
currentNote = 0; // resetta, così la melodia ricomincia dall'inizio
}