Voting resources, early voting, and poll worker information - VOTE. ... Adafruit is open and shipping.
0

Trying to get "Music Maker" MP3 shield to play random MP3
Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.

Trying to get "Music Maker" MP3 shield to play random MP3

by Aero98 on Sat Sep 27, 2014 5:40 pm

I have been working on this all day and I have not been able to come up with any solution. 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
Code: Select all | TOGGLE FULL SIZE
musicPlayer.startPlayingFile("track001.mp3")
line but I have not been able to get that to work either. Any help anyone could provide would be appreciated.

Thank you,
Jason Krise

Aero98
 
Posts: 9
Joined: Sat Sep 27, 2014 5:30 pm

Re: Trying to get "Music Maker" MP3 shield to play random MP

by franklin97355 on Sat Sep 27, 2014 9:58 pm

Could you post your code and a description or drawing of your connections between it all?
Please use the code button "</>" or [code] tags when posting code to the forums.

franklin97355
 
Posts: 21617
Joined: Mon Apr 21, 2008 2:33 pm
Location: Lacomb, OR.

Re: Trying to get "Music Maker" MP3 shield to play random MP

by Aero98 on Sun Sep 28, 2014 2:17 pm

What I am trying to do is get the Arduino to read the names of the mp3s off of the SD card inserted into the shield and load them into an array. Then once they array contains the list of mp3s I want the code to randomly play one of the mp3s. I have other things I need the card to do in the background while mp3 is playing, which is why I am using the interrupts. Once the mp3 finishes, I want another random mp3 to play and so on and so forth. This is the closest I have gotten to getting this to work, but the return of the SD.Read() function into my int FileNum is 308 instead of 22 (see mp3.txt) and I am just not sure how to even get the data to be written to an array now that I can use since I am not getting the right data return I am looking for.

Code: Select all | TOGGLE FULL SIZE
/***************************************************
  This is an example for the Adafruit VS1053 Codec Breakout

  Designed specifically to work with the Adafruit VS1053 Codec Breakout
  ----> https://www.adafruit.com/products/1381

  Adafruit invests time and resources providing this open source code,
  please support Adafruit and open-source hardware by purchasing
  products from Adafruit!

  Written by Limor Fried/Ladyada for Adafruit Industries.
  BSD license, all text above must be included in any redistribution
 ****************************************************/

// 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);

File MP3s;
int FileNum= 0;
////

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);

  // Look for MP3s.txt, which should contain the full list of MP3s on the SD card
  if (SD.exists("MP3s.txt")) {
    Serial.println("MP3s.txt exists.");
    MP3s = SD.open("MP3s.txt");
    if (MP3s) {
     Serial.println("\n Contents of MP3s.txt:");
     
     // read from the file until there's nothing else in it:
     while (MP3s.available()) {
         FileNum++;
         Serial.write(MP3s.read());
     }
     Serial.print(FileNum);
     Serial.println(" File(s)found");
     // close the file:
     MP3s.close();
   } else {
     // if the file didn't open, print an error:
     Serial.println("error opening test.txt");
   }
 }
  else {
    Serial.println("MP3s.txt doesn't exist.");
    while (1);  // don't do anything more
  }

  // 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() {
  // Start playing a file, then we can do stuff while waiting for it to finish
  if (! musicPlayer.startPlayingFile("track001.mp3")) {
    Serial.println("Could not open file track001.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();
  }
}

MP3s.txt
(307 Bytes) Downloaded 256 times


I am not sure if there is a better way to do it, use a txt file that is. I might accidently have other files on the SD card I wouldn't want loaded, or I might have MP3s grouped by type.. (I.E. Christmas###.mp3, Halloween###.mp3, Vocal###.mp3, etc.) that I would want to play based on a set of rules.

Aero98
 
Posts: 9
Joined: Sat Sep 27, 2014 5:30 pm

Re: Trying to get "Music Maker" MP3 shield to play random MP

by adafruit_support_mike on Mon Sep 29, 2014 2:58 am

The routine that reads your text file reads one byte at a time. You're getting a 308 because there are 307 bytes in the file.

To read the file into an array you'd need to scan the bytes as you read them and decide where each filename begins. That's possible, but there's an easier way to select a random file.

Start by putting all the files you want in your option pool into a single directory, then use this routine to select one at random:

Code: Select all | TOGGLE FULL SIZE
    void playRandomFileIn( File dir ) {
        File entry, result;
        int count = 1;
   
        dir.rewindDirectory();
       
        while ( entry = dir.openNextFile() ) {
            if ( random( count ) == 0 ) {
                if ( result ) {
                    result.close();
                }
                result = entry;
            } else {
                entry.close();
            }
            count++;
        }
        //  play result
    }

