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

Adafruit Ethernet, Motor, Proto, Wave, Datalogger, GPS Shields - etc!

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
User avatar
adafruit_support_mike
 
Posts: 67446
Joined: Thu Feb 11, 2010 2:51 pm

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

Post by adafruit_support_mike »

Glad to hear you have it working. Happy hacking! ;-)

User avatar
haybear
 
Posts: 2
Joined: Sun Jul 07, 2013 5:16 pm

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

Post by haybear »

Hmmm, seems like the Music Maker Library needs a function similar to the that you can use with the Sparkfun MP3 Shield's "MP3player.playTrack(X);"

I just picked these shields up for a project and really like them, but was surprised I couldn't tell it to play a track by number... I guess the trade off is that you can call the tracks anything you like.

User avatar
adafruit_support_mike
 
Posts: 67446
Joined: Thu Feb 11, 2010 2:51 pm

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

Post by adafruit_support_mike »

That's the beauty of Open Source.. you can tweak the library to do whatever you want.

That should be a fairly simple wrapper function.. take a number as a parameter, turn it into a complete filename, then pass that to .startPlaying() or .playFullFile().

User avatar
tertiumquid
 
Posts: 1
Joined: Fri Feb 14, 2014 11:58 am

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

Post by tertiumquid »

Thanks for posting this, it was extremely helpful for my project (http://www.thingswemake.com/psl-modem/).

One note. Using a variant of your code, I wound up with a big memory leak. I resolved this by making

Code: Select all

File path
a global variable, rather than instantiating it each time through the loop. Instead, I call

Code: Select all

path = SD.open("/");
each time through the loop to avoid the leak.

User avatar
haybear
 
Posts: 2
Joined: Sun Jul 07, 2013 5:16 pm

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

Post by haybear »

Thanks for pointing that out, Mike. I will try my hand at it. I am not the best coder, and depend on the hard work of others... a lot!

All that said, this code ended up helping me create a little random song playing MP3 player wrapped in an old Realist WeatheRadio, and for that I am very grateful.

Also, that Music Make board is AWESOME!!! The built in amp option is clutch and the price is great. Adafruit's got some real standout items. Keep it up! Please!!!

User avatar
ndnbolla
 
Posts: 31
Joined: Tue Mar 31, 2015 11:17 am

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

Post by ndnbolla »

I am trying to implement random mp3 file playing into my code using the techniques discussed in this thread however it is unable to compile.

I end up with the error:

Code: Select all

Casptone_Program_Loop_Works.ino: In function 'char* selectRandomFileFrom(File, File)':
Casptone_Program_Loop_Works:513: error: [b]invalid conversion from 'const char*' to 'char*' [-fpermissive][/b]
invalid conversion from 'const char*' to 'char*' [-fpermissive]
How were you guys able to compile, I tried using the exact same code but to no avail.

The following is my code:

Code: Select all

#include <UTFT.h>
#include <UTouch.h>
#include <UTFT_Buttons.h>
#include <SPI.h>
#include <UTFT_SdRaw.h>
#include <SdFat.h>
#include <Adafruit_VS1053.h>
#include <DueFlashStorage.h>

// #include <SD.h>

UTFT          display_LCD(EHOUSE70, 22, 23, 31, 33);
UTouch        touch(25, 26, 27, 29, 30);
UTFT_Buttons  button(&display_LCD, &touch);
UTFT_SdRaw    sd_Files(&display_LCD);

#define BREAKOUT_RESET  9      // VS1053 reset pin (output)
#define BREAKOUT_CS     10     // VS1053 chip select pin (output)
#define BREAKOUT_DCS    8      // VS1053 Data/command select pin (output)
// #define CARDCS 4               // Card chip select pin
#define DREQ 3                 // VS1053 Data request, ideally an Interrupt pin
#define mosipin 11
#define misopin 12
#define clkpin 13

DueFlashStorage dueFlashStorage;    //Memory Storage

// SD chip select pin
const uint8_t chipSelect = 42;

//Push Button Setup

const int p_button = 2;     // the number of the pushbutton pin

uint8_t debounceRead(int pin)
{
  uint8_t pinState = digitalRead(pin);
  uint32_t timeout = millis();
  while (millis() < timeout+10)
  {
    if (digitalRead(pin) != pinState)
    {
      pinState = digitalRead(pin);
      timeout = millis();
    }
  }

  return pinState;
}

boolean pressed = HIGH;
boolean played = 0;
unsigned char count=0;

// file system
SdFat sd;

Adafruit_VS1053_FilePlayer musicPlayer = 
   Adafruit_VS1053_FilePlayer(mosipin, misopin, clkpin, BREAKOUT_RESET, BREAKOUT_CS, BREAKOUT_DCS, DREQ, chipSelect);  // create breakout-example object!
  
extern unsigned short bw_logo[3100];
extern unsigned short uml_logo[7040];
extern uint8_t SmallFont[];
extern uint8_t BigFont[];
extern uint8_t SevenSegNumFont[];
extern uint8_t Dingbats1_XL[];
extern uint8_t arial_bold[];

int more_b, less_b, start_b, set_b, enter, pressed_button;
int buf[798];
int g, prev_g, f, prev_f = 0;
int x, y, w, l;
int X, Y;

uint8_t counter = 3;

void setup()
{
  // Setup the LCD
  display_LCD.InitLCD();
  display_LCD.setFont(BigFont);
  display_LCD.clrScr();
  display_LCD.fillScr(255, 255, 255); //Fill screen with white color

 // initialize the pushbutton pin as an input:
 // pinMode(buttonPin, INPUT);
 
 pinMode(p_button, INPUT_PULLUP);
 digitalWrite(p_button, HIGH);

  Serial.begin(9600);

    while (!Serial) {
    ; // wait for serial port to connect. Needed for DUE & Leonardo only
  }
  counter = constrain(counter, 1, 10);
  Serial.println(F("Initialising SD card..."));
  bool mysd = 0;
  // see if the card is present and can be initialized:
  while (!mysd)
  {
    if (!sd.begin(chipSelect, SPI_FULL_SPEED)) {
      Serial.println(F("Card failed, or not present"));
      Serial.println(F("Retrying...."));
    }
    else
    {
      mysd = 1;
      Serial.println(F("Card initialised."));
    }
  }

  // initialise the music player
  if (! musicPlayer.begin()) {
    Serial.println(F("Couldn't find VS1053!"));
  }
  else
  {
    Serial.println(F("VS1053 found"));
  }
//  
//  if (!sd.begin(CARDCS)) // initialize the SD card
//  {
//    Serial.println(F("SD failed, or not present"));
//  }
//  else
//  {
//    Serial.println(F("SD OK"));
//  }
  if (!musicPlayer.useInterrupt(VS1053_FILEPLAYER_PIN_INT)) { // DREQ int
    Serial.println(F("DREQ Pin problem"));
  }
 
  // Set volume for left, right channels. lower numbers == louder volume!
  musicPlayer.setVolume(30,30);
 
  touch.InitTouch();
  touch.setPrecision(PREC_EXTREME);

  button.setTextFont(arial_bold);
  button.setSymbolFont(Dingbats1_XL);

[b]  uint32_t seed = 0;  // Generate random seed start
  for ( uint8_t i = 10 ; i ; i-- ) {
    seed = ( seed << 5 ) + ( analogRead( 0 ) * 3 );
  }
  randomSeed( seed );  //set random seed[/b]
}

void loop()
{
display_LCD.clrScr();
button.deleteAllButtons();
// MainMenu();
MainProgram();
}

void MainMenu()
{
    button.deleteAllButtons();
  display_LCD.clrScr();
  display_LCD.fillScr(255, 255, 255); //Fill screen with white color
  
  // Make a Main Menu Title Bar
  display_buttons(0, 0, 799, 50, 20, 40, 140);
  display_LCD.setFont(BigFont);
  display_LCD.setBackColor(20, 40, 140);
  display_LCD.setColor(255, 255, 255);
  display_LCD.print("MAIN MENU", CENTER, 15);

  //Display text asking how to continue
  display_LCD.setFont(SmallFont);
  display_LCD.setBackColor(255, 255, 255);
  display_LCD.setColor(0, 0, 0);
  display_LCD.print("How would you like to continue?", 100, 100);

  start_b = button.addButton(150, 120, 500, 50, "Begin messaging");
  set_b = button.addButton(150, 200, 500, 50, "Change settings");
  button.setButtonColors(VGA_WHITE, VGA_GRAY, VGA_WHITE, VGA_RED, VGA_NAVY);
  button.drawButtons();

  //Display text telling battery percentage
  display_LCD.setFont(SmallFont);
  display_LCD.setBackColor(255, 255, 255);
  display_LCD.setColor(0, 0, 0);
  display_LCD.print("Battery Remaining", CENTER, 380);
  display_LCD.print("100%", CENTER, 420);

  while(1)
  {
    if (touch.dataAvailable() == true)
    {
      pressed_button = button.checkButtons();

      if (pressed_button == start_b)
      {
        MainProgram();
        loop();
        }
      if (pressed_button == set_b)
      {
        SettingsPage();
      }
    }
  }
}

void check(unsigned char num)
{
  count = 0;
  played = 0;
  while(count<(counter*10))    //delay of 10 second with the checking of input
  {
    pressed = digitalRead(p_button);
    delay(100);
    if((pressed==LOW)&&(played==0))  //the button is pressed
    {
      switch(num)
      {
        case 1:
        musicPlayer.playFullFile("talk.mp3");
        break;
      case 2:
        musicPlayer.playFullFile("hungry.mp3");
        break;
      case 3:
        musicPlayer.playFullFile("thirsty.mp3");
        break;
      case 4:
        musicPlayer.playFullFile("bathroom.mp3");
        break;
      case 5:
        musicPlayer.playFullFile("clean.mp3");
        break;
      case 6:
        musicPlayer.playFullFile("sick.mp3");
        break;
      case 7:
        musicPlayer.playFullFile("wheelc.mp3");
          break;
          case 8:
        musicPlayer.stopPlaying();
        break;
        default:
          break;
      }
      played = 1;
    }
    else if (touch.dataAvailable() == true)
    {
      pressed_button = button.checkButtons();
      if (pressed_button == set_b)
      {
        SettingsPage();
      }
    }
    count++;
  }
  pressed = HIGH; 
}

void MainProgram()
{
   button.deleteAllButtons();
  display_LCD.clrScr(); // clear the screen
  display_LCD.setColor(255, 255, 255);
  int mytime1 = millis();
  int ret1 = sd_Files.load(0, 0, 800, 480, "talk.raw", 16);
  Serial.println(millis() - mytime1);
  Serial.println(ret1);
  set_b = button.addButton(599, 0, 200, 50, "SETTINGS");
  button.setButtonColors(VGA_WHITE, VGA_GRAY, VGA_WHITE, VGA_RED, VGA_NAVY);
  button.drawButtons();
  check(1);

//    display_LCD.clrScr(); // clear the screen
//          display_LCD.setColor(255, 255, 255);
//  int mytime2 = millis();
//  int ret2 = sd_Files.load(0, 0, 800, 480, "hungry.raw", 16);
//  Serial.println(millis() - mytime2);
//  Serial.println(ret2);
//  check(2);
//
//    display_LCD.clrScr(); // clear the screen
//          display_LCD.setColor(255, 255, 255);
//  int mytime3 = millis();
//  int ret3 = sd_Files.load(0, 0, 800, 480, "thirsty.raw", 16);
//  Serial.println(millis() - mytime3);
//  Serial.println(ret3);
//  check(3);
//
//      display_LCD.clrScr(); // clear the screen
//          display_LCD.setColor(255, 255, 255);
//  int mytime4 = millis();
//  int ret4 = sd_Files.load(0, 0, 800, 480, "bathroom.raw", 16);
//  Serial.println(millis() - mytime4);
//  Serial.println(ret4);
//  check(4);
//
//  display_LCD.clrScr(); // clear the screen
//          display_LCD.setColor(255, 255, 255);
//  int mytime5 = millis();
//  int ret5 = sd_Files.load(0, 0, 800, 480, "clean.raw", 16);
//  Serial.println(millis() - mytime5);
//  Serial.println(ret5);
//  check(5);
//
//  display_LCD.clrScr(); // clear the screen
//          display_LCD.setColor(255, 255, 255);
//  int mytime6= millis();
//  int ret6 = sd_Files.load(0, 0, 800, 480, "sick.raw", 16);
//  Serial.println(millis() - mytime6);
//  Serial.println(ret6);
//  check(6);
//
//  display_LCD.clrScr(); // clear the screen
//  display_LCD.setColor(255, 255, 255);
//  int mytime7 = millis();
//  int ret7 = sd_Files.load(0, 0, 800, 480, "wheelc.raw", 16);
//  Serial.println(millis() - mytime7);
//  Serial.println(ret7);
//  check(7);

  //all 7 pictures are shown
  //now show the picture for audio
  display_LCD.clrScr(); // clear the screen
  display_LCD.setColor(255, 255, 255);
  int mytime8 = millis();
  int ret8 = sd_Files.load(0, 0, 800, 480, "picmusic.raw", 16);
  Serial.println(millis() - mytime8);
  Serial.println(ret8);

[b]//////////////////////////////////////////////////////////////////////////////////////////////  
  count = 0;
  played = 0;

  while(count<counter*10)    //delay of some selected time delay with the checking of input
  {
    pressed = debounceRead(p_button);
    delay(100);
    if (pressed == LOW)  //the button is pressed
    { File path = sd.open("MUSIC/");
    File results;
char* MP3 = selectRandomFileFrom( path, results );
    delay(250);                                            // Delay is necessary for good operation
      
  if (! musicPlayer.startPlayingFile(MP3)) {
    Serial.println("Could not open file track001.mp3");
    while (1);
  }
  Serial.println(F("Started playing"));

  while (musicPlayer.playingMusic) {
    check(8);  
  }
// file is now playing in the 'background' so now's a good time
// to do something else like handling LEDs or buttons :)
//    
//    Serial.print(".");
//    if (Serial.available()) {
//    char c = Serial.read();
//    
//    // if we get an 's' on the serial console, stop!
//    pressed = debounceRead(p_button);
//    delay(100);
//    if (c == 's') {
//    if (pressed==LOW) {
//      musicPlayer.stopPlaying();
//    }
//    delay(1000);
//  }
//  Serial.println("Done playing music");
//  
//}
    }
    count++;
  }
}
/////////////////////////////////////////////////////////////////////////////////////////////
[/b]
void SettingsPage()
{
  button.deleteAllButtons();
  display_LCD.clrScr();
  display_LCD.fillScr(255, 255, 255); //Fill screen with white color
  display_LCD.setFont(BigFont);
  
  // Make a Settings Title Bar
  display_buttons(0, 0, 799, 50, 20, 40, 140);
  display_LCD.setBackColor(20, 40, 140);
  display_LCD.setColor(255, 255, 255);
  display_LCD.print("SETTINGS", CENTER, 15);

  //Display text asking how long
  display_LCD.setFont(SmallFont);
  display_LCD.setBackColor(255, 255, 255);
  display_LCD.setColor(0, 0, 0);
  display_LCD.print("How long would you like images to be displayed on screen for?", CENTER, 125);

  //Create '+' Button
  int w1 = 80;
  button.setButtonColors(VGA_WHITE, VGA_GRAY, VGA_WHITE, VGA_RED, VGA_GREEN);
  more_b = button.addButton(533, 150, w1, 48, "+");   //(X, Y, W, H, "")  
  button.drawButton(more_b);

  //Create '-' Button
  button.setButtonColors(VGA_WHITE, VGA_GRAY, VGA_WHITE, VGA_RED, VGA_RED);
  less_b = button.addButton(267 - w1, 150, w1, 48, "-");
  button.drawButton(less_b);

  //Seconds Counter & Label
  display_LCD.setFont(SevenSegNumFont);
  display_LCD.printNumI(counter, CENTER, 150, 2, '0');
  display_LCD.setFont(SmallFont);
  display_LCD.print("SECONDS", CENTER, 200);

  //Main Menu Button
  button.setButtonColors(VGA_WHITE, VGA_GRAY, VGA_WHITE, VGA_RED, VGA_NAVY);
  int w2 = 320;
  enter = button.addButton(400 - w2 / 2, 320, w2, 48, "Return to Main Menu");
  button.drawButton(enter);

  //Display Bridgewell Logo
//  display_LCD.drawBitmap(10, 429, 100, 31, bw_logo, 1);
  //Display UML Logo
//  display_LCD.drawBitmap(611, 390, 88, 80, uml_logo, 1);

  while(1)
  {
    if (touch.dataAvailable() == true)
    {
      pressed_button = button.checkButtons();
       
    if (pressed_button==more_b)
      {
              counter = counter + 1;
              counter = constrain(counter, 1, 10);
              display_LCD.setFont(SevenSegNumFont);
              display_LCD.printNumI(counter, CENTER, 150, 2, '0');
      }
    if (pressed_button==less_b)
      {
            counter = counter - 1;
            counter = constrain(counter, 1, 10);
            display_LCD.setFont(SevenSegNumFont);
            display_LCD.printNumI(counter, CENTER, 150, 2, '0');
        }
      }
     else if (pressed_button==enter)
      {
        button.deleteAllButtons();
//        dueFlashStorage.write(1, counter);
        MainMenu();
      }
    }
  }
  
void display_buttons(int x, int y, int w, int l, int R, int G, int B)
{
  display_LCD.setColor(R, G, B);
  display_LCD.fillRect(x, y, w, l);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
[b]// Function to select random mp3
char* selectRandomFileFrom( File dir, File result)
{
  File entry;
  int rcount = 0;
  dir.rewindDirectory();
  while ( entry = dir.openNextFile() ) 
  {
    if ( random( rcount ) == 0 ) 
    {
      result = entry;
    }
    entry.close();
    rcount++;
  }
  return result.name();   // returns the randomly selected file name

}[/b]
//////////////////////////////////////////////////////////////////////////////////////////////

User avatar
michaelw3
 
Posts: 69
Joined: Sun Mar 10, 2013 6:58 pm

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

Post by michaelw3 »

In case it is helpful to other people searching for a solution for playing random files off this board, I've taken the code that was reported to work (without adding the memory leak fix) and cut out all of the stuff that has to do with the servos. So this is just the code to randomly play the files off the card.

Code: Select all

/*
adapted from https://forums.adafruit.com/viewtopic.php?f=31&t=60742
*/
// 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 =
  // create shield-exmaple object!
  Adafruit_VS1053_FilePlayer(SHIELD_RESET, SHIELD_CS, SHIELD_DCS, DREQ, CARDCS);
//////////////////////////////////////////////////////////////////////////////////////////////////////
//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);  
  
  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(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 );
  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);
  }

  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(".");
    //////////////////////////////////////////////////////////////////////////////////////////////////////////
  }
  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
}

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



