/*
* example sketch to play audio file(s) in a directory, using the mp3 library
* for playback and the arduino sd library to read files from a microsd card.
* pins are setup to work well for teensy 2.0. double-check if using arduino.
*
* originally based on frank zhao's player: http://frank.circleofcurrent.com/
* utilities adapted from previous versions of the functions by matthew seal.
*
* (c) 2011 david sirkin sirkin@cdr.stanford.edu
* akil srinivasan akils@stanford.edu
*/
// check that the microsd card is present, can be initialized and has a valid
// root volume. a pointer to the card's root object is returned as sd_root.
void sd_card_setup() {
if (!SD.begin(sd_cs)) {
Serial.println("Card failed, or isn't present.");
return;
}
if (!card.init(SPI_HALF_SPEED, sd_cs)) {
Serial.println("Card found, but initialization failed.");
return;
}
if (!volume.init(card)) {
Serial.println("Initialized, but couldn't find partition.");
return;
}
if (!sd_root.openRoot(&volume)) {
Serial.println("Partition found, but couldn't open root");
return;
}
}
// for each song file in the current directory, store its file name in eeprom
// for later retrieval. this saves on using program memory for the same task,
// which is helpful as you add more functionality to the program.
void sd_dir_setup() {
dir_t p;
num_songs = 0;
sd_root.rewind();
while (sd_root.readDir(&p) > 0 && num_songs < max_num_songs) {
// break out of while loop when we wrote all files (past the last entry).
if (p.name[0] == DIR_NAME_FREE) {
break;
}
// only store current (not deleted) file entries, and ignore the . and ..
// sub-directory entries. also ignore any sub-directories.
if (p.name[0] == DIR_NAME_DELETED || p.name[0] == '.' || !DIR_IS_FILE(&p)) {
continue;
}
// only store mp3 or wav files in eeprom (for now). if you add other file
// types, you should add their extension here.
// it's okay to hard-code the 8, 9 and 10 as indices here, since SdFatLib
// pads shorter file names with a ' ' to fill 8 characters. the result is
// that file extensions are always stored in the last 3 positions.
if ((p.name[8] == 'M' && p.name[9] == 'P' && p.name[10] == '3') ||
(p.name[8] == 'W' && p.name[9] == 'A' && p.name[10] == 'V')) {
// store each character of the file name into an individual byte in the
// eeprom. sd_file->name doesn't return the '.' part of the name, so we
// add that back later when we read the file from eeprom.
unsigned char pos = 0;
for (unsigned char i = 0; i < 11; i++) {
if (p.name[i] != ' ') {
EEPROM.write(num_songs * max_name_len + pos, p.name[i]);
pos++;
}
}
// add an 'end of string' character to signal the end of the file name.
EEPROM.write(num_songs * max_name_len + pos, '\0');
num_songs++;
// seed the start number
EEPROM.write(num_songs * max_name_len - 1 , 127);
}
}
}
// given the numerical index of a particular song to play, go to its location
// in eeprom, retrieve its file name and set the global variable 'fn' to it.
void map_current_song_to_fn() {
int fnln = max_name_len;
// based on the current_song index, get song's name and length from eeprom.
for (int i = 0; i < max_name_len - 1; i++) {
fn[i] = EEPROM.read(current_song * max_name_len + i);
// break if we reach the end of the file name, or if we have a directory.
// keep track of the file name length (fnln), so we can put the '.' back.
if (fn[i] == '\0') {
fnln = i;
i = max_name_len;
break;
}
else
if (fn[i] == '/') {
fn[0] = '\0';
fnln = 0;
i = max_name_len;
break;
}
}
// now restore the '.' that sd_file->name didn't store in its array for us.
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] = '.';
}
}
Song_Utilities:
/*
* example sketch to play audio file(s) in a directory, using the mp3 library
* for playback and the arduino sd library to read files from a microsd card.
* pins are setup to work well for teensy 2.0. double-check if using arduino.
*
* originally based on frank zhao's player: http://frank.circleofcurrent.com/
* utilities adapted from previous versions of the functions by matthew seal.
*
* (c) 2011 david sirkin sirkin@cdr.stanford.edu
* akil srinivasan akils@stanford.edu
*/
// check that the microsd card is present, can be initialized and has a valid
// root volume. a pointer to the card's root object is returned as sd_root.
void sd_card_setup() {
if (!SD.begin(sd_cs)) {
Serial.println("Card failed, or isn't present.");
return;
}
if (!card.init(SPI_HALF_SPEED, sd_cs)) {
Serial.println("Card found, but initialization failed.");
return;
}
if (!volume.init(card)) {
Serial.println("Initialized, but couldn't find partition.");
return;
}
if (!sd_root.openRoot(&volume)) {
Serial.println("Partition found, but couldn't open root");
return;
}
}
// for each song file in the current directory, store its file name in eeprom
// for later retrieval. this saves on using program memory for the same task,
// which is helpful as you add more functionality to the program.
void sd_dir_setup() {
dir_t p;
num_songs = 0;
sd_root.rewind();
while (sd_root.readDir(&p) > 0 && num_songs < max_num_songs) {
// break out of while loop when we wrote all files (past the last entry).
if (p.name[0] == DIR_NAME_FREE) {
break;
}
// only store current (not deleted) file entries, and ignore the . and ..
// sub-directory entries. also ignore any sub-directories.
if (p.name[0] == DIR_NAME_DELETED || p.name[0] == '.' || !DIR_IS_FILE(&p)) {
continue;
}
// only store mp3 or wav files in eeprom (for now). if you add other file
// types, you should add their extension here.
// it's okay to hard-code the 8, 9 and 10 as indices here, since SdFatLib
// pads shorter file names with a ' ' to fill 8 characters. the result is
// that file extensions are always stored in the last 3 positions.
if ((p.name[8] == 'M' && p.name[9] == 'P' && p.name[10] == '3') ||
(p.name[8] == 'W' && p.name[9] == 'A' && p.name[10] == 'V')) {
// store each character of the file name into an individual byte in the
// eeprom. sd_file->name doesn't return the '.' part of the name, so we
// add that back later when we read the file from eeprom.
unsigned char pos = 0;
for (unsigned char i = 0; i < 11; i++) {
if (p.name[i] != ' ') {
EEPROM.write(num_songs * max_name_len + pos, p.name[i]);
pos++;
}
}
// add an 'end of string' character to signal the end of the file name.
EEPROM.write(num_songs * max_name_len + pos, '\0');
num_songs++;
// seed the start number
EEPROM.write(num_songs * max_name_len - 1 , 127);
}
}
}
// given the numerical index of a particular song to play, go to its location
// in eeprom, retrieve its file name and set the global variable 'fn' to it.
void map_current_song_to_fn() {
int fnln = max_name_len;
// based on the current_song index, get song's name and length from eeprom.
for (int i = 0; i < max_name_len - 1; i++) {
fn[i] = EEPROM.read(current_song * max_name_len + i);
// break if we reach the end of the file name, or if we have a directory.
// keep track of the file name length (fnln), so we can put the '.' back.
if (fn[i] == '\0') {
fnln = i;
i = max_name_len;
break;
}
else
if (fn[i] == '/') {
fn[0] = '\0';
fnln = 0;
i = max_name_len;
break;
}
}
// now restore the '.' that sd_file->name didn't store in its array for us.
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] = '.';
}
}