The Arduino's random() function returns an integer between zero and the limit you provide as a parameter. The chance of getting a zero is 1/N where N is the limit.

When N=1, the result is guaranteed to be zero, so the first file in the directory will always be selected. There's a 50% chance of the result being zero when N=2, so if there are only two files in the directory there's a 50-50 chance that either one will be selected. As the count increases, each new item has a 1/N chance of replacing the previous selection, so each item gets an equal chance of being the one that finally makes it to the end.

It's a nice routine to have in the bag of tricks because you don't have to know how many items are in the set before you start choosing them.

adafruit_support_mike
 
Posts: 61443
Joined: Thu Feb 11, 2010 2:51 pm

Re: Trying to get "Music Maker" MP3 shield to play random MP

by adafruit_support_mike on Mon Sep 29, 2014 3:00 am

BTW - be careful with your filenames when you use the SD library. Its internal buffer only holds a single 8.3 filename. Names like Halloween###.mp3 will be too long for it.

adafruit_support_mike
 
Posts: 61443
Joined: Thu Feb 11, 2010 2:51 pm

Re: Trying to get "Music Maker" MP3 shield to play random MP

by Aero98 on Mon Sep 29, 2014 8:32 pm

Ok, I must be doing something wrong, I think I have entered the code correctly, but result is always 1 and entry is always 0.

Code: Select all | TOGGLE FULL SIZE
/***************************************************
  This is an example for the Adafruit VS1053 Codec Breakout

  Designed specifically to work with the Adafruit VS1053 Codec Breakout
  ----> https://www.adafruit.com/products/1381

  Adafruit invests time and resources providing this open source code,
  please support Adafruit and open-source hardware by purchasing
  products from Adafruit!

  Written by Limor Fried/Ladyada for Adafruit Industries.
  BSD license, all text above must be included in any redistribution
 ****************************************************/

// 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);

