// "Trigger" example sketch for Lilypad MP3 Player
// Mike Grusin, SparkFun Electronics
// http://www.sparkfun.com
// Uses the SdFat library by William Greiman, which is supplied
// with this archive, or download from http://code.google.com/p/sdfatlib/
// Uses the SFEMP3Shield library by Bill Porter, which is supplied
// with this archive, or download from http://www.billporter.info/
// NOTE: The large bracket lines surround the blocks of text which
// are important for this project.
// ------------ [ ------------ [ ------------ [ ------------ [
// ------------ [ ------------ [ ------------ [ ------------ [
// ------------ ------------ ------------ ------------
// (Section 1a - Initialization) These are the libraries you need to make sure you import into your Arduino Library folder
#include <SPI.h> // To talk to the SD card and MP3 chip
#include <SdFat.h> // SD card file system
#include <SFEMP3Shield.h> // MP3 decoder chip
const int TRIG1 = A0; // This is the only pin that is going to remain a trigger
// These 4 pins are made into digital output pins so you can send a digitalWrite(pinName) to them
const int TRIG2 = A4;
const int TRIG3 = A5;
const int TRIG4 = 1;
const int TRIG5 = 0;
// This creates an array (table) of integers with a length of 5
// The array stores the trigger names, so typing TRIG1 in the code
// would be the same as typing trigger[1]. This is a shortcut for declaring pins.
int trigger[5] = {TRIG1,TRIG2,TRIG3,TRIG4,TRIG5};
// ------------ ------------ ------------ ------------
// (Section 1b Boolean Setting) These are the libraries you need to make sure you import into your Arduino Library folder
// Set debugging = true if you'd like status messages sent
// to the serial port. Note that this will take over trigger
// inputs 4 and 5. (You can leave triggers connected to 4 and 5
// and still use the serial port, as long as you're careful to
// NOT ground the triggers while you're using the serial port).
boolean debugging = false;
// Setting this value to true will repurpose trigger pins 2 - 5
// so that they are digital outputs. (BD)
// this just says that there ARE digital output pins
boolean digitalOutputPins = true;
// ------------ ] ------------ ] ------------ ] ------------ ]
// ------------ ] ------------ ] ------------ ] ------------ ]
// And a few outputs we'll be using: (Needed for the system)
const int ROT_LEDR = 10; // Red LED in rotary encoder (optional)
const int EN_GPIO1 = A2; // Amp enable + MIDI/MP3 mode select
const int SD_CS = 9; // Chip Select for SD card
// Create library objects:
SFEMP3Shield MP3player;
SdFat sd;
// ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
// Set interrupt = false if you would like a triggered file to
// play all the way to the end. If this is set to true, new
// triggers will stop the playing file and start a new one.
boolean interrupt = true;
// Set interruptself = true if you want the above rule to also
// apply to the same trigger. In other words, if interrupt = true
// and interruptself = false, subsequent triggers on the same
// file will NOT start the file over. However, a different trigger
// WILL stop the original file and start a new one.
boolean interruptself = true;
// We'll store the five filenames as arrays of characters.
// "Short" (8.3) filenames are used, followed by a null character.
char filename[5][13];
// ------------ [ ------------ [ ------------ [ ------------ [
// ------------ [ ------------ [ ------------ [ ------------ [
// Sets up pins and board
void setup() {
int x, index; SdFile file; byte result; char tempfilename[13];
if (digitalOutputPins) { // if digitalOutputPins is set to true, pins 2 - 5 are set to outputs
debugging = false; // debugging takes over pins 3 and 4 so it is disabled to make them outputs
pinMode(TRIG2,OUTPUT); pinMode(TRIG3,OUTPUT); pinMode(TRIG4,OUTPUT); pinMode(TRIG5,OUTPUT); // Sets pins 2 - 5 to outputs
digitalWrite(TRIG5,LOW);
pinMode(TRIG1,INPUT); digitalWrite(TRIG1,HIGH); // Sets T1 to be a trigger pin
}
else { // This is the standard setup of the board where all pins are triggers
for (x = 0; x <= 4; x++) { // loops through trigger array syntax: for ( start; // ends if this is true; // increment per loop to increase x by (x++ is the same as x = x + 1))
pinMode(trigger[x],INPUT); // sets pin at trigger index
digitalWrite(trigger[x],HIGH); // writes once to set up pulldown resistor
}
}
// ------------ ] ------------ ] ------------ ] ------------ ]
// ------------ ] ------------ ] ------------ ] ------------ ]
// If serial port debugging is inconvenient, you can connect
// a LED to the red channel of the rotary encoder to blink
// startup error codes:
pinMode(ROT_LEDR,OUTPUT);
digitalWrite(ROT_LEDR,HIGH); // HIGH = off
// The board uses a single I/O pin to select the
// mode the MP3 chip will start up in (MP3 or MIDI),
// and to enable/disable the amplifier chip:
pinMode(EN_GPIO1,OUTPUT);
digitalWrite(EN_GPIO1,LOW); // MP3 mode / amp off
// If debugging is true, initialize the serial port:
// (The 'F' stores constant strings in flash memory to save RAM)
if (debugging)
{
Serial.begin(9600);
Serial.println(F("Lilypad MP3 Player trigger sketch"));
}
// Initialize the SD card; SS = pin 9, half speed at first
if (debugging) Serial.print(F("initialize SD card... "));
result = sd.begin(SD_CS, SPI_HALF_SPEED); // 1 for success
if (result != 1) // Problem initializing the SD card
{
if (debugging) Serial.print(F("error, halting"));
errorBlink(1); // Halt forever, blink LED if present.
}
else
if (debugging) Serial.println(F("success!"));
// Start up the MP3 library
if (debugging) Serial.print(F("initialize MP3 chip... "));
result = MP3player.begin(); // 0 or 6 for success
// Check the result, see the library readme for error codes.
if ((result != 0) && (result != 6)) // Problem starting up
{
if (debugging)
{
Serial.print(F("error code "));
Serial.print(result);
Serial.print(F(", halting."));
}
errorBlink(result); // Halt forever, blink red LED if present.
}
else
if (debugging) Serial.println(F("success!"));
// Now we'll access the SD card to look for any (audio) files
// starting with the characters '1' to '5':
if (debugging) Serial.println(F("reading root directory"));
// Start at the first file in root and step through all of them:
sd.chdir("/",true);
while (file.openNext(sd.vwd(),O_READ))
{
// get filename
file.getFilename(tempfilename);
// Does the filename start with char '1' through '5'?
if (tempfilename[0] >= '1' && tempfilename[0] <= '5')
{
// Yes! subtract char '1' to get an index of 0 through 4.
index = tempfilename[0] - '1';
// Copy the data to our filename array.
strcpy(filename[index],tempfilename);
if (debugging) // Print out file number and name
{
Serial.print(F("found a file with a leading "));
Serial.print(index+1);
Serial.print(F(": "));
Serial.println(filename[index]);
}
}
else
if (debugging)
{
Serial.print(F("found a file w/o a leading number: "));
Serial.println(tempfilename);
}
file.close();
}
if (debugging)
Serial.println(F("done reading root directory"));
if (debugging) // List all the files we saved:
{
for(x = 0; x <= 4; x++)
{
Serial.print(F("trigger "));
Serial.print(x+1);
Serial.print(F(": "));
Serial.println(filename[x]);
}
}
// Set the VS1053 volume. 0 is loudest, 255 is lowest (off):
MP3player.setVolume(10,10);
// Turn on the amplifier chip:
digitalWrite(EN_GPIO1,HIGH);
delay(2);
}
void loop() {
int t; int i; // current trigger
static int last_t; // previous (playing) trigger
int x;
byte result;
// Step through the trigger inputs, looking for LOW signals.
// The internal pullup resistors will keep them HIGH when
// there is no connection to the input.
// If serial debugging is on, only check triggers 1-3,
// otherwise check triggers 1-5.
int triggers = 0; // Number of trigger pins
if (debugging) {
triggers = 3;
}
else if (digitalOutputPins) {
triggers = 1;
}
else {
triggers = 5;
};
for(t = 1; t <= triggers; t++)
{
// The trigger pins are stored in the inputs[] array.
// Read the pin and check if it is LOW (triggered).
if (digitalRead(trigger[t-1]) == LOW)
{
// Wait for trigger to return high for a solid 50ms
// (necessary to avoid switch bounce on T2 and T3
// since we need those free for I2C control of the
// amplifier)
x = 0;
while(x < 50)
{
if (digitalRead(trigger[t-1]) == HIGH){
x++; }
else
x = 0;
delay(1);
}
if (debugging)
{
Serial.print(F("got trigger "));
Serial.println(t);
}
// Do we have a valid filename for this trigger?
// (Invalid filenames will have 0 as the first character)
if (filename[t-1][0] == 0)
{
if (debugging)
Serial.println(F("no file with that number"));
}
else // We do have a filename for this trigger!
{
// If a file is already playing, and we've chosen to
// allow playback to be interrupted by a new trigger,
// stop the playback before playing the new file.
if (interrupt && MP3player.isPlaying() && ((t != last_t) || interruptself))
{
if (debugging)
Serial.println(F("stopping playback"));
MP3player.stopTrack();
}
// Play the filename associated with the trigger number.
// (If a file is already playing, this command will fail
// with error #2).
//To make the mp3 track play at a certain point in the track, add a comma after the filename and the number of millisecondsin you want the
// track to play.
result = MP3player.playMP3(filename[t-1]); // plays mp3 sequence
if (result == 0) last_t = t; // Save playing trigger
// ------------ [ ------------ [ ------------ [ ------------ [
// ------------ [ ------------ [ ------------ [ ------------ [
// SOUTH AFRICAN NATIONAL ANTHEM PLAYS
// Yellow LEDs blink every .5 seconds during the song
if (digitalOutputPins) { // LED Sequence digitalWrites - will start BEFORE music)
for (i = 1; i < 27; i++) { // Blink Sequence 1
digitalWrite(TRIG2,HIGH);
delay(500);
digitalWrite(TRIG2,LOW);
delay(500);
}
}
if (digitalOutputPins) { // LED Sequence digitalWrites - will start AFTER music)
// MARVINA SPEAKS
// 3 RED LEDs turn on for the whole time she is speaking
{
// Blink Sequence 2
digitalWrite(TRIG3,HIGH);
delay(75000);
digitalWrite(TRIG3,LOW);
delay(1000);
}
// MEL INTRODUCES NELSON Note: USE TRIGGER PIN 5
// Left side Yellow LEDs blink for 39 seconds
for (i = 1; i < 32; i++) { // Blink Sequence 3
digitalWrite(TRIG5,HIGH);
delay(500);
digitalWrite(TRIG5,LOW);
delay(500);
}
// NELSON MANDELA SPEAKS (FIRST 30 SECONDS) Note: USE TRIGGER PIN 4
// Right side Yellow LEDs blink for 30 seconds
for (i = 1; i < 25; i++) { // Blink Sequence 4
digitalWrite(TRIG4,HIGH);
delay(500);
digitalWrite(TRIG4,LOW);
delay(500);
}
// NELSON MANDELA SPEAKS (last 120 seconds)
// Right side and Left side Yellow LEDs blink alternately
for (i=0;i<76; i++)
{
// display Mandela's lights
digitalWrite(TRIG5,HIGH);
delay(600);
digitalWrite(TRIG5,LOW);
digitalWrite(TRIG4,HIGH);
delay(600);
digitalWrite(TRIG4,LOW);
}
//Put the Spotlight on Mandela for the last 30 seconds
digitalWrite(TRIG4,HIGH);
delay(15000);
digitalWrite(TRIG4,LOW);
}
// ------------ ] ------------ ] ------------ ] ------------ ]
// ------------ ] ------------ ] ------------ ] ------------ ]
if(debugging)
{
if(result != 0)
{
Serial.print(F("error "));
Serial.print(result);
Serial.print(F(" when trying to play track "));
}
else
{
Serial.print(F("playing "));
}
Serial.println(filename[t-1]);
}
}
}
}
}
void errorBlink(int blinks)
{
// The following function will blink the red LED in the rotary
// encoder (optional) a given number of times and repeat forever.
// This is so you can see any startup error codes without having
// to use the serial monitor window.
int x;
while(true) // Loop forever
{
for (x=0; x < blinks; x++) // Blink the given number of times
{
digitalWrite(ROT_LEDR,LOW); // Turn LED ON
delay(250);
digitalWrite(ROT_LEDR,HIGH); // Turn LED OFF
delay(250);
}
delay(1500); // Longer pause between blink-groups
}
}