I am having problems trying to play a random MP3 from an SD card

I first want to say I am new to Arduino and programming so I am having a little trouble grasping some of the concepts, or at least that is what I think I am doing wrong, amoung other things I am sure. :cold_sweat:

I have gotten some help from a few places, but I have been given more of vague references that I do not understand full, but I have included a copy of my code below.

I am using a Adafruit “Music Maker” MP3 Shield for Arduino w/3W Stereo Amp and an Arduino Mega 2560. I am trying to get the Adafruit_VS1053, “player_interrupts” code to run and play a random MP3 stored on SD card inserted into a Adafruit “Music Maker” MP3 Shield. I have not been able to figure out how to tell the code to play a random file. I can only get it to play if I specify the file name specifically in the code. I have tried placing a txt file, (MP3s.txt) on the SD card and read that into an array to pass to the line but I have not been able to get that to work either. The latest version of my code tries to take advantage of the random() function to get the file names; I played around with it and got it to run without errors, but when I upload it to my Arduino, it plays the beep, lists the files on the SD card, and stops.

// include SPI, MP3 and SD libraries
#include <SPI.h>
#include <Adafruit_VS1053.h>
#include <SD.h>
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\
// These are the pins used for the music maker shield
#define SHIELD_RESET  -1      // VS1053 reset pin (unused!)
#define SHIELD_CS     7      // VS1053 chip select pin (output)
#define SHIELD_DCS    6      // VS1053 Data/command select pin (output)

// These are common pins between breakout and shield
#define CARDCS 4     // Card chip select pin
// DREQ should be an Int pin, see http://arduino.cc/en/Reference/attachInterrupt
#define DREQ 3       // VS1053 Data request, ideally an Interrupt pin

Adafruit_VS1053_FilePlayer musicPlayer =
  Adafruit_VS1053_FilePlayer(SHIELD_RESET, SHIELD_CS, SHIELD_DCS, DREQ, CARDCS);