File MP3s;
////

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() {
  // Get Random file from SD card
  playRandomFileIn(SD.open("/"));

  // Start playing a file, then we can do stuff while waiting for it to finish
  if (! musicPlayer.startPlayingFile("track001.mp3")) {
    Serial.println("Could not open file track001.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();
  }
}

void playRandomFileIn( File dir ) {
  File entry, result;
  int count = 1;

  dir.rewindDirectory();

  while ( entry = dir.openNextFile() ) {
    if ( random( count ) == 0 ) {
      if ( result ) {
        result.close();
      }
      result = entry;
    } else {
      entry.close();
    }
    count++;
  }
  //  play result
  Serial.println(result);
  Serial.println(entry);
}


Serial Results:
Code: Select all | TOGGLE FULL SIZE
Adafruit VS1053 Library Test
VS1053 found
SD OK!
SYSTEM~1/
   INDEXE~1      76
TRACK001.MP3      4138978
TRACK002.MP3      4987930
TRACK003.MP3      15151
TRACK004.MP3      3516948
TRACK005.MP3      1781985
TRACK006.MP3      42213
TRACK007.MP3      100800
TRACK008.MP3      1130536
TRACK009.MP3      905007
TRACK010.MP3      1597466
TRACK011.MP3      131200
TRACK012.MP3      1846777
TRACK013.MP3      2065368
TRACK014.MP3      656431
TRACK015.MP3      695293
TRACK016.MP3      1704259
TRACK017.MP3      3076003
TRACK018.MP3      6922892
TRACK019.MP3      9663114
TRACK020.MP3      644682
TRACK021.MP3      9981632
TRACK022.MP3      5120768
MP3S.TXT      308
1
0
Started playing
.................................
Done playing music
1
0
Started playing
..............................
Done playing music


I've looked online at a few things but I am missing something obviously.

Aero98
 
Posts: 9
Joined: Sat Sep 27, 2014 5:30 pm

Re: Trying to get "Music Maker" MP3 shield to play random MP

by Aero98 on Mon Sep 29, 2014 8:32 pm

Ok, I must be doing something wrong, I think I have entered the code correctly, but result is always 1 and entry is always 0.

Code: Select all | TOGGLE FULL SIZE
/***************************************************
  This is an example for the Adafruit VS1053 Codec Breakout

  Designed specifically to work with the Adafruit VS1053 Codec Breakout
  ----> https://www.adafruit.com/products/1381

  Adafruit invests time and resources providing this open source code,
  please support Adafruit and open-source hardware by purchasing
  products from Adafruit!

  Written by Limor Fried/Ladyada for Adafruit Industries.
  BSD license, all text above must be included in any redistribution
 ****************************************************/

// 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);

File MP3s;
////

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() {
  // Get Random file from SD card
  playRandomFileIn(SD.open("/"));

  // Start playing a file, then we can do stuff while waiting for it to finish
  if (! musicPlayer.startPlayingFile("track001.mp3")) {
    Serial.println("Could not open file track001.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();
  }
}

void playRandomFileIn( File dir ) {
  File entry, result;
  int count = 1;

  dir.rewindDirectory();

  while ( entry = dir.openNextFile() ) {
    if ( random( count ) == 0 ) {
      if ( result ) {
        result.close();
      }
      result = entry;
    } else {
      entry.close();
    }
    count++;
  }
  //  play result
  Serial.println(result);
  Serial.println(entry);
}


Serial Results:
Code: Select all | TOGGLE FULL SIZE
Adafruit VS1053 Library Test
VS1053 found
SD OK!
SYSTEM~1/
   INDEXE~1      76
TRACK001.MP3      4138978
TRACK002.MP3      4987930
TRACK003.MP3      15151
TRACK004.MP3      3516948
TRACK005.MP3      1781985
TRACK006.MP3      42213
TRACK007.MP3      100800
TRACK008.MP3      1130536
TRACK009.MP3      905007
TRACK010.MP3      1597466
TRACK011.MP3      131200
TRACK012.MP3      1846777
TRACK013.MP3      2065368
TRACK014.MP3      656431
TRACK015.MP3      695293
TRACK016.MP3      1704259
TRACK017.MP3      3076003
TRACK018.MP3      6922892
TRACK019.MP3      9663114
TRACK020.MP3      644682
TRACK021.MP3      9981632
TRACK022.MP3      5120768
MP3S.TXT      308
1
0
Started playing
.................................
Done playing music
1
0
Started playing
..............................
Done playing music


I've looked online at a few things but I am missing something obviously.

Aero98
 
Posts: 9
Joined: Sat Sep 27, 2014 5:30 pm

Re: Trying to get "Music Maker" MP3 shield to play random MP

by adafruit_support_mike on Tue Sep 30, 2014 1:37 am

'result' and 'entry' are File objects, so it looks like Serial.print() is treating them as boolean "is this variable defined" values when converting them to strings. If you want their names, you need:

Code: Select all | TOGGLE FULL SIZE
  Serial.println( result.name() );
  Serial.println( entry.name() );

I'm not surprised to see 'entry' being rendered as '0' because the loop calls:

Code: Select all | TOGGLE FULL SIZE
    entry.close();

any time the value in 'entry' isn't copied to 'result'. As a matter of fact, you can probably drop that condition and just close 'entry' every time.

If you want to see the selection process at work, try this:

Code: Select all | TOGGLE FULL SIZE
void playRandomFileIn( File dir ) {
  File entry, result;
  int count = 1;

  dir.rewindDirectory();

  while ( entry = dir.openNextFile() ) {
    Serial.print("looking at ");
    Serial.print( entry.name() );
   
    if ( random( count ) == 0 ) {
      if ( result ) {
        result.close();
      }
      result = entry;
    }
    entry.close();
    count++;

    Serial.print(" -- selected ");
    Serial.println( result.name() );
  }
  //  play result
}

adafruit_support_mike
 
Posts: 61443
Joined: Thu Feb 11, 2010 2:51 pm

Re: Trying to get "Music Maker" MP3 shield to play random MP

by Aero98 on Tue Sep 30, 2014 8:02 pm

Fist off, let me take a moment to say thank you for all of your help. I did not realize just what a task it was going to be to play a random mp3 file; so, thank you for your help. I have played around with code and have gotten further but I am running into a couple of hang ups.

1.The same track is selected every time
2.Once a track is selected the name of the file getting passed id TRA m not TRACK018.MP3

Here is my code
Code: Select all | TOGGLE FULL SIZE
/***************************************************
  This is an example for the Adafruit VS1053 Codec Breakout

  Designed specifically to work with the Adafruit VS1053 Codec Breakout
  ----> https://www.adafruit.com/products/1381

  Adafruit invests time and resources providing this open source code,
  please support Adafruit and open-source hardware by purchasing
  products from Adafruit!

  Written by Limor Fried/Ladyada for Adafruit Industries.
  BSD license, all text above must be included in any redistribution
 ****************************************************/
/*
// http://playground.arduino.cc/ComponentLib/Servo
// http://forum.arduino.cc/index.php?topic=146230.0
// http://rcarduino.blogspot.com/2012/01/can-i-control-more-than-x-servos-with.html
// http://arduino.cc/en/Tutorial/SecretsOfArduinoPWM
// http://itp.nyu.edu/physcomp/Tutorials/HighCurrentLoads
// https://learn.adafruit.com/adafruit-motor-shield
*/

// 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);

////

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() {
  // Get Random file from SD card
  char* MP3 = playRandomFileIn(SD.open("/"));
  Serial.print("File selected is:" );
  Serial.println(MP3);
  // Start playing a file, then we can do stuff while waiting for it to finish
  if (! musicPlayer.startPlayingFile( MP3 )) {  //Play random file selected from function playRandomFileIn above
    Serial.print("Could not open file");
    Serial.println( MP3 ); // If the file above cannot be found or loaded, display error
    while (1); //If we failed to play the file, stop
  }
  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();
  }
}

char* playRandomFileIn( File dir ) {
  File entry, result;  //Initiate entry and results
  int count = 1;   //Initiate count as an integer and set the value to 1

  dir.rewindDirectory();   //reset back to the first file in the directory, used in conjunction with openNextFile().

  while ( entry = dir.openNextFile() ) {
    Serial.print("looking at ");
    Serial.print( entry.name() );

    if ( random( count ) == 0 ) {
      if ( result ) {
        result.close();
      }
      result = entry;
    }
    entry.close();
    count++;      //Increases the value of count by 1

    Serial.print(" -- selected ");   //Prints  -- selected to the serial monitor and does not create a new line
    Serial.println( result.name() );  //appends the name of the selected file stored in result.name() to the end of the current line in the serial monitor and then creates a new line
  }
  //  play result
    char* results = result.name();
    return results;
}

and here are the serial results
Code: Select all | TOGGLE FULL SIZE
Adafruit VS1053 Library Test
VS1053 found
SD OK!
looking at SYSTEM~1 -- selected
looking at TRACK001.MP3 -- selected
looking at TRACK002.MP3 -- selected
looking at TRACK003.MP3 -- selected
looking at TRACK004.MP3 -- selected
looking at TRACK005.MP3 -- selected
looking at TRACK006.MP3 -- selected
looking at TRACK007.MP3 -- selected
looking at TRACK008.MP3 -- selected
looking at TRACK009.MP3 -- selected
looking at TRACK010.MP3 -- selected
looking at TRACK011.MP3 -- selected
looking at TRACK012.MP3 -- selected TRACK012.MP3
looking at TRACK013.MP3 -- selected TRACK012.MP3
looking at TRACK014.MP3 -- selected TRACK012.MP3
looking at TRACK015.MP3 -- selected TRACK012.MP3
looking at TRACK016.MP3 -- selected TRACK012.MP3
looking at TRACK017.MP3 -- selected TRACK012.MP3
looking at TRACK018.MP3 -- selected TRACK018.MP3
looking at TRACK019.MP3 -- selected TRACK018.MP3
looking at TRACK020.MP3 -- selected TRACK018.MP3
looking at TRACK021.MP3 -- selected TRACK018.MP3
looking at TRACK022.MP3 -- selected TRACK018.MP3
looking at MP3S.TXT -- selected TRACK018.MP3
File selected is:TRA  m   
Could not open file


I thought maybe the issue was caused by passing the File result.name() to something that appears to want char*, so I changed the code around a little to compensate for it, but it still is not working. I know there are some servo references and links at the top, have some things I need to implement later, just getting ready.

Aero98
 
Posts: 9
Joined: Sat Sep 27, 2014 5:30 pm

Re: Trying to get "Music Maker" MP3 shield to play random MP

by adafruit_support_mike on Wed Oct 01, 2014 1:45 am

What you have now is a scope problem.

The chunk of data storage that holds the name of the file belongs to the object named 'result' which is defined inside the function 'playRandomFileIn()'. The memory for that object is allocated as soon as execution enters the function, and is released as soon as execution leaves the function.

This line:

Code: Select all | TOGGLE FULL SIZE
    char* results = result.name();

puts the address of the data storage associated with the name string into the variable 'results'.

When you leave the function and the storage is released, that address no longer points to meaningful data, so your return value is "where the name used to be stored but isn't any more".

If you want to return the name of the selected file, you have to write it into storage locations that were defined before execution enters 'playRandomFileIn()', and you have to pass information about that location into the function as a parameter:

Code: Select all | TOGGLE FULL SIZE
char* doesNotWork() {
    char storage[] = "this string will go away";
    return( storage );
}

void doesWorkOn( char* str ) {
    char storage[] = "this string will be copied";
   
    char* ptr = storage;
    while ( *ptr ) {
        *str = *ptr;  // copy one character at a time
        str++;
        ptr++;
    }
    *str = 0;
   
    return;
}

void wantsAstring() {
    char buffer[ 64 ];
   
    char* str = doesNotWork();
    Serial.println( str );  // probably prints garbage
   
    doesWorkOn( buffer );
    Serial.println( buffer );  // prints what you expect
}

If you want to turn 'platRandomFileIn()' to 'selectRandomFileFrom()', you'd want something like this:

Code: Select all | TOGGLE FULL SIZE
void 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++;
  }
}

