// Include the Multi_Tone library to support simultaneous tones using multiple timers
#include "Multi_Tone.h"
// Create two tone objects for polyphonic playback (bass and tenor voices)
Tone tone1;
Tone tone2;
// Set the playback speed of the song, smaller value = faster playback
int tempo = 100;
// Pin assignments for RGB LEDs representing the tenor voice
const int tenor_red = 4;
const int tenor_green = 3;
const int tenor_blue = 2;
// Pin assignments for RGB LEDs representing the bass voice
const int bass_red = 7;
const int bass_green = 6;
const int bass_blue = 5;
// Data structure to map a note to an RGB color
struct NoteColor {
int note; // Frequency constant from tone library (e.g., NOTE_C4)
int r, g, b; // Red, green, and blue intensity values (0–255)
};
// Lookup table mapping tenor notes to colors
NoteColor tenorNoteColors[] = {
{NOTE_A4, 255, 0, 0},
{NOTE_B3, 255, 32, 0},
{NOTE_B4, 255, 255, 0},
{NOTE_C4, 0, 255, 0},
{NOTE_C5, 0, 255, 32},
{NOTE_CS4, 0, 255, 255},
{NOTE_D4, 0, 0, 255},
{NOTE_E4, 32, 0, 255},
{NOTE_F4, 255, 0, 255},
{NOTE_G4, 255, 255, 32},
{NOTE_GS4, 32, 255, 255},
{NOTE_R, 255, 255, 255} // white light for rests
};
// Lookup table mapping bass notes to colors
NoteColor bassNoteColors[] = {
{NOTE_A2, 255, 0, 0},
{NOTE_D3, 255, 32, 0},
{NOTE_G2, 255, 255, 0},
{NOTE_C3, 0, 255, 0},
{NOTE_B2, 0, 255, 32},
{NOTE_F2, 0, 255, 255},
{NOTE_F3, 0, 0, 255},
{NOTE_E3, 32, 0, 255},
{NOTE_GS2, 255, 0, 255},
{NOTE_AS2, 255, 255, 32},
{NOTE_G3, 32, 255, 255},
{NOTE_FS3, 255, 32, 255},
{NOTE_A3, 255, 255, 255},
{NOTE_GS3, 32, 32, 255}
};
// Automatically determine size of lookup tables
const int numTenorNotes = sizeof(tenorNoteColors) / sizeof(tenorNoteColors[0]);
const int numBassNotes = sizeof(bassNoteColors) / sizeof(bassNoteColors[0]);
// Function to set RGB color for tenor note
void setTenorColor(int note) {
for (int i = 0; i < numTenorNotes; i++) {
if (tenorNoteColors[i].note == note) {
analogWrite(tenor_red, tenorNoteColors[i].r);
analogWrite(tenor_green, tenorNoteColors[i].g);
analogWrite(tenor_blue, tenorNoteColors[i].b);
return;
}
}
// If note not found, turn off LED
analogWrite(tenor_red, 0);
analogWrite(tenor_green, 0);
analogWrite(tenor_blue, 0);
}
// Function to set RGB color for bass note
void setBassColor(int note) {
for (int i = 0; i < numBassNotes; i++) {
if (bassNoteColors[i].note == note) {
analogWrite(bass_red, bassNoteColors[i].r);
analogWrite(bass_green, bassNoteColors[i].g);
analogWrite(bass_blue, bassNoteColors[i].b);
return;
}
}
// If note not found, turn off LED
analogWrite(bass_red, 0);
analogWrite(bass_green, 0);
analogWrite(bass_blue, 0);
}
// Sequences of notes for bass and tenor voices
// These arrays must be the same length
int bass[] = {NOTE_A2, NOTE_A2, NOTE_A2, NOTE_A2, NOTE_A2, NOTE_A2, NOTE_A2, NOTE_A2, NOTE_D3, NOTE_D3, NOTE_D3, NOTE_D3, NOTE_D3, NOTE_D3, NOTE_D3, NOTE_D3, NOTE_G2, NOTE_G2, NOTE_G2, NOTE_G2, NOTE_G2, NOTE_G2, NOTE_G2, NOTE_G2, NOTE_C3, NOTE_C3, NOTE_C3, NOTE_B2, NOTE_A2, NOTE_A2, NOTE_G2, NOTE_G2, NOTE_F2, NOTE_F2, NOTE_F2, NOTE_F2, NOTE_C3, NOTE_C3, NOTE_C3, NOTE_C3, NOTE_B2, NOTE_B2, NOTE_B2, NOTE_C3, NOTE_D3, NOTE_D3, NOTE_F3, NOTE_F3, NOTE_E3, NOTE_E3, NOTE_E3, NOTE_E3, NOTE_GS2, NOTE_GS2, NOTE_GS2, NOTE_GS2, NOTE_A2, NOTE_A2, NOTE_A2, NOTE_AS2, NOTE_AS2, NOTE_AS2, NOTE_AS2, NOTE_AS2, NOTE_F3, NOTE_F3, NOTE_F3, NOTE_F3, NOTE_F3, NOTE_F3, NOTE_A2, NOTE_A2, NOTE_G2, NOTE_G2, NOTE_F3, NOTE_F3, NOTE_F3, NOTE_F3, NOTE_F3, NOTE_F3, NOTE_G3, NOTE_G3, NOTE_G3, NOTE_G3, NOTE_FS3, NOTE_FS3, NOTE_FS3, NOTE_FS3, NOTE_F3, NOTE_F3, NOTE_F3, NOTE_F3, NOTE_G3, NOTE_G3, NOTE_G3, NOTE_G3, NOTE_F3, NOTE_F3, NOTE_F3, NOTE_D3, NOTE_D3, NOTE_D3, NOTE_A2, NOTE_A2, NOTE_G2, NOTE_G2, NOTE_F3, NOTE_F3, NOTE_F3, NOTE_F3, NOTE_F3, NOTE_F3, NOTE_A3, NOTE_A3, NOTE_A3, NOTE_G3, NOTE_G3, NOTE_G3, NOTE_C3, NOTE_C3, NOTE_A3, NOTE_A3, NOTE_A3, NOTE_GS3, NOTE_GS3, NOTE_GS3, NOTE_GS3};
int tenor[] = {NOTE_C5, NOTE_C5, NOTE_B4, NOTE_B4, NOTE_A4, NOTE_G4, NOTE_G4, NOTE_G4, NOTE_F4, NOTE_F4, NOTE_F4, NOTE_G4, NOTE_A4, NOTE_A4, NOTE_C5, NOTE_C5, NOTE_B4, NOTE_B4, NOTE_A4, NOTE_A4, NOTE_G4, NOTE_F4, NOTE_F4, NOTE_F4, NOTE_E4, NOTE_E4, NOTE_E4, NOTE_E4, NOTE_E4, NOTE_E4, NOTE_E4, NOTE_E4, NOTE_A4, NOTE_A4, NOTE_G4, NOTE_G4, NOTE_F4, NOTE_E4, NOTE_E4, NOTE_E4, NOTE_D4, NOTE_D4, NOTE_D4, NOTE_E4, NOTE_F4, NOTE_F4, NOTE_A4, NOTE_A4, NOTE_GS4, NOTE_GS4, NOTE_F4, NOTE_F4, NOTE_E4, NOTE_D4, NOTE_D4, NOTE_D4, NOTE_C4, NOTE_B3, NOTE_C4, NOTE_CS4, NOTE_CS4, NOTE_CS4, NOTE_CS4, NOTE_CS4, NOTE_D4, NOTE_A4, NOTE_A4, NOTE_A4, NOTE_A4, NOTE_A4, NOTE_A4, NOTE_A4, NOTE_A4, NOTE_A4, NOTE_C5, NOTE_C5, NOTE_C5, NOTE_C5, NOTE_B4, NOTE_B4, NOTE_G4, NOTE_G4, NOTE_G4, NOTE_G4, NOTE_G4, NOTE_G4, NOTE_G4, NOTE_G4, NOTE_G4, NOTE_G4, NOTE_G4, NOTE_G4, NOTE_CS4, NOTE_CS4, NOTE_B3, NOTE_B3, NOTE_C4, NOTE_F4, NOTE_F4, NOTE_F4, NOTE_F4, NOTE_F4, NOTE_F4, NOTE_R, NOTE_R, NOTE_R, NOTE_A4, NOTE_A4, NOTE_A4, NOTE_A4, NOTE_G4, NOTE_G4, NOTE_F4, NOTE_F4, NOTE_F4, NOTE_E4, NOTE_E4, NOTE_E4, NOTE_E4, NOTE_E4, NOTE_D4, NOTE_D4, NOTE_D4, NOTE_E4, NOTE_E4, NOTE_E4, NOTE_E4};
void setup() {
// Initialize tone output pins
tone1.begin(13); // Bass speaker pin
tone2.begin(12); // Tenor speaker pin
// Configure RGB LED pins as output
pinMode(tenor_red, OUTPUT);
pinMode(tenor_green, OUTPUT);
pinMode(tenor_blue, OUTPUT);
pinMode(bass_red, OUTPUT);
pinMode(bass_green, OUTPUT);
pinMode(bass_blue, OUTPUT);
// Track previous note to avoid unnecessary re-triggers
int previousBassNote = -1;
int previousTenorNote = -1;
// Get number of notes to play
int length = sizeof(bass) / sizeof(bass[0]);
// Main loop to play note sequences
for (int count = 0; count < length; count++) {
int currentBass = bass[count];
int currentTenor = tenor[count];
// Only play bass note if different from previous
if (currentBass != previousBassNote) {
if (currentBass == NOTE_R) {
tone1.stop();
} else {
tone1.play(currentBass);
}
setBassColor(currentBass);
previousBassNote = currentBass;
}
// Only play tenor note if different from previous
if (currentTenor != previousTenorNote) {
if (currentTenor == NOTE_R) {
tone2.stop();
} else {
tone2.play(currentTenor);
}
setTenorColor(currentTenor);
previousTenorNote = currentTenor;
}
// Delay between notes (note duration control)
delay(tempo);
}
// Stop all tones after melody ends
tone1.stop();
tone2.stop();
}
void loop() {
// No repeating loop needed; song plays once on power-up
}