void setup() {
  Serial.begin(9600);
  Serial.println("Adafruit VS1053 Library Test");
  // initialise the music player
  if (! musicPlayer.begin()) { // initialise the music player
    Serial.println(F("Couldn't find VS1053, do you have the right pins defined?"));
    while (1);
  }
  Serial.println(F("VS1053 found"));

  musicPlayer.sineTest(0x44, 500);    // Make a tone to indicate VS1053 is working

  if (!SD.begin(CARDCS)) {
    Serial.println(F("SD failed, or not present"));
    while (1);  // don't do anything more
  }
  Serial.println("SD OK!");
  

// list files
  printDirectory(SD.open("/"), 0);
  // Set volume for left, right channels. lower numbers == louder volume!
  musicPlayer.setVolume(20, 20);

  if (! musicPlayer.useInterrupt(VS1053_FILEPLAYER_PIN_INT))
    Serial.println(F("DREQ pin is not an interrupt pin"));
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void loop() {
  // put your main code here, to run repeatedly:
  File path = SD.open("/");
  File results; 
  char* MP3 = selectRandomFileFrom( path, results );
  Serial.println(MP3);
  delay(1000);
// Start playing a file, then we can do stuff while waiting for it to finish
  if (! musicPlayer.startPlayingFile(MP3)) {
    Serial.println("Could not open file: ");
    //Serial.println(MP3);
    //while (1);
  }
  Serial.println(F("Started playing"));

  while (musicPlayer.playingMusic) {
    // file is now playing in the 'background' so now's a good time
    // to do something else like handling LEDs or buttons :)
    Serial.print(".");
    delay(1000);
  }
  Serial.println("Done playing music");
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// File listing helper
void printDirectory(File dir, int numTabs) {
  while (true) {

    File entry =  dir.openNextFile();
    if (! entry) {
      // no more files
      //Serial.println("**nomorefiles**");
      break;
    }
    for (uint8_t i = 0; i < numTabs; i++) {
      Serial.print('\t');
    }
    Serial.print(entry.name());
    if (entry.isDirectory()) {
      Serial.println("/");
      printDirectory(entry, numTabs + 1);
    } else {
      // files have sizes, directories do not
      Serial.print("\t\t");
      Serial.println(entry.size(), DEC);
    }
    entry.close();
  }
}

// Function to select random mp3
char* selectRandomFileFrom( File dir, File result ) {
  File entry;
  int count = 1;

  dir.rewindDirectory();

  while ( entry = dir.openNextFile() ) {
    if ( random( count ) == 0 ) {
      result = entry;
    }
    entry.close();
    count++;
  }
}

I am using this version of the code:

// Start playing a file, then we can do stuff while waiting for it to finish
  if (! musicPlayer.startPlayingFile(MP3)) {
    Serial.println("Could not open file: ");
    //Serial.println(MP3);
    //while (1);
  }
  Serial.println(F("Started playing"));

  while (musicPlayer.playingMusic) {
    // file is now playing in the 'background' so now's a good time
    // to do something else like handling LEDs or buttons :)
    Serial.print(".");
    delay(1000);

because I need to run a couple of servos while the MP3 are playing.

  char* MP3 = selectRandomFileFrom( path, results );

What, exactly, are you expecting MP3 to point to when this function returns?

char* selectRandomFileFrom( File dir, File result ) {
  File entry;
  int count = 1;

  dir.rewindDirectory();

  while ( entry = dir.openNextFile() ) {
    if ( random( count ) == 0 ) {
      result = entry;
    }
    entry.close();
    count++;
  }
}

The first call to random will generate a random number somewhere between 0 and 0. It's pretty safe to assume that the number will be 0. So, the value in entry will be assigned to result. But, result is an input variable, so the caller will know nothing about what the function is doing to the variable.

Since you don't break out of the while loop, the code will keep executing, but accomplishing nothing. When the end of the directory is reached, the function returns without actually returning anything.

So, MP3 will be assigned some random garbage from the stack, and point to who knows where, containing who knows what.

You can't really expect to play the file who's name is at some unpredictable location in memory, can you?

Yeah, I know what you mean :disappointed_relieved: I was getting help on another forum and this is the path they lead me down with just some vague sample codes and after a few days of back and forth this is where I ended up. Honestly I am more confused and lost now than I was when I started this project. I still appreciate the help I was getting on the other forum, but either I am just not getting what they are trying to show me or I just am really bad at trying to describe what it is I am trying to do.

I am just looking for a function that I can call that will read the list of files on an attached SD card, pick a random MP3 and return that so I can pass it to the adafruit MP3 shield function musicPlayer.startPlayingFile(); And at this point if that is all it does, I would be ecstatic.

My end goal is to have a function that pulls the name of a random MP3 off of the SD card based on either Folder name, (.\halloween\1.mp3, .\halloween\2.mp3, .\christm\1.mp3, .\chrism\2.mp3) or Filename (hallow01.mp3, hallow02.mp3, christm01.mp3, chrism02.mp3) so that eventually I can incorporate a pir sensor to trigger a switch between different types of sounds.

I appreciate any help I can get and I am willing to learn. I want to get to the point where I am answering questions, not creating them. But for now I would just love a good working example with hopefully a little commenting to explain what or why it is doing so I can figure out how to put it in my code and hopefully learn to update it to perform my end goal.

Thank you for your assistance.

Alright, I am more confused. I added a return to the function (yeah I know, newbie move to forget to the return) but now the code is working. So I want to post a question to all of you. How is this working? I still don’t quite understand it, oh and why is the random order always the same?

// include SPI, MP3 and SD libraries
#include <SPI.h>
#include <Adafruit_VS1053.h>
#include <SD.h>
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\
// These are the pins used for the music maker shield
#define SHIELD_RESET  -1      // VS1053 reset pin (unused!)
#define SHIELD_CS     7      // VS1053 chip select pin (output)
#define SHIELD_DCS    6      // VS1053 Data/command select pin (output)

// These are common pins between breakout and shield
#define CARDCS 4     // Card chip select pin
// DREQ should be an Int pin, see http://arduino.cc/en/Reference/attachInterrupt
#define DREQ 3       // VS1053 Data request, ideally an Interrupt pin

Adafruit_VS1053_FilePlayer musicPlayer =
  Adafruit_VS1053_FilePlayer(SHIELD_RESET, SHIELD_CS, SHIELD_DCS, DREQ, CARDCS);

void setup() {
  Serial.begin(9600);
  Serial.println("Adafruit VS1053 Library Test");
  // initialise the music player
  if (! musicPlayer.begin()) { // initialise the music player
    Serial.println(F("Couldn't find VS1053, do you have the right pins defined?"));
    while (1);
  }
  Serial.println(F("VS1053 found"));

  musicPlayer.sineTest(0x44, 500);    // Make a tone to indicate VS1053 is working

  if (!SD.begin(CARDCS)) {
    Serial.println(F("SD failed, or not present"));
    while (1);  // don't do anything more
  }
  Serial.println("SD OK!");
  

// list files
  printDirectory(SD.open("/"), 0);
  // Set volume for left, right channels. lower numbers == louder volume!
  musicPlayer.setVolume(20, 20);

  if (! musicPlayer.useInterrupt(VS1053_FILEPLAYER_PIN_INT))
    Serial.println(F("DREQ pin is not an interrupt pin"));
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void loop() {
  // put your main code here, to run repeatedly:
  File path = SD.open("/");
  File results; 
  char* MP3 = selectRandomFileFrom( path, results );
// Serial.println(MP3);
  delay(1000);
// Start playing a file, then we can do stuff while waiting for it to finish
  if (! musicPlayer.startPlayingFile(MP3)) {
    Serial.println("Could not open file: ");
    Serial.println(MP3);
    //while (1);
  }
  Serial.print(F("Now playing "));
  Serial.println(MP3);

  while (musicPlayer.playingMusic) {
    // file is now playing in the 'background' so now's a good time
    // to do something else like handling LEDs or buttons :)
    Serial.print(".");
    delay(1000);
  }
  Serial.println("Done playing music");
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// File listing helper
void printDirectory(File dir, int numTabs) {
  while (true) {

    File entry =  dir.openNextFile();
    if (! entry) {
      // no more files
      //Serial.println("**nomorefiles**");
      break;
    }
    for (uint8_t i = 0; i < numTabs; i++) {
      Serial.print('\t');
    }
    Serial.print(entry.name());
    if (entry.isDirectory()) {
      Serial.println("/");
      printDirectory(entry, numTabs + 1);
    } else {
      // files have sizes, directories do not
      Serial.print("\t\t");
      Serial.println(entry.size(), DEC);
    }
    entry.close();
  }
}

// Function to select random mp3
char* selectRandomFileFrom( File dir, File result ) {
  File entry;
  int count = 0;

  dir.rewindDirectory();

  while ( entry = dir.openNextFile() ) {
    if ( random( count ) == 0 ) {
      result = entry;
    }
    entry.close();
    count++;
  }
  return result.name();   // returns the randomly selected file name
}

Oh and I have one more, possibly stupid question, when the code is uploaded, do the comments get uploaded too taking up more programming space? :~

I am just looking for a function that I can call that will read the list of files on an attached SD card, pick a random MP3 and return that so I can pass it to the adafruit MP3 shield function musicPlayer.startPlayingFile(); And at this point if that is all it does, I would be ecstatic.

In the function to choose a random file, the first thing you need to do is count the files.

Then, you choose a random number between 0 and that number of files. The random function will never return the upper limit value, so the number of files IS the correct upper limit.

Then, you cycle through the files again, counting them. When you get to the nth file (where n is the chosen random number, get the name of the file. That is what you want to return.

Of course, the array that holds the file name must be static, so the memory continues to remain reserved when the function ends, so that the pointer remains valid.

Is there some part of this that you need help with?

I appreciate all of the help I have received, I couldn’t have done it otherwise. Here is the basically final copy of my code including the lighting control. I hope it helps someone else.

// include SPI, MP3 and SD libraries
#include <SPI.h>
#include <Adafruit_VS1053.h>
#include <SD.h>
#include <Servo.h>
//////////////////////////////////////////////////////////////////////////////////////////////////////
// These are the pins used for the music maker shield
#define SHIELD_RESET  -1      // VS1053 reset pin (unused!)
#define SHIELD_CS     7      // VS1053 chip select pin (output)
#define SHIELD_DCS    6      // VS1053 Data/command select pin (output)
// These are common pins between breakout and shield
#define CARDCS 4     // Card chip select pin
// DREQ should be an Int pin, see http://arduino.cc/en/Reference/attachInterrupt
#define DREQ 3       // VS1053 Data request, ideally an Interrupt pin
Adafruit_VS1053_FilePlayer musicPlayer =
  Adafruit_VS1053_FilePlayer(SHIELD_RESET, SHIELD_CS, SHIELD_DCS, DREQ, CARDCS);
//////////////////////////////////////////////////////////////////////////////////////////////////////
Servo EyeLh, EyeLv, EyeRh, EyeRv, Jaw; //4 servos control the eyes left/right and up/down, and 1 for the jaw
int ELHpos, ELVpos, ERHpos, ERVpos, Jpos = 0;
int Jdelay = 10;
//////////////////////////////////////////////////////////////////////////////////////////////////////
//Pin Definitions //The 74HC595 uses a serial communication link which has three pins
int data = 2;
int clock = 5;
int latch = 8;

//Used for single LED manipulation
int ledState = 0;
const int ON = HIGH;
const int OFF = LOW;
/////////////////////////////////////////////////////////////////////////////////////////////////////
void setup() {
  Serial.begin(9600);  //initialize the serial monitor
  // LED set the three control pins to outputs
  pinMode(data, OUTPUT);
  pinMode(clock, OUTPUT);
  pinMode(latch, OUTPUT);
  //////////////////////////////////////////////////////////////////////////////////////////////////////
  uint32_t seed = 0;  // Generate random see start
  for ( uint8_t i = 10 ; i ; i-- ) {
    seed = ( seed << 5 ) + ( analogRead( 0 ) * 3 );
  }
  randomSeed( seed );  //set random seed
  EyeLh.attach(53); //Attaches the Left Eye servo for horizontel movement to pin 24
  EyeLv.attach(41);
  EyeRh.attach(45);
  EyeRv.attach(49);
  Jaw.attach(37); //Pin assignment for the Jaw servo
  Serial.println("Adafruit VS1053 Library Test");
  Serial.print("RandomSeed value = ");
  Serial.println(seed);
  // initialise the music player
  if (! musicPlayer.begin()) { // initialise the music player
    Serial.println(F("Couldn't find VS1053, do you have the right pins defined?"));
    while (1);
  }
  Serial.println(F("VS1053 found"));
  musicPlayer.sineTest(0x44, 500);    // Make a tone to indicate VS1053 is working

  if (!SD.begin(CARDCS)) {
    Serial.println(F("SD failed, or not present"));
    while (1);  // don't do anything more
  }

  Serial.println("SD OK!");

  // list files
  printDirectory(SD.open("/"), 0);
  // Set volume for left, right channels. lower numbers == louder volume!
  musicPlayer.setVolume(0, 0);

  if (! musicPlayer.useInterrupt(VS1053_FILEPLAYER_PIN_INT))
    Serial.println(F("DREQ pin is not an interrupt pin"));
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
void loop() {
  // put your main code here, to run repeatedly:
  File path = SD.open("/");
  File results;
  char* MP3 = selectRandomFileFrom( path, results );
  delay(1000);
  ELHpos, ELVpos, ERHpos, ERVpos, Jpos = 0; //always return the servos back to 0 at the start of a new song
  // Start playing a file, then we can do stuff while waiting for it to finish
  if (! musicPlayer.startPlayingFile(MP3)) {
    Serial.println("Could not open file: ");
    Serial.println(MP3);
  }

  Serial.print(F("Now playing "));
  Serial.println(MP3);
  while (musicPlayer.playingMusic) {
    // file is now playing in the 'background' so now's a good time
    // to do something else like handling LEDs or buttons :)
    Jpos = random( 20, 105 );
    delay( 50 );
    Jaw.write(Jpos);
    // Select new Eye position
    MoveEyes();
    // LED Section
    int i = random(255);
    updateLEDs(i);
    delay(250);
    //Serial.print(".");
    //////////////////////////////////////////////////////////////////////////////////////////////////////////
  }
  Serial.print("Done playing: ");
  Serial.println(MP3);
  Serial.println();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/// File listing helper
void printDirectory(File dir, int numTabs) {
  while (true) {

    File entry =  dir.openNextFile();
    if (! entry) {
      // no more files
      //Serial.println("**nomorefiles**");
      break;
    }
    for (uint8_t i = 0; i < numTabs; i++) {
      Serial.print('\t');
    }
    Serial.print(entry.name());
    if (entry.isDirectory()) {
      Serial.println("/");
      printDirectory(entry, numTabs + 1);
    } else {
      // files have sizes, directories do not
      Serial.print("\t\t");
      Serial.println(entry.size(), DEC);
    }
    entry.close();
  }
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Function to select random mp3
char* selectRandomFileFrom( File dir, File result ) {
  File entry;
  int count = 0;

  dir.rewindDirectory();

  while ( entry = dir.openNextFile() ) {
    if ( random( count ) == 0 ) {
      result = entry;
    }
    entry.close();
    count++;
  }
  return result.name();   // returns the randomly selected file name
}

//////////////////////////////////////////////////////////////////////////////////////////////////////
void MoveEyes() {
  ELHpos = random(10, 100);
  ELVpos = random(10, 100);
  ERHpos = random(10, 100);
  ERVpos = random(10, 100);
  // tell the Eye servos to move to the new position
  EyeLh.write(ELHpos);
  EyeLv.write(ELVpos);
  delay(5);
  EyeRh.write(ERHpos);
  EyeRv.write(ERVpos);
  delay(5);
}
//Functions for the LEDs
/*
 * updateLEDs() - sends the LED states set in ledStates to the 74HC595
 * sequence
 */
void updateLEDs(int value) {
  digitalWrite(latch, LOW);     //Pulls the chips latch low
  shiftOut(data, clock, MSBFIRST, value); //Shifts out the 8 bits to the shift register
  digitalWrite(latch, HIGH);   //Pulls the latch high displaying the data
}

/*
 * updateLEDsLong() - sends the LED states set in ledStates to the 74HC595
 * sequence. Same as updateLEDs except the shifting out is done in software
 * so you can see what is happening.
 */
void updateLEDsLong(int value) {
  digitalWrite(latch, LOW);    //Pulls the chips latch low
  for (int i = 0; i < 8; i++) { //Will repeat 8 times (once for each bit)
    int bit = value & B10000000; //We use a "bitmask" to select only the eighth
    //bit in our number (the one we are addressing this time through
    value = value << 1;          //we move our number up one bit value so next time bit 7 will be
    //bit 8 and we will do our math on it
    if (bit == 128) {
      digitalWrite(data, HIGH); //if bit 8 is set then set our data pin high
    }
    else {
      digitalWrite(data, LOW); //if bit 8 is unset then set the data pin low
    }
    digitalWrite(clock, HIGH);                //the next three lines pulse the clock pin
    delay(1);
    digitalWrite(clock, LOW);
  }
  digitalWrite(latch, HIGH);  //pulls the latch high shifting our data into being displayed
}


//These are used in the bitwise math that we use to change individual LEDs
//For more details http://en.wikipedia.org/wiki/Bitwise_operation
int bits[] = {B00000001, B00000010, B00000100, B00001000, B00010000, B00100000, B01000000, B10000000};
int masks[] = {B11111110, B11111101, B11111011, B11110111, B11101111, B11011111, B10111111, B01111111};
/*
 * changeLED(int led, int state) - changes an individual LED
 * LEDs are 0 to 7 and state is either 0 - OFF or 1 - ON
 */
void changeLED(int led, int state) {
  ledState = ledState & masks[led];  //clears ledState of the bit we are addressing
  if (state == ON) {
    ledState = ledState | bits[led]; //if the bit is on we will add it to ledState
  }
  updateLEDs(ledState);              //send the new LED state to the shift register
}

hi there -

i’m currently trying to use this code, but i need to repurpose two functions…i need it to continually randomly play (right now it stops playing after it has randomly scrolled through all of the files) - and i need it to start on a different file each time it starts. i’m even less experienced than the OP, so i’m not sure how to do this, i would greatly appreciate any kind of help.

i modified the previous code to take out all of the LED/servo stuff, so hopefully this will be clearer:

// include SPI, MP3 and SD libraries
#include <SPI.h>
#include <Adafruit_VS1053.h>
#include <SD.h>
//////////////////////////////////////////////////////////////////////////////////////////////////////
// These are the pins used for the music maker shield
#define SHIELD_RESET  -1      // VS1053 reset pin (unused!)
#define SHIELD_CS     7      // VS1053 chip select pin (output)
#define SHIELD_DCS    6      // VS1053 Data/command select pin (output)
// These are common pins between breakout and shield
#define CARDCS 4     // Card chip select pin
// DREQ should be an Int pin, see http://arduino.cc/en/Reference/attachInterrupt
#define DREQ 3       // VS1053 Data request, ideally an Interrupt pin
Adafruit_VS1053_FilePlayer musicPlayer =
Adafruit_VS1053_FilePlayer(SHIELD_RESET, SHIELD_CS, SHIELD_DCS, DREQ, CARDCS);

void setup() {
  Serial.begin(9600);  //initialize the serial monitor
 
  //////////////////////////////////////////////////////////////////////////////////////////////////////
  uint32_t seed = 0;  // Generate random see start
  for ( uint8_t i = 10 ; i ; i-- ) {
    seed = ( seed << 5 ) + ( analogRead( 0 ) * 3 );
  }
  randomSeed( seed );  //set random seed
  Serial.println("Adafruit VS1053 Library Test");
  Serial.print("RandomSeed value = ");
  Serial.println(seed);
  // initialise the music player
  if (! musicPlayer.begin()) { // initialise the music player
    Serial.println(F("Couldn't find VS1053, do you have the right pins defined?"));
    while (1);
  }
  Serial.println(F("VS1053 found"));
  musicPlayer.sineTest(0x44, 500);    // Make a tone to indicate VS1053 is working

  if (!SD.begin(CARDCS)) {
    Serial.println(F("SD failed, or not present"));
    while (1);  // don't do anything more
  }

  Serial.println("SD OK!");

  // list files
  printDirectory(SD.open("/"), 0);
  // Set volume for left, right channels. lower numbers == louder volume!
  musicPlayer.setVolume(0, 0);

  if (! musicPlayer.useInterrupt(VS1053_FILEPLAYER_PIN_INT))
    Serial.println(F("DREQ pin is not an interrupt pin"));
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
void loop() {
  // put your main code here, to run repeatedly:
  File path = SD.open("/");
  File results;
  char* MP3 = selectRandomFileFrom( path, results );
  delay(1000);

  if (! musicPlayer.startPlayingFile(MP3)) {
    Serial.println("Could not open file: ");
    Serial.println(MP3);
  }

  Serial.print(F("Now playing "));
  Serial.println(MP3);
  while (musicPlayer.playingMusic) {
    // file is now playing in the 'background' so now's a good time
    // to do something else like handling LEDs or buttons :)
  }
  Serial.print("Done playing: ");
  Serial.println(MP3);
  Serial.println();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/// File listing helper
void printDirectory(File dir, int numTabs) {
  while (true) {

    File entry =  dir.openNextFile();
    if (! entry) {
      // no more files
      //Serial.println("**nomorefiles**");
      break;
    }
    for (uint8_t i = 0; i < numTabs; i++) {
      Serial.print('\t');
    }
    Serial.print(entry.name());
    if (entry.isDirectory()) {
      Serial.println("/");
      printDirectory(entry, numTabs + 1);
    } else {
      // files have sizes, directories do not
      Serial.print("\t\t");
      Serial.println(entry.size(), DEC);
    }
    entry.close();
  }
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Function to select random mp3
char* selectRandomFileFrom( File dir, File result ) {
  File entry;
  int count = 0;

  dir.rewindDirectory();

  while ( entry = dir.openNextFile() ) {
    if ( random( count ) == 0 ) {
      result = entry;
    }
    entry.close();
    count++;
  }
  return result.name();   // returns the randomly selected file name
}

//////////////////////////////////////////////////////////////////////////////////////////////////////

OK, the first issue was that there was a sine wave "test" and I was just playing sine wave mp3s, so I got confused. Sorry for that.

Second issue: There were hidden files on the SD card, causing the program to crash. I took care of that.

Still, now, though, there does seem to be a point in the code where something like this happens:
Now playing TRACK004.MP3
Now playing
Could not open file:

It tries to open a blank, can't find it, and crashes.

Any thoughts on what causes that?

here’s the code, i’ve changed it slightly - but i am still having the same problem. any pointers would be great. thank you!

// include SPI, MP3 and SD libraries
#include <SPI.h>
#include <Adafruit_VS1053.h>
#include <SD.h>

//////////////////////////////////////////////////////////////////////////////////////////////////////
// These are the pins used for the music maker shield
#define SHIELD_RESET  -1      // VS1053 reset pin (unused!)
#define SHIELD_CS     7      // VS1053 chip select pin (output)
#define SHIELD_DCS    6      // VS1053 Data/command select pin (output)
// These are common pins between breakout and shield
#define CARDCS 4     // Card chip select pin
// DREQ should be an Int pin, see http://arduino.cc/en/Reference/attachInterrupt
#define DREQ 3       // VS1053 Data request, ideally an Interrupt pin
Adafruit_VS1053_FilePlayer musicPlayer =
Adafruit_VS1053_FilePlayer(SHIELD_RESET, SHIELD_CS, SHIELD_DCS, DREQ, CARDCS);


void setup() {
  Serial.begin(9600);  //initialize the serial monitor
  
  uint32_t seed = 0;  // Generate random see start
  for ( uint8_t i = 10 ; i ; i-- ) {
    seed = ( seed << 5 ) + ( analogRead( 0 ) * 3 );
  }
  randomSeed( seed );  //set random seed
  
  Serial.println("Adafruit VS1053 Library Test");
  Serial.print("RandomSeed value = ");
  Serial.println(seed);
  // initialise the music player
  if (! musicPlayer.begin()) { // initialise the music player
    Serial.println(F("Couldn't find VS1053, do you have the right pins defined?"));
    while (1);
  }
  Serial.println(F("VS1053 found"));

  if (!SD.begin(CARDCS)) {
    Serial.println(F("SD failed, or not present"));
    while (1);  // don't do anything more
  }

  Serial.println("SD OK!");

  // list files
  printDirectory(SD.open("/"), 0);
  // Set volume for left, right channels. lower numbers == louder volume!
  musicPlayer.setVolume(0, 0);

  if (! musicPlayer.useInterrupt(VS1053_FILEPLAYER_PIN_INT))
    Serial.println(F("DREQ pin is not an interrupt pin"));
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
void loop() {
  // put your main code here, to run repeatedly:
  
  File path = SD.open("/");
  File results;
  char* MP3 = selectRandomFileFrom( path, results );
  delay(100);
  
  // Start playing a file, then we can do stuff while waiting for it to finish
  if (! musicPlayer.startPlayingFile(MP3)) {
    Serial.println("Could not open file: ");
    Serial.println(MP3);
  }

  Serial.print(F("Now playing "));
  Serial.println(MP3);
  while (musicPlayer.playingMusic) {
    delay(250);
    //Serial.print(".");
    //////////////////////////////////////////////////////////////////////////////////////////////////////////
  }

}
////////////////////////////////////////////////////////////////////////////////////////////////////
/// File listing helper
void printDirectory(File dir, int numTabs) {
  while (true) {

    File entry =  dir.openNextFile();
    if (! entry) {
      // no more files
      //Serial.println("**nomorefiles**");
      break;
    }
    for (uint8_t i = 0; i < numTabs; i++) {
      Serial.print('\t');
    }
    Serial.print(entry.name());
    if (entry.isDirectory()) {
      Serial.println("/");
      printDirectory(entry, numTabs + 1);
    } else {
      // files have sizes, directories do not
      Serial.print("\t\t");
      Serial.println(entry.size(), DEC);
    }
    entry.close();
  }
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Function to select random mp3
char* selectRandomFileFrom( File dir, File result ) {
  File entry;
  int count = 0;

  dir.rewindDirectory();

  while ( entry = dir.openNextFile() ) {
    if ( random( count ) == 0 ) {
      result = entry;
    }
    entry.close();
    count++;
  }
  return result.name();   // returns the randomly selected file name
}

marigoldmaripol:
hi there -

i'm currently trying to use this code, but i need to repurpose two functions..i need it to continually randomly play (right now it stops playing after it has randomly scrolled through all of the files) - and i need it to start on a different file each time it starts. i'm even less experienced than the OP, so i'm not sure how to do this, i would greatly appreciate any kind of help.

i modified the previous code to take out all of the LED/servo stuff, so hopefully this will be clearer:

Marigoldmaripol, are you still having the same issues or have you found a solution? If so, I would like to know how you did it as I am trying to do the same thing as you.

HI,

I think I have the same problem, although I don’t understand how to apply the sollutions given in this forum to my problem. I am using an Adafruit VS1053 Music Maker shield with an 8 ohm speaker. I tried using the player_interrupt and player_simple code but both do not work, but in different ways. I am using the VS1053 shield to make an interactive trash bin with an IR sensor, tilt sensor and 4 neopixel rgb strips. I am using an Arduino Uno.

With the player_simple, i get the following serial monitor messages:

adafruit VS1053 simple test
VS1053 found
SYSTEM~1/
WPSETT~1.DAT 12
INDEXE~1 76
TRACK~1.MP3 147165
TRACK~2.MP3 132850
TRACK~3.MP3 95756
Playing track 001
Playing track 002
Done playing music

But no music has played.

With the player_interrupt code, the serial monitor gives me these messages. This is when I upload the file, but haven’t opened the serial monitor yet:

Adafruit VS1053 Library test
VS1053 found

If I already opened the serial monitor, and the code runs a 2nd round, I see more messages(I programmed line of code for the tune as an extra):

Adafruit VS1053 Library Test
VS1053 found
tone played
SD OK!
SYSTEM~1/
WPSETT~1.DAT 12
INDEXE~1 76
TRACK0~1.MP3 147165
TRACK0~2.MP3 132850
TRACK0~3.MP3 95756
Could not open file track001.mp3

I do hear the tune through my headphones. Also through my speaker. ALthough it seams to take longer before they are played through the speaker. So therefore I conclude the board works, jack works, arduino-VS1053 connection works and the connection to the speaker works.

I have 3 tracks on the microSD, called track001.mp3, track002.mp3, track003.mp3.

So these are my questions:

  1. What I am I doing wrong compared to the tutorial provided by adafruit (Play Music | Adafruit Music Maker Shield | Adafruit Learning System) that I set everything up, but it won’t work. (I used the latest libraries)?

  2. Why am I having information returned from the player_simple that the tracks have been played, but from player_interrupt it says it cannot open the track? With both I did not hear any of the tracks, just the tune from the code.

  3. I want to use the IR sensor to activate uneven tracks, the tilt sensor should interrupt the uneven track played and to have it continue with and even number track. How is this achieved most easly?

  4. Is the code in player interrupt supposed to run a 2nd round?

  5. Tips to transfer this to an Arduino Micro? (I need the space that the Micro saves compared to an Uno).

Please, I am only a beginner. I don’t know a lot of terms and I need some explanation. Thank you for any answers!!

player_simple_bin.ino (4.43 KB)

player_interrupts_bin.ino (4.45 KB)