adafruit_support_mike
 
Posts: 61443
Joined: Thu Feb 11, 2010 2:51 pm

Re: Trying to get "Music Maker" MP3 shield to play random MP

by Aero98 on Wed Oct 01, 2014 9:00 pm

I don't know, I guess I just don't get it. 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.

Code: Select all | TOGGLE FULL SIZE
// 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++;
  }
}

Aero98
 
Posts: 9
Joined: Sat Sep 27, 2014 5:30 pm

Re: Trying to get "Music Maker" MP3 shield to play random MP

by adafruit_support_mike on Wed Oct 01, 2014 11:08 pm

Let's isolate the pieces that aren't working..

The line that's supposed to play the file is this one:

Code: Select all | TOGGLE FULL SIZE
  if (! musicPlayer.startPlayingFile(MP3)) {

For that to work, the variable 'MP3' needs to point to the name of a file.

The line where you assign a value to 'MP3' is this one:

Code: Select all | TOGGLE FULL SIZE
  char* MP3 = selectRandomFileFrom( path, results );

So.. where's the line that sets the return value of 'selectRandomFileFrom()' to point to the name of a file?

adafruit_support_mike
 
Posts: 61443
Joined: Thu Feb 11, 2010 2:51 pm

Re: Trying to get "Music Maker" MP3 shield to play random MP

by Aero98 on Fri Oct 03, 2014 9:55 am

I swear I made a reply last night with an update, but it has apparently disappeared. I was able to get the code to work by adding a return to the function and it plays now. The weird part is that is always pick the files in the same order, they are not in numerical order, but they play in the same order every single time.

Code: Select all | TOGGLE FULL SIZE
// 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
}