User avatar
Marby
 
Posts: 12
Joined: Fri Mar 17, 2017 11:19 am

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

Post by Marby »

Awesome! Even years later!
I'm so happy that you put the complete working code in this threat; I think its really important & helpful to do so!

User avatar
jim_lee
 
Posts: 709
Joined: Thu May 24, 2012 8:24 pm

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

Post by jim_lee »

adafruit_support_mike wrote: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

    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

That's a really neat trick! Never in 1,000 years would I have come up with something like that! I was thinking I wanted to do a random play file thing. I was going to count everything, pick a number, rewind, look for it..

-jim lee

User avatar
adafruit_support_mike
 
Posts: 67446
Joined: Thu Feb 11, 2010 2:51 pm

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

Post by adafruit_support_mike »

I picked that up years ago, either in an algorithms class or from a collection of coding tricks.

The secret to being a good programmer is to steal from the best. ;-)

User avatar
Marby
 
Posts: 12
Joined: Fri Mar 17, 2017 11:19 am

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

Post by Marby »

Sadly there is still a memory leak? Because after 3 plays it can't read anything from the SD card anymore. (I've only added the neopixel library )

There does seem to be a point in the code where something like this happens:
Now playing SOUND42.MP3
Done playing: SOUND42.MP3
Could not open file:
Now playing
Done playing:
Could not open file:
Now playing
Done playing:

It tries to open a blank, can't find it, and crashes.
With 90 neopixel it happens after 3 playbacks, with 150 it even can't get so far, the serial output stops at 'SD OK!
'. Without it seems to work fine (for x instances ?).


Code: Select all

// include SPI, MP3 and SD libraries
#include <SPI.h>
#include <Adafruit_VS1053.h>
#include <SD.h>
#include <Adafruit_NeoPixel.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);
//////////////////////////////////////////////////////////////////////////////////////////////////////

const int buttonPin = 5;     // the number of the pushbutton pin
int buttonState = 0;         // variable for reading the pushbutton status

#define PIN            2
#define NUMPIXELS      250
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
int val = 0;
/////////////////////////////////////////////////////////////////////////////////////////////////////
void setup() {
  Serial.begin(9600);

  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(20, 20);

  if (! musicPlayer.useInterrupt(VS1053_FILEPLAYER_PIN_INT))
    Serial.println(F("DREQ pin is not an interrupt pin"));

  ///////////////////////// button
  pinMode(buttonPin, INPUT);

delay(1000);
  /////////// ws2812b
  strip.begin(); // This initializes the NeoPixel library.
colorWipe(strip.Color(0, 100, 0), 0);
delay(100);
colorWipe(strip.Color(0, 0, 0), 0);
strip.setBrightness(200);
}
void loop() {
  colorWipe(strip.Color(0, 0, 0), 0);
  delay(100);

  buttonState = digitalRead(buttonPin);
  if (buttonState == LOW) {
    Serial.println("Button Pressed");

    File path = SD.open("/");
    File results;
    char* MP3 = selectRandomFileFrom( path, results );

    // 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);
    Serial.print("Light = ");
    Serial.println(val);
    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 :)
      switch (val) {
        case 0:
          theaterChase(strip.Color(127, 127, 127), 20);
          break;
        case 1:
          theaterChase(strip.Color(250, 255, 0), 20);
          break;
        case 2:
          theaterChase(strip.Color(255, 0, 255), 20);
          break;
        case 3:
          colorWipe(strip.Color(255, 0, 0), 3);
          delay(100);
          colorWipe(strip.Color(0, 0, 255), 3);
          delay(100);
          break;
        case 4:
          colorWipe(strip.Color(0, 255, 0), 3);
          delay(100);
          colorWipe(strip.Color(255, 0, 255), 3);
          delay(100);
          break;
        case 5:
          colorWipe(strip.Color(0, 0, 255), 3);
          delay(100);
          colorWipe(strip.Color(255, 255, 0), 3);
          delay(100);
          break;
      }

    }
    Serial.print("Done playing: ");
    Serial.println(MP3);
    Serial.println();
    val = random(6);
  }
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/// 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 colorWipe(uint32_t c, uint8_t wait) {
  for (uint16_t i = 0; i < strip.numPixels(); i++) {
    strip.setPixelColor(i, c);
    strip.show();
    delay(wait);
  }
}

