/*
* example sketch to play audio file(s) in a directory using the mp3
* library for playback and the arduino fatfs wrapper to read files.
* based on frank zhao's player at http://frank.circleofcurrent.com/
*
* (c) 2010 david sirkin sirkin@stanford.edu
*
* Heavily reworked by Matthew Seal (mattseal@stanford.edu)
* Modified for use with the Teensy 2.0 by Akil Srinivasan (akils@stanford.edu)
*
*/
// Use 40*13 = 520 bytes of EEPROM
#define MAX_FILE_COUNT 40
#define MAX_NAME_LENGTH 13
#include <mp3.h>
#include <mp3conf.h>
// include the SD library:
#include <SD.h>
#include <EEPROM.h>
#include <Bounce.h>
// set up variables using the SD utility library functions:
Sd2Card card;
SdVolume volume;
SdFile root;
#define DEBUG // Comment this line to remove debugging features
#define mp3_cs 21 // 'command chip select' to cs pin
#define sd_cs 12 // 'chip select' for SD card
#define dcs 20 // 'data chip select' to bsync pin
#define rst 18 // 'reset' to decoder's reset pin
#define dreq 19 // 'data request line' to dreq pin
#define read_buffer 512 // size of the microsd read buffer
#define mp3_vol 200 // output volume range is 0 to 254 (0 = minimum, 254 = max)
// Instantiate a Bounce object with a 5 millisecond debounce time
int interruptPin = 5;
Bounce bouncer = Bounce(interruptPin, 5);
int ListFiles(SdFile *dir) {
int count = 0;
dir_t p;
dir->rewind();
while (dir->readDir(&p) > 0 && count < MAX_FILE_COUNT) {
// done if past last used entry
if (p.name[0] == DIR_NAME_FREE) break;
// skip deleted entry and entries for . and ..
if (p.name[0] == DIR_NAME_DELETED || p.name[0] == '.') continue;
/* Uncomment to allow subdirectories to be listed (with a '/' after the name) */
// only list subdirectories and files
//if (!DIR_IS_FILE_OR_SUBDIR(&p)) continue;
/* Uncomment to only allow files to be listed */
// only list files
if (!DIR_IS_FILE(&p)) continue;
// print file name into string
unsigned char pos = 0;
for (unsigned char i = 0; i < 11; i++) {
if (p.name[i] != ' ') {
EEPROM.write((count*MAX_NAME_LENGTH)+pos, p.name[i]);
pos++;
}
}
// append slash if file is a directory
if (DIR_IS_SUBDIR(&p)) {
EEPROM.write((count*MAX_NAME_LENGTH)+pos, '/');
pos++;
}
// add the end string character
EEPROM.write((count*MAX_NAME_LENGTH)+pos, '\0');
count++;
}
#ifdef DEBUG
Serial.print("Stored ");
Serial.print(count+1);
Serial.print(" files, using ");
Serial.print((count+1)*MAX_NAME_LENGTH, DEC);
Serial.println(" bytes in EEPROM.");
#endif
return count+1;
}
/*
* read in buffer 'bytes' of 'read_buffer' size from the file opened
* in the while loop below. This function assumes that file has already
* been opened and does NOT close the file. This means you need to do this
* outside of the function.
*/
void mp3_play (SdFile *file) {
unsigned char bytes[read_buffer]; // buffer to send to the decoder
unsigned int bytes_to_read; // number of bytes to read from sd card
// reset the file to be at the beginning of data
file->seekSet(0);
// Try to read 'read_buffer' length of bytes and send it to the decoder.
// If less than 'read_buffer' bytes are available, stop last send.
do {
// Update the debouncer
bouncer.update ( );
// Get the update value
int value = bouncer.read();
bytes_to_read = file->read(bytes, read_buffer);
Mp3.play(bytes, bytes_to_read);
if(value==LOW)
{
pause();
}
//Serial.println('.');
}
while (bytes_to_read == read_buffer);
#ifdef DEBUG
Serial.println("Played song...");
#endif
}
/*
* play back an mp3 or wav file (only!) in the root directory. first
* check that it's a file (and not a directory); next, check that it
* has a proper extension; finally, play only if it opens cleanly.
*/
void dir_play (SdFile *dir) {
int numFiles = ListFiles(dir);
for (int i = 0; i < numFiles; i++) {
char fn[MAX_NAME_LENGTH+2];
int fnln = MAX_NAME_LENGTH;
// get file name and name length
for (int j = 0; j < MAX_NAME_LENGTH; j++) {
fn[j] = EEPROM.read((i*MAX_NAME_LENGTH)+j);
// end of name
if (fn[j] == '\0') {
fnln = j;
j = MAX_NAME_LENGTH;
break;
}
// directory => nullify entry name
else if (fn[j] == '/') {
fn[0] = '\0';
fnln = 0;
j = MAX_NAME_LENGTH;
break;
}
}
if (fnln > 4) {
fn[fnln+1] = '\0';
fn[fnln] = fn[fnln-1];
fn[fnln-1] = fn[fnln-2];
fn[fnln-2] = fn[fnln-3];
fn[fnln-3] = '.';
fnln++;
#ifdef DEBUG
Serial.print("Opening ");
Serial.println(fn);
#endif
}
SdFile dataFile;
// ensure we can open the file
if (dataFile.open(dir, fn, O_RDONLY) > 0) {
// ensure it's not a directory
if (!dataFile.isDir() || fn == 0) {
//get filenames in directory fn
//get length of the filename fnln
#ifdef DEBUG
Serial.print(fn);
Serial.println(": File is valid.");
#endif
if ((fn[fnln-3] == 'M' && fn[fnln-2] == 'P' && fn[fnln-1] == '3') ||
(fn[fnln-3] == 'W' && fn[fnln-2] == 'A' && fn[fnln-1] == 'V')) {
#ifdef DEBUG
Serial.print("Playing ");
Serial.println(fn);
#endif
//buffer data for playing
mp3_play(&dataFile);
}
#ifdef DEBUG
else {
Serial.print("Skipping ");
Serial.println(fn);
}
#endif
}
#ifdef DEBUG
else {
Serial.print("File is directory ");
Serial.println(fn);
}
#endif
}
else {
Serial.print("File is not valid ");
Serial.println(fn);
}
}
}
/*
* initialize the processor speed, setup the fatfs sd card (or, mms)
* filesystem, setup mp3 playback and register the pins used (device
* specific configuration)
*/
void setup() {
Serial.begin(9600); // initialize the serial terminal
pinMode(SS_PIN, OUTPUT); // change this to 53 on a mega
digitalWrite(SS_PIN, HIGH);
// see if the card is present and can be initialized:
if (!SD.begin(sd_cs)) {
Serial.println("Card failed, or not present");
// don't do anything more:
return;
}
// we'll use the initialization code from the utility libraries
// since we're just testing if the card is working!
if (!card.init(SPI_HALF_SPEED, sd_cs)) {
Serial.println("Initialization failed. Things to check:");
Serial.println("* is a card is inserted?");
Serial.println("* Is your wiring correct?");
Serial.println("* did you change the SD chipSelect pin to match your setup?");
return;
}
// Now we will try to open the 'volume'/'partition' - it should be FAT16 or FAT32
if (!volume.init(card)) {
Serial.println("Could not find FAT16/FAT32 partition.\nMake sure you've formatted the card");
return;
}
if (!root.openRoot(&volume)) {
Serial.println("Failed to open root");
// don't do anything more:
return;
}
Mp3.begin(mp3_cs,dcs,rst,dreq); // decoder cs, dcs, rst, dreq pin from your setup
Mp3.volume(mp3_vol); // default volume level is silent (note: 0 = minimum, 254 = max)
#ifdef DEBUG
Serial.println("Card initialized.");
Serial.println("\nFiles found on the card (name, date and size in bytes): ");
// list all files in the card with date and size
root.ls(LS_R | LS_DATE | LS_SIZE);
Serial.println("Checking free memory...");
Serial.print("There are ");
Serial.print(get_free_memory(), DEC);
Serial.println(" bytes of free memory.");
Serial.print("~");
Serial.print(read_buffer, DEC);
Serial.println(" free bytes required for mp3 playing.");
#endif
// List all files to in the root directory and play each
// one at a time. Maximum of MAX_FILE_COUNT files will be read
dir_play(&root);
root.close();
}
// Do nothing for now
void loop() {
while (1);
}
void pause()
{
while(true)
{
delay(100);
bouncer.update ( );
int value = bouncer.read();
if(value==LOW)
{
delay(100);
break;
}
}
}
Comments (0)
You don't have permission to comment on this page.