Is there a reason why it always plays the files in the same order? I unplugged and replugged in the card and used the reset button a few times and the results were always the same, the files picked by the random function are always picked in the same order.

Also, if it is not too much to ask, is there a way I can make sure that only MP3,WAV, or OGG files are picked and not a txt or other file format?

Aero98
 
Posts: 9
Joined: Sat Sep 27, 2014 5:30 pm

Re: Trying to get "Music Maker" MP3 shield to play random MP

by adafruit_support_mike on Fri Oct 03, 2014 7:09 pm

The sequence repeats because it's technically impossible to generate true random numbers with a computer program.

Computers are 'deterministic', which means that if you feed them the same input they'll produce the same output every time. The Arduino starts in the same state every time, so the random number routine starts with the same values every time, and that gives you the same sequence every time.

To get a different sequence every time, you need some kind of input that changes. The traditional way to get that kind of value is to read an unconnected analog pin, but those results aren't all that great. You can improve them by mashing several readings together in your setup() function:

Code: Select all | TOGGLE FULL SIZE
    uint32_t seed = 0;
   
    for ( uint8_t i=10 ; i ; i-- ) {
        seed = ( seed << 5 ) + ( analogRead( 0 ) * 3 );
    }
    randomSeed( seed );

Matching file extensions is possible, but requires quite a bit of code, especially if you want to match several extensions and want to allow filenames to be different lengths.

It's much easier to just make sure all the files in the directory are ones you want to play.

adafruit_support_mike
 
Posts: 61443
Joined: Thu Feb 11, 2010 2:51 pm

Re: Trying to get "Music Maker" MP3 shield to play random MP

by Aero98 on Sun Oct 05, 2014 2:34 pm

Thanks for all of the help. he is my basically finalized code.

Code: Select all | TOGGLE FULL SIZE
/*
http://www.instructables.com/id/Serial-Servo-Controller-wAduino-Control-Up-To-1/?ALLSTEPS
http://www.slideshare.net/MsWillcox/event-driven-programming-amazeballs
http://learn.adafruit.com/adafruit-arduino-lesson-14-servo-motors/the-breadboard-layout-for-sweep
http://forums.adafruit.com/viewtopic.php?f=25&t=38740
*/
// 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
}

Aero98
 
Posts: 9
Joined: Sat Sep 27, 2014 5:30 pm

Please be positive and constructive with your questions and comments.