void theaterChase(uint32_t c, uint8_t wait) {
  for (int j = 0; j < 6; j++) { //do 10 cycles of chasing
    for (int q = 0; q < 3; q++) {
      for (int i = 0; i < strip.numPixels(); i = i + 3) {
        strip.setPixelColor(i + q, c);  //turn every third pixel on
      }
      strip.show();

      delay(wait);

      for (int i = 0; i < strip.numPixels(); i = i + 3) {
        strip.setPixelColor(i + q, 0);      //turn every third pixel off
        strip.show();
      }
    }
  }
}

User avatar
jim_lee
 
Posts: 709
Joined: Thu May 24, 2012 8:24 pm

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

Post by jim_lee »

File path = SD.open("/");

You never close this file.

printDirectory(SD.open("/"), 0);

Or this file.

Actually printDirectory(SD.open("/"), 0); Is a real bad idea. You create something in a call but who is responsible to free it? If it were created -before- the call you could close it after. But better would be just to pass in "/" and have it created and closed inside the function.

-jim lee

User avatar
Marby
 
Posts: 12
Joined: Fri Mar 17, 2017 11:19 am

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

Post by Marby »

Hi! Thanks for your reply!
Could you give me the example how I can do that?
Thanks!

User avatar
jim_lee
 
Posts: 709
Joined: Thu May 24, 2012 8:24 pm

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

