// Arduino Music Player
// By: Daniel Gottfried
// Date: 08/05/2024
// Include Libraries and Information
#include "pitches.h"
#include "songs.h"
// Pin Definitions:
const byte dataPinOut = 5; // DS
const byte latchPinOut = 6; // STCP
const byte clockPinOut = 7; // SHCP
const byte buzzerPin = 8; // Buzzer Output
const byte playButtonPin = 9; // Play Button
const byte stopButtonPin = 2; // Stop Button
const byte cycleButtonPin = 11; // Cycle Songs Button
// Constant Definitions:
const byte numLeds = 5; // Number of LEDs (attached to shift register)
const byte numBits = 8; // Number of shift register pins (outputs for the LEDs)
const byte playLedIndex = 0; // Array index in "ledDataArray" for the Play LED
const byte s3LedIndex = 1; // Array index in "ledDataArray" for the the #3 song indicator LED (value of 4) (left most LED)
const byte s2LedIndex = 2; // Array index in "ledDataArray" for the the #2 song indicator LED (value of 2)
const byte s1LedIndex = 3; // Array index in "ledDataArray" for the the #1 song indicator LED (value of 1) (right most LED)
const byte powerLedIndex = 7; // Array index in "ledDataArray" for the Power LED
const long cycleDelTime = 500; // delay time for cycling songs
const float noteSeparation = 0.2; // Amount of the note's durration to use as separation
// Variable Definitions:
bool ledDataArray[numBits]; // Array containing output data for the shift register
// bool playLedState = LOW; // State for Play LED
// bool powerLedState = LOW; // State for Power LED
bool playState = false; // Playing State (is a song being played)
byte songSelection = 0; // Current Song Selection
unsigned long noteCounter = 0; // Keeps track of the current note number
int tempoCounter = 0; // Keeps track of the current tempo number
void setup() {
// Set Pinmodes:
pinMode(dataPinOut, OUTPUT);
pinMode(latchPinOut, OUTPUT);
pinMode(clockPinOut, OUTPUT);
pinMode(buzzerPin, OUTPUT);
pinMode(playButtonPin, INPUT_PULLUP);
pinMode(stopButtonPin, INPUT_PULLUP);
pinMode(cycleButtonPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(stopButtonPin), stopPlayingISR, FALLING);
// Set ledDataArray to LOW:
for (int i=0; i<numBits; i++) {
ledDataArray[i] = LOW;
}
// Clear and Write to Output Registers:
writeRegistersOut(ledDataArray, numBits);
// Turn on Power Indicating LED:
ledDataArray[powerLedIndex] = HIGH;
writeRegistersOut(ledDataArray, numBits);
// Start Serial Monitor Communication for Debugging:
Serial.begin(115200);
Serial.println(sizeof(noteArray2) / sizeof(int));
Serial.println(sizeof(durrationArray2) / sizeof(float));
}
void loop() {
// put your main code here, to run repeatedly:
cycleSongs();
startPlaying();
// Serial.println((1/float(tempoArray0[0][tempoCounter])));
switch (songSelection) {
case 0:
if ((playState == true) && (noteCounter < (sizeof(noteArray0) / sizeof(int)))) {
if (noteCounter >= tempoArray0[1][tempoCounter]) {
tempoCounter = tempoCounter + 1;
}
Serial.println(noteCounter);
unsigned long noteLength = ((1/float(tempoArray0[0][tempoCounter]))*(240000))/durrationArray0[noteCounter];
Serial.println(noteLength);
tone(buzzerPin, noteArray0[noteCounter], (1-noteSeparation) * noteLength);
delay(noteLength);
noTone(buzzerPin);
noteCounter = noteCounter + 1;
}
if ((playState == true) && (noteCounter >= (sizeof(noteArray0) / sizeof(int)))) {
stopPlayingISR();
}
break;
case 1:
if ((playState == true) && (noteCounter < (sizeof(noteArray1) / sizeof(int)))) {
if (noteCounter >= tempoArray1[1][tempoCounter]) {
tempoCounter = tempoCounter + 1;
}
Serial.println(noteCounter);
unsigned long noteLength = ((1/float(tempoArray1[0][tempoCounter]))*(240000))/durrationArray1[noteCounter];
Serial.println(noteLength);
tone(buzzerPin, noteArray1[noteCounter], (1-noteSeparation) * noteLength);
delay(noteLength);
noTone(buzzerPin);
noteCounter = noteCounter + 1;
}
if ((playState == true) && (noteCounter >= (sizeof(noteArray1) / sizeof(int)))) {
stopPlayingISR();
}
break;
case 2:
if ((playState == true) && (noteCounter < (sizeof(noteArray2) / sizeof(int)))) {
if (noteCounter >= tempoArray2[1][tempoCounter]) {
tempoCounter = tempoCounter + 1;
}
Serial.println(noteCounter);
unsigned long noteLength = ((1/float(tempoArray2[0][tempoCounter]))*(240000))/durrationArray2[noteCounter];
Serial.println(noteLength);
tone(buzzerPin, noteArray2[noteCounter], (1-noteSeparation) * noteLength);
delay(noteLength);
noTone(buzzerPin);
noteCounter = noteCounter + 1;
}
if ((playState == true) && (noteCounter >= (sizeof(noteArray2) / sizeof(int)))) {
stopPlayingISR();
}
break;
case 3:
if ((playState == true) && (noteCounter < (sizeof(noteArray3) / sizeof(int)))) {
if (noteCounter >= tempoArray3[1][tempoCounter]) {
tempoCounter = tempoCounter + 1;
}
Serial.println(noteCounter);
unsigned long noteLength = ((1/float(tempoArray3[0][tempoCounter]))*(240000))/durrationArray3[noteCounter];
Serial.println(noteLength);
tone(buzzerPin, noteArray3[noteCounter], (1-noteSeparation) * noteLength);
delay(noteLength);
noTone(buzzerPin);
noteCounter = noteCounter + 1;
}
if ((playState == true) && (noteCounter >= (sizeof(noteArray3) / sizeof(int)))) {
stopPlayingISR();
}
break;
case 4:
if ((playState == true) && (noteCounter < (sizeof(noteArray4) / sizeof(int)))) {
if (noteCounter >= tempoArray4[1][tempoCounter]) {
tempoCounter = tempoCounter + 1;
}
Serial.println(noteCounter);
unsigned long noteLength = ((1/float(tempoArray4[0][tempoCounter]))*(240000))/durrationArray4[noteCounter];
Serial.println(noteLength);
tone(buzzerPin, noteArray4[noteCounter], (1-noteSeparation) * noteLength);
delay(noteLength);
noTone(buzzerPin);
noteCounter = noteCounter + 1;
}
if ((playState == true) && (noteCounter >= (sizeof(noteArray4) / sizeof(int)))) {
stopPlayingISR();
}
break;
case 5:
if ((playState == true) && (noteCounter < (sizeof(noteArray5) / sizeof(int)))) {
if (noteCounter >= tempoArray5[1][tempoCounter]) {
tempoCounter = tempoCounter + 1;
}
Serial.println(noteCounter);
unsigned long noteLength = ((1/float(tempoArray5[0][tempoCounter]))*(240000))/durrationArray5[noteCounter];
Serial.println(noteLength);
tone(buzzerPin, noteArray5[noteCounter], (1-noteSeparation) * noteLength);
delay(noteLength);
noTone(buzzerPin);
noteCounter = noteCounter + 1;
}
if ((playState == true) && (noteCounter >= (sizeof(noteArray5) / sizeof(int)))) {
stopPlayingISR();
}
break;
case 6:
if ((playState == true) && (noteCounter < (sizeof(noteArray6) / sizeof(int)))) {
if (noteCounter >= tempoArray6[1][tempoCounter]) {
tempoCounter = tempoCounter + 1;
}
Serial.println(noteCounter);
unsigned long noteLength = ((1/float(tempoArray6[0][tempoCounter]))*(240000))/durrationArray6[noteCounter];
Serial.println(noteLength);
tone(buzzerPin, noteArray6[noteCounter], (1-noteSeparation) * noteLength);
delay(noteLength);
noTone(buzzerPin);
noteCounter = noteCounter + 1;
}
if ((playState == true) && (noteCounter >= (sizeof(noteArray6) / sizeof(int)))) {
stopPlayingISR();
}
break;
case 7:
if ((playState == true) && (noteCounter < (sizeof(noteArray7) / sizeof(int)))) {
if (noteCounter >= tempoArray7[1][tempoCounter]) {
tempoCounter = tempoCounter + 1;
}
Serial.println(noteCounter);
unsigned long noteLength = ((1/float(tempoArray7[0][tempoCounter]))*(240000))/durrationArray7[noteCounter];
Serial.println(noteLength);
tone(buzzerPin, noteArray7[noteCounter], (1-noteSeparation) * noteLength);
delay(noteLength);
noTone(buzzerPin);
noteCounter = noteCounter + 1;
}
if ((playState == true) && (noteCounter >= (sizeof(noteArray7) / sizeof(int)))) {
stopPlayingISR();
}
break;
}
// while
}
void writeRegistersOut(bool dataArray[], uint8_t numRegPinsOut) {
digitalWrite(latchPinOut, LOW);
for (int i = numRegPinsOut - 1; i >= 0; i--) {
digitalWrite(clockPinOut, LOW);
digitalWrite(dataPinOut, dataArray[i]);
digitalWrite(clockPinOut, HIGH);
}
digitalWrite(latchPinOut, HIGH);
}
void stopPlayingISR() {
playState = LOW;
noteCounter = 0;
tempoCounter = 0;
ledDataArray[playLedIndex] = LOW;
writeRegistersOut(ledDataArray, numBits);
Serial.println("Stop Playing");
}
void startPlaying() {
if ((digitalRead(playButtonPin)==LOW) && (playState==false)) {
playState = true;
noteCounter = 0;
tempoCounter = 0;
ledDataArray[playLedIndex] = HIGH;
writeRegistersOut(ledDataArray, numBits);
Serial.println("Start Playing");
delay(cycleDelTime);
}
}
void cycleSongs() {
if ((digitalRead(cycleButtonPin)==LOW) && (playState==false)) {
songSelection = songSelection + 1;
if (songSelection >= maxNumSongs) {
songSelection = 0;
}
Serial.println(songSelection);
switch (songSelection) {
case 0:
ledDataArray[s1LedIndex] = LOW;
ledDataArray[s2LedIndex] = LOW;
ledDataArray[s3LedIndex] = LOW;
break;
case 1:
ledDataArray[s1LedIndex] = HIGH;
ledDataArray[s2LedIndex] = LOW;
ledDataArray[s3LedIndex] = LOW;
break;
case 2:
ledDataArray[s1LedIndex] = LOW;
ledDataArray[s2LedIndex] = HIGH;
ledDataArray[s3LedIndex] = LOW;
break;
case 3:
ledDataArray[s1LedIndex] = HIGH;
ledDataArray[s2LedIndex] = HIGH;
ledDataArray[s3LedIndex] = LOW;
break;
case 4:
ledDataArray[s1LedIndex] = LOW;
ledDataArray[s2LedIndex] = LOW;
ledDataArray[s3LedIndex] = HIGH;
break;
case 5:
ledDataArray[s1LedIndex] = HIGH;
ledDataArray[s2LedIndex] = LOW;
ledDataArray[s3LedIndex] = HIGH;
break;
case 6:
ledDataArray[s1LedIndex] = LOW;
ledDataArray[s2LedIndex] = HIGH;
ledDataArray[s3LedIndex] = HIGH;
break;
case 7:
ledDataArray[s1LedIndex] = HIGH;
ledDataArray[s2LedIndex] = HIGH;
ledDataArray[s3LedIndex] = HIGH;
break;
}
writeRegistersOut(ledDataArray, numBits);
delay(cycleDelTime);
}
}