Post by jim_lee »

Code: Select all

// The original function. + a file name string.
void chooseRandomFile( File dir , char* outFileName) {
        
        File entry, result;
        int count = 1;
    
        dir.rewindDirectory();
        
        while ( entry = dir.openNextFile() ) {
            if ( random( count ) == 0 ) {
                if ( result ) {    // This bit was forgotten. We put it back.
                    result.close();
                }
                result = entry;
            } else {
                entry.close();
            }
            count++;
        }
        strcpy(outFileName,result.name());  // Copy the resulting file name out.
        result.close();  // Close result.
    }

When calling this function..

Code: Select all

char MP3[15];  // Allocate some room.
File dir = SD.open("/");  // Your standard root directory.
chooseRandomFile(dir,MP3);
dir.close();  // Clean up our stuff.
// Go play the file.
Hope this helps.

-jim lee

User avatar
mikememmi
 
Posts: 6
Joined: Wed Mar 29, 2017 9:06 pm

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

Post by mikememmi »

https://www.youtube.com/watch?v=Y-Mp6BJoY_k

hi guys, i found lots of great info in this thread for a project i am just starting. support here is excellent. in any case, there is a solution to the "playing in same order every time" issue in this video. by coincidence i just found this today. my app will use lots of random numbers. i will be building midi files with rando notes.

randomSeed(##)

thanks

Locked
Please be positive and constructive with your questions and comments.

Return to “Arduino Shields from Adafruit”