VS1053 problems with playing random file

General project help for Adafruit customers

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
User avatar
anthonyw
 
Posts: 10
Joined: Thu Nov 22, 2012 9:09 am

VS1053 problems with playing random file

Post by anthonyw »

I have two problems with trying to play a random mp3 file.

1. When listing the files, I get the filename plus the filename preceded by a underscore.
I think I have correctly formatted the SD card. I used SDformatter on my MacBook.

2. The arduino program works intermittently. It will play a track or two, then freezes.

Code: Select all


//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------  
//----------------------------------------------------------------------------------------  
/*
  Toothbrush Music player
  When a toothbrush is removed from a 3D printed holder, which has an imbedded light sensor,
  play a tune randomly selected from a folder on the SD card
  If the toothbrush is returned then withdrawn again, select a new tune.
  
  Designed  to work with the Adafruit VS1053 Codec Breakout 
  ----> https://www.adafruit.com/products/1381

  Written by Anthony Watts
  Dated: 14Sep2014
  
*/
//----------------------------------------------------------------------------------------  

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

// define the pins used
//#define CLK 13       // SPI Clock, shared with SD card
//#define MISO 12      // Input data, from VS1053/SD card
//#define MOSI 11      // Output data, to VS1053/SD card
// Connect CLK, MISO and MOSI to hardware SPI pins. 
// See http://arduino.cc/en/Reference/SPI "Connections"

// These pins are used for the breakout 
#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)

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

// create breakout object!
//Adafruit_VS1053_FilePlayer musicPlayer = Adafruit_VS1053_FilePlayer(SHIELD_CS, SHIELD_DCS, DREQ, CARDCS);
Adafruit_VS1053_FilePlayer musicPlayer = 
  Adafruit_VS1053_FilePlayer(SHIELD_RESET, SHIELD_CS, SHIELD_DCS, DREQ, CARDCS);

/* Analog Inputs  
  A0 = Volume potentiometer
  A1 = Toothbrush sensor 1 (user1)
  A2 = Toothbrush sensor 2 (user2)
*/
int sensor1_previous_value = 100; 
int sensor2_previous_value = 100;

//----------------------------------------------------------------------------------------  
//----------------------------------------------------------------------------------------  
//----------------------------------------------------------------------------------------  
void setup() 
{
  Serial.begin(9600);
  // F() macro saves arduino RAM by reading constant text strings direct from Program Memory
  Serial.println(F("------Arduino booting-----------------------"));
  //---------------------------------------------------
  // Generate the random number generator seed 
  uint32_t seed = 0; 
  for ( uint8_t i = 10 ; i ; i-- ) 
  {
    seed = ( seed << 5 ) + ( analogRead( 3 ) * 3 );
  }
  randomSeed( seed );  //set random seed
  Serial.print(F("RandomSeed value = "));
  Serial.println(seed);
  
  //---------------------------------------------------  
  // Test the music player is OK
  Serial.println("Adafruit VS1053 Library Test");
  if (! musicPlayer.begin()) 
  { 
     // initialise the music player
     Serial.println(F("Couldn't connect to VS1053 music player"));
     while (1); // don't do anything more
  }
  else
  {
     Serial.println(F("VS1053 music player OK"));
  }
  //---------------------------------------------------   
  // initialise the SD card
  Serial.println("Initializing SD card...");
  SD.begin(CARDCS);
  delay(500);
  
  // test for SD card
  if (SD.begin(CARDCS)) 
  { Serial.println(F("SD card failed, or not present"));}
  else
  { Serial.println(F("SD card OK!"));}
  delay(500); 
   
  // list user1's files
  Serial.println(F("List user1's files ----------------------------"));
  printDirectory(SD.open("/user1"), 1);
  delay(500);

  // list user2es's files
  Serial.println(F("List user2's files ----------------------------"));  
  printDirectory(SD.open("/user2"), 1);
  
  //--------------------------------------------------- 
  // Set a default volume for left, right channels. lower numbers == louder volume!
  musicPlayer.setVolume(20,20);
  delay(500);  
  
//--------------------------------------------------- 
  // If DREQ is on an interrupt pin (on uno, #2 or #3) we can do background audio playing
  //musicPlayer.useInterrupt(VS1053_FILEPLAYER_PIN_INT);  // DREQ int   


  /***** Two interrupt options! *******/ 
  // This option uses timer0, this means timer1 & t2 are not required
  // (so you can use 'em for Servos, etc) BUT millis() can lose time
  // since we're hitchhiking on top of the millis() tracker
  //musicPlayer.useInterrupt(VS1053_FILEPLAYER_TIMER0_INT);
  
  // This option uses a pin interrupt. No timers required! But DREQ
  // must be on an interrupt pin. For Uno/Duemilanove/Diecimilla
  // that's Digital #2 or #3
  // See http://arduino.cc/en/Reference/attachInterrupt for other pins
  // *** This method is preferred
  if (! musicPlayer.useInterrupt(VS1053_FILEPLAYER_PIN_INT))
    Serial.println(F("DREQ pin is not an interrupt pin"));


//---------------------------------------------------  
  Serial.println(F("-----System ready ------"));
  musicPlayer.startPlayingFile("/system/ready.mp3");
  delay(500);
}
//----------------------------------------------------------------------------------------  
//----------------------------------------------------------------------------------------  
//----------------------------------------------------------------------------------------  
void loop() 
{
  Serial.println(F("-------Start of Loop-------"));
  
  // Read the volume setting from the potentiometer 
  // The musicPlayer a range of about 100, where 100 for the  minimum and 0 is maximum
  // By swapping the location of the minimum and the maximum in the map function, 0 = quietest and 60 = loudest 
  int Volume = map(analogRead(A0), 0, 1023, 0, 100); 
  
  // set both left and right channels to the same volume 
  musicPlayer.setVolume(Volume, Volume);
  Serial.print ("Volume= ");  Serial.println(100-Volume); // 100-Volume to display larger number for geater volume
  
  // read the toothbrush sensors connected to A1 and A2 and scale the signal 0% to 100%
  int sensor1 = map(analogRead(A1), 0, 1023, 0, 100);
  Serial.print (F("user1's sensor= "));
  Serial.println(sensor1);
  
  int sensor2 = map(analogRead(A2), 0, 1023, 0, 100);
  Serial.print (F("user2's sensor= "));  Serial.println(sensor2);
  int deadband = 5;
 
  //---------------------------------------------------
  // user1
  //---------------------------------------------------  
  // if sensor1 < 70% and less than previous value, then the toothbrush has been removed, so play a tune
  if( sensor1 < 70   &&   (sensor1 < sensor1_previous_value -deadband))
  {
    Serial.println(F("Play a tune for user1"));  
       
    // Create the File variable path for the SD card file path
    File path = SD.open("/user1"); //Opens a directory on the SD card
    Serial.print ("path= ");Serial.println(path.name());
        
    // Create the File variable results to receive the filename from the selectRandomFileFrom function
    File results;  
    
    //Create the character array MP3 to store the random filename 
    char* MP3 = selectRandomFileFrom( path, results );
    Serial.print ("user1's MP3= ");  Serial.println(MP3);

    // convert a constant string into a String object
    String stringPath =  String("/user1/");
    Serial.print ("stringPath= ");  Serial.println(stringPath);
    
    String stringRandomFileName = String(MP3); 
    Serial.print ("stringRandomFileName= ");  Serial.println(stringRandomFileName);
        
    String PathAndFileName = String(stringPath + MP3);
    Serial.print ("PathAndFileName= ");  Serial.println(PathAndFileName);

    // Create the integer variable str_len to store the number of characters in the filename and then add one extra character for the null terminator)
    int str_len = PathAndFileName.length() + 1; 
    
    // Prepare the character array (the buffer) 
    char char_array[str_len];
    // Copy it over 
    PathAndFileName.toCharArray(char_array, str_len); 
    Serial.print ("user1's file result= ");  Serial.println(char_array);
    
    // Start playing a file, then proceed while waiting for it to finish, if not able to play, print error
    if (! musicPlayer.startPlayingFile(char_array)) 
    {
      Serial.print("Could not open file: "); Serial.println ("user1's randomm file= ");Serial.println(char_array);
    }

    // if the toothbrush is returned, then stop the tune !
    if( sensor1 > 70   &&   sensor1 > (sensor1_previous_value + deadband)) 
    {
      musicPlayer.stopPlaying();
    }
  }
  //--------------------------------------------------- 
  // user2  
  //---------------------------------------------------    
  // if > 70%, then the toothbrush is present, else it has been removed
  // sense when removed

  if( sensor2 < 70   &&   (sensor2 < sensor2_previous_value -deadband))
  {
    Serial.println("Play a tune for user2");     
    // Set the SD card file path
    File path = SD.open("/user2");
    File results;  
    char* MP3 = selectRandomFileFrom( path, results );
    String stringOne =  String("/user2/");    // converting a constant string into a String object  
    String PathAndFileName = String(stringOne + MP3);   
    // Length (with one extra character for the null terminator)
    int str_len = PathAndFileName.length() + 1; 
    // Prepare the character array (the buffer) 
    char char_array[str_len];
    // Copy it over 
    PathAndFileName.toCharArray(char_array, str_len); 
    Serial.print ("user2's file result= ");  Serial.println(char_array);
    
    // Start playing a file, then proceed while waiting for it to finish, if not able to play, print error
    if (! musicPlayer.startPlayingFile(char_array)) 
    {
      Serial.print("Could not open file: "); Serial.println ("user2's randomm file= ");Serial.println(char_array);
    }
  } 
 
  // if the toothbrush is returned, then stop the tune !
  if( sensor2 > 70   &&   sensor2 > (sensor2_previous_value + deadband)) 
  {
    musicPlayer.stopPlaying();
  }

  // if the toothbrush is returned, then stop the tune !
  if( sensor1 > 70   &&   sensor1 > (sensor1_previous_value + deadband)) 
  {
    musicPlayer.stopPlaying();
  }

  //-------------------------- 
  /* 
  // File is playing in the background
  if (musicPlayer.stopped()) 
  {
    Serial.println("Done playing music");
    //while (1);
  }
  */

  delay(1500);
  
  // save sensor readings
  sensor1_previous_value = sensor1;  
  sensor2_previous_value = sensor2;
}

//----------------------------------------------------------------------------------------  
//----------------------------------------------------------------------------------------  
//----------------------------------------------------------------------------------------  
////////////////////////////////////////////////////////////////////////////////////////////////////
/// 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
}
//-----------------------------------------------------------------------------------------------

Code: Select all


------Arduino booting-----------------------
RandomSeed value = 2147686646
Adafruit VS1053 Library Test
VS1053 music player OK
Initializing SD card...
SD card OK!
List user1's files ----------------------------
	AERO.MP3		286349
	_AER~1.MP3		4096
	ALVIN1.MP3		2787705
	_ALVIN~1.MP3		4096
	ALVIN2.MP3		2933781
	_ALVIN~2.MP3		4096
	ALVIN3.MP3		1349507
	_ALVIN~3.MP3		4096
	CRICKETS.MP3		253760
	_CRICK~1.MP3		4096
	HEINZ.MP3		275751
	_HEIN~1.MP3		4096
	IPANA.MP3		949978
	_IPAN~1.MP3		4096
	MICKEY.MP3		2596811
	_MICKE~1.MP3		4096
	VEGE.MP3		958755
	_VEG~1.MP3		4096
	WEETB.MP3		572934
	_WEET~1.MP3		4096
**nomorefiles**
List user2's files ----------------------------
	BICYCLE.MP3		3679761
	_BICYC~1.MP3		4096
	BOHEMIAN.MP3		7169203
	_BOHEM~1.MP3		4096
	CHAMPION.MP3		3631705
	_CHAMP~1.MP3		4096
	CRAZYLOV.MP3		3280106
	_CRAZY~1.MP3		4096
	DONTSTOP.MP3		4238264
	_DONTS~1.MP3		4096
	DUST.MP3		4341714
	_DUS~1.MP3		4096
	FATGIRLS.MP3		4094586
	_FATGI~1.MP3		4096
	FLASH.MP3		3372027
	_FLAS~1.MP3		4096
	FRIEND.MP3		3447276
	_FRIEN~1.MP3		4096
	KILLER.MP3		3643712
	_KILLE~1.MP3		4096
	BANNED.MP3		3519909
	_BANNED~1.MP3		4096
	NOWHERE.MP3		5108132
	_NOWHE~1.MP3		4096
	PLAYGAM.MP3		4269608
	_PLAYG~1.MP3		4096
	ROCKYOU.MP3		2458797
	_ROCKY~1.MP3		4096
	SAVEME.MP3		4575750
	_SAVEM~1.MP3		4096
	SEVENS~1.MP3		3412797
	_SEVEN~1.MP3		4096
	SOMEBODY.MP3		5957121
	_SOMEB~1.MP3		4096
**nomorefiles**
-----System ready ------
-------Start of Loop-------
Volume= 68
user1's sensor= 74
user2's sensor= 96

-------Start of Loop-------
Volume= 68
user1's sensor= 44
user2's sensor= 96
Play a tune for user1
path= user1
user1's MP3= IPANA.MP3
stringPath= /user1/
stringRandomFileName= IPANA.MP3
PathAndFileName= /user1/IPANA.MP3
user1's file result= /user1/IPANA.MP3
-------Start of Loop-------
Volume= 68
user1's sensor= 44
user2's sensor= 96

-------Start of Loop-------
Volume= 68
user1's sensor= 91
user2's sensor= 96
-------Start of Loop-------
Volume= 68
user1's sensor= 44
user2's sensor= 96
Play a tune for user1
path= user1
user1's MP3= _IPAN~1.MP3
stringPath= /user1/
stringRandomFileName= _IPAN~1.MP3
PathAndFileName= /user1/_IPAN~1.MP3
user1's file result= /user1/_IPAN~1.MP3
Could not open file: user1's randomm file= 
/user1/_IPAN~1.MP3
-------Start of Loop-------
Volume= 68
user1's sensor= 44
user2's sensor= 96

-------Start of Loop-------
Volume= 68
user1's sensor= 93
user2's sensor= 96
-------Start of Loop-------
Volume= 68
user1's sensor= 44
user2's sensor= 96
Play a tune for user1
path= user1
user1's MP3= ALVIN3.MP3
stringPath= /user1/
stringRandomFileName= ALVIN3.MP3
PathAndFileName= /user1/ALVIN3.MP3
user1's file result= /user1/ALVIN3.MP3
-------Start of Loop-------
Volume= 68
user1's sensor= 44
user2's sensor= 96

-------Start of Loop-------
Volume= 68
user1's sensor= 92
user2's sensor= 96
-------Start of Loop-------
Volume= 68
user1's sensor= 44
user2's sens�������)��ե���booting-----------------------
RandomSeed value = 2074854876
Adafruit VS1053 Library Test
VS1053 music player OK
Initializing SD card...
SD card OK!
List user1's files ----------------------------
	AERO.MP3		286349
	_AER~1.MP3		4096
	ALVIN1.MP3		2787705
	_ALVIN~1.MP3		4096
	ALVIN2.MP3		2933781
	_ALVIN~2.MP3		4096
	ALVIN3.MP3		1349507
	_ALVIN~3.MP3		4096
	CRICKETS.MP3		253760
	_CRICK~1.MP3		4096
	HEINZ.MP3		275751
	_HEIN~1.MP3		4096
	IPANA.MP3		949978
	_IPAN~1.MP3		4096
	MICKEY.MP3		2596811
	_MICKE~1.MP3		4096
	VEGE.MP3		958755
	_VEG~1.MP3		4096
	WEETB.MP3		572934
	_WEET~1.MP3		4096
**nomorefiles**
List user2's files ----------------------------
	BICYCLE.MP3		3679761
	_BICYC~1.MP3		4096
	BOHEMIAN.MP3		7169203
	_BOHEM~1.MP3		4096
	CHAMPION.MP3		3631705
	_CHAMP~1.MP3		4096
	CRAZYLOV.MP3		3280106
	_CRAZY~1.MP3		4096
	DONTSTOP.MP3		4238264
	_DONTS~1.MP3		4096
	DUST.MP3		4341714
	_DUS~1.MP3		4096
	FATGIRLS.MP3		4094586
	_FATGI~1.MP3		4096
	FLASH.MP3		3372027
	_FLAS~1.MP3		4096
	FRIEND.MP3		3447276
	_FRIEN~1.MP3		4096
	KILLER.MP3		3643712
	_KILLE~1.MP3		4096
	BANNED.MP3		3519909
	_BANNED~1.MP3		4096
	NOWHERE.MP3		5108132
	_NOWHE~1.MP3		4096
	PLAYGAM.MP3		4269608
	_PLAYG~1.MP3		4096
	ROCKYOU.MP3		2458797
	_ROCKY~1.MP3		4096
	SAVEME.MP3		4575750
	_SAVEM~1.MP3		4096
	SEVENS~1.MP3		3412797
	_SEVEN~1.MP3		4096
	SOMEBODY.MP3		5957121
	_SOMEB~1.MP3		4096
**nomorefiles**
-----System ready ------
-------Start of Loop-------
Volume= 68
user1's sensor= 44
user2's sensor= 96
Play a tune for user1
path= user1

Thanks
Anthony

User avatar
adafruit_support_rick
 
Posts: 35092
Joined: Tue Mar 15, 2011 11:42 am

Re: VS1053 problems with playing random file

Post by adafruit_support_rick »

Looks like your file names are not 8.3 format. That is, the names are longer than 8 characters plus a 3-character extension. Rename all of your files to be 8.3 compliant.

Do this on your Mac. Reformat the SD and copy everything over again. I think that will get rid of the "_xxxx~.mp3 files. Those are your problem.

User avatar
anthonyw
 
Posts: 10
Joined: Thu Nov 22, 2012 9:09 am

Re: VS1053 problems with playing random file

Post by anthonyw »

I reformatted the SD card, then created the directory "user1"
I then copied files using the Windows COMMAND window.
This was the only way I found to ensure true 8.3 Short File Names. The MacBook copied the 8.3 filename, but stored it as a Long File Name.
Is there a way to use the MacBook and force SHORT FILE NAMES?

Then reinserted the SD card into the VS1053 and ran the program.

It works OK, but on the sixth time it plays a music file, it fails.
It gets the serial output scrambled and then either, freezes or auto reboots.

I added a function to printout the freeRam. I suspect this may be the problem.
The free RAM decreases with each loop that plays a tune.

Code: Select all

------Arduino booting-----------------------
Free SRAM=[705]
RandomSeed value = 3051285289
Adafruit VS1053 Library Test
VS1053 music player OK
Initializing SD card...
SD card OK!
USER1/
	AEROJEL1.MP3		286349
	ALVIN1.MP3		2787705
	ALVIN2.MP3		2933781
	ALVIN3.MP3		1349507
	CRICKET1.MP3		253760
	HEINZ1.MP3		275751
	IPANA1.MP3		949978
	MICKEY.MP3		2596811
	VEGEMIT1.MP3		958755
	WEETBIX1.MP3		572934
**nomorefiles**
**nomorefiles**
List user1's files ----------------------------
	AEROJEL1.MP3		286349
	ALVIN1.MP3		2787705
	ALVIN2.MP3		2933781
	ALVIN3.MP3		1349507
	CRICKET1.MP3		253760
	HEINZ1.MP3		275751
	IPANA1.MP3		949978
	MICKEY.MP3		2596811
	VEGEMIT1.MP3		958755
	WEETBIX1.MP3		572934
**nomorefiles**
List user2's files ----------------------------
**nomorefiles**
-----System ready ------
-------Start of Loop-------
Free SRAM=[539]
Volume= 68
user1's sensor= 62
user2's sensor= 95
Play a tune for user1
path=[user1]
user1's MP3=[MICKEY.MP3]
stringPath=[/user1/]
stringRandomFileName=[MICKEY.MP3]
PathAndFileName=[/user1/MICKEY.MP3]
str_len=[18]
user1's file result=[/user1/MICKEY.MP3]
-------Start of Loop-------
Free SRAM=[414]
Volume= 68
user1's sensor= 62
user2's sensor= 95
-------Start of Loop-------
Free SRAM=[414]
Volume= 68
user1's sensor= 62
user2's sensor= 95
-------Start of Loop-------
Free SRAM=[414]
Volume= 68
user1's sensor= 62
user2's sensor= 95
-------Start of Loop-------
Free SRAM=[414]
Volume= 68
user1's sensor= 62
user2's sensor= 95
-------Start of Loop-------
Free SRAM=[414]
Volume= 68
user1's sensor= 62
user2's sensor= 95
-------Start of Loop-------
Free SRAM=[414]
Volume= 68
user1's sensor= 62
user2's sensor= 95
-------Start of Loop-------
Free SRAM=[414]
Volume= 68
user1's sensor= 62
user2's sensor= 95
-------Start of Loop-------
Free SRAM=[414]
Volume= 68
user1's sensor= 62
user2's sensor= 95
-------Start of Loop-------
Free SRAM=[414]
Volume= 68
user1's sensor= 95
user2's sensor= 95
Done playing music
-------Start of Loop-------
Free SRAM=[508]
Volume= 68
user1's sensor= 95
user2's sensor= 95
Done playing music
-------Start of Loop-------
Free SRAM=[508]
Volume= 68
user1's sensor= 95
user2's sensor= 95
Done playing music
-------Start of Loop-------
Free SRAM=[508]
Volume= 68
user1's sensor= 62
user2's sensor= 95
Play a tune for user1
path=[user1]
user1's MP3=[HEINZ1.MP3]
stringPath=[/user1/]
stringRandomFileName=[HEINZ1.MP3]
PathAndFileName=[/user1/HEINZ1.MP3]
str_len=[18]
user1's file result=[/user1/HEINZ1.MP3]
-------Start of Loop-------
Free SRAM=[383]
Volume= 68
user1's sensor= 62
user2's sensor= 95
-------Start of Loop-------
Free SRAM=[383]
Volume= 68
user1's sensor= 62
user2's sensor= 95
-------Start of Loop-------
Free SRAM=[383]
Volume= 68
user1's sensor= 62
user2's sensor= 95
-------Start of Loop-------
Free SRAM=[383]
Volume= 68
user1's sensor= 96
user2's sensor= 95
Done playing music
-------Start of Loop-------
Free SRAM=[477]
Volume= 68
user1's sensor= 96
user2's sensor= 95
Done playing music
-------Start of Loop-------
Free SRAM=[477]
Volume= 68
user1's sensor= 96
user2's sensor= 95
Done playing music
-------Start of Loop-------
Free SRAM=[477]
Volume= 68
user1's sensor= 62
user2's sensor= 95
Play a tune for user1
path=[user1]
user1's MP3=[HEINZ1.MP3]
stringPath=[/user1/]
stringRandomFileName=[HEINZ1.MP3]
PathAndFileName=[/user1/HEINZ1.MP3]
str_len=[18]
user1's file result=[/user1/HEINZ1.MP3]
-------Start of Loop-------
Free SRAM=[352]
Volume= 68
user1's sensor= 62
user2's sensor= 95
-------Start of Loop-------
Free SRAM=[352]
Volume= 68
user1's sensor= 62
user2's sensor= 95
-------Start of Loop-------
Free SRAM=[352]
Volume= 68
user1's sensor= 96
user2's sensor= 95
Done playing music
-------Start of Loop-------
Free SRAM=[446]
Volume= 68
user1's sensor= 96
user2's sensor= 95
Done playing music
-------Start of Loop-------
Free SRAM=[446]
Volume= 68
user1's sensor= 62
user2's sensor= 95
Play a tune for user1
path=[user1]
user1's MP3=[ALVIN3.MP3]
stringPath=[/user1/]
stringRandomFileName=[ALVIN3.MP3]
PathAndFileName=[/user1/ALVIN3.MP3]
str_len=[18]
user1's file result=[/user1/ALVIN3.MP3]
-------Start of Loop-------
Free SRAM=[321]
Volume= 68
user1's sensor= 62
user2's sensor= 95
-------Start of Loop-------
Free SRAM=[321]
Volume= 68
user1's sensor= 62
user2's sensor= 95
-------Start of Loop-------
Free SRAM=[321]
Volume= 68
user1's sensor= 95
user2's sensor= 95
Done playing music
-------Start of Loop-------
Free SRAM=[415]
Volume= 68
user1's sensor= 95
user2's sensor= 95
Done playing music
-------Start of Loop-------
Free SRAM=[415]
Volume= 68
user1's sensor= 62
user2's sensor= 95
Play a tune for user1
path=[user1]
user1's MP3=[IPANA1.MP3]
stringPath=[/user1/]
stringRandomFileName=[IPANA1.MP3]
PathAndFileName=[/user1/IPANA1.MP3]
str_len=[18]
user1's file result=[/user1/IPANA1.MP3]
Could not open file: user1's random file=[/user1/IPANA1.MP3]
Done playing music
-------Start of Loop-------
Free SRAM=[321]
Volume= 68
user1's sensor= 62
user2's sensor= 95
Done playing music
-------Start of Loop-------
Free SRAM=[321]
Volume= 68
user1's sensor= 62
user2's sensor= 95
Done playing music
-------Start of Loop-------
Free SRAM=[321]
Volume= 68
user1's sensor= 95
user2's sensor= 95
Done playing music
-------Start of Loop-------
Free SRAM=[321]
Volume= 68
user1's sensor= 96
user2's sensor= 95
Done playing music
-------Start of Loop-------
Free SRAM=[321]
Volume= 68
user1's sensor= 62
user2's sensor= 95
Play a tune for user1
path=[user1]
user1's MP3=[]
stringPath=[/user1/]
stringRandomFileName=[]
PathAndFileName=[/user1/]
str_len=[8]
user1's file result=[/user1/]

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

Re: VS1053 problems with playing random file

Post by adafruit_support_mike »

Check your code for objects being created but not deleted. That's the most common source of memory leaks in C++.

User avatar
adafruit_support_rick
 
Posts: 35092
Joined: Tue Mar 15, 2011 11:42 am

Re: VS1053 problems with playing random file

Post by adafruit_support_rick »

Are you using String objects? Make sure to use the reserve() method on those to prevent memory fragmentation
https://www.arduino.cc/en/Reference/StringReserve

You can also post your code and we'll see if we can spot anything

User avatar
anthonyw
 
Posts: 10
Joined: Thu Nov 22, 2012 9:09 am

Re: VS1053 problems with playing random file

Post by anthonyw »

Yes, I am using String objects.
I will investigate the reserve() method

Here is the latest version of code

Code: Select all


//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------  
//----------------------------------------------------------------------------------------  
/*
  Toothbrush Music player
  When a toothbrush is removed from a 3D printed holder, which has an imbedded light sensor,
  play a tune randomly selected from a folder on the SD card
  If the toothbrush is returned then withdrawn again, select a new tune.
  
  Designed  to work with the Adafruit VS1053 Codec Breakout 
  ----> https://www.adafruit.com/products/1381

  Written by Anthony Watts
  Dated: 14Sep2014
  
*/
//----------------------------------------------------------------------------------------  

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

// define the pins used
//#define CLK 13       // SPI Clock, shared with SD card
//#define MISO 12      // Input data, from VS1053/SD card
//#define MOSI 11      // Output data, to VS1053/SD card
// Connect CLK, MISO and MOSI to hardware SPI pins. 
// See http://arduino.cc/en/Reference/SPI "Connections"

// These pins are used for the breakout 
#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)

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

// create breakout object!
//Adafruit_VS1053_FilePlayer musicPlayer = Adafruit_VS1053_FilePlayer(SHIELD_CS, SHIELD_DCS, DREQ, CARDCS);
Adafruit_VS1053_FilePlayer musicPlayer = 
  Adafruit_VS1053_FilePlayer(SHIELD_RESET, SHIELD_CS, SHIELD_DCS, DREQ, CARDCS);

/* Analog Inputs  
  A0 = Volume potentiometer
  A1 = Toothbrush sensor 1 (user1)
  A2 = Toothbrush sensor 2 (user2)
*/
int sensor1_previous_value = 100; 
int sensor2_previous_value = 100;

//----------------------------------------------------------------------------------------  
//----------------------------------------------------------------------------------------  
//----------------------------------------------------------------------------------------  
void setup() 
{
  Serial.begin(9600);
  // F() macro saves arduino SRAM by reading constant text strings direct from Flash Program Memory
  Serial.println(F("------Arduino booting-----------------------"));

  // Determine the amount of free SRAM

  Serial.print ("Free SRAM=[");Serial.print(freeRam()); Serial.println ("]");
  
  //---------------------------------------------------
  // Generate the random number generator seed 
  uint32_t seed = 0; 
  for ( uint8_t i = 10 ; i ; i-- ) 
  {
    seed = ( seed << 5 ) + ( analogRead( 3 ) * 3 );
  }
  randomSeed( seed );  //set random seed
  Serial.print(F("RandomSeed value = "));
  Serial.println(seed);
  
  //---------------------------------------------------  
  // Test the music player is OK
  Serial.println("Adafruit VS1053 Library Test");
  if (! musicPlayer.begin()) 
  { 
     // initialise the music player
     Serial.println(F("Couldn't connect to VS1053 music player"));
     while (1); // don't do anything more
  }
  else
  {
     Serial.println(F("VS1053 music player OK"));
  }
  //---------------------------------------------------   
  // initialise the SD card
  Serial.println("Initializing SD card...");
  SD.begin(CARDCS);
  delay(500);
  
  // test for SD card
  if (SD.begin(CARDCS)) 
  { Serial.println(F("SD card failed, or not present"));}
  else
  { Serial.println(F("SD card OK!"));}
  delay(500); 

  // list all files
  printDirectory(SD.open("/"), 0);
  delay(500); 
   
  // list user1's files
  Serial.println(F("List user1's files ----------------------------"));
  printDirectory(SD.open("/user1"), 1);
  delay(500);

  // list user2es's files
  Serial.println(F("List user2's files ----------------------------"));  
  printDirectory(SD.open("/user2"), 1);
  
  //--------------------------------------------------- 
  // Set a default volume for left, right channels. lower numbers == louder volume!
  musicPlayer.setVolume(20,20);
  delay(500);  
  
//--------------------------------------------------- 
  // If DREQ is on an interrupt pin (on uno, #2 or #3) we can do background audio playing
  //musicPlayer.useInterrupt(VS1053_FILEPLAYER_PIN_INT);  // DREQ int   


  /***** Two interrupt options! *******/ 
  // This option uses timer0, this means timer1 & t2 are not required
  // (so you can use 'em for Servos, etc) BUT millis() can lose time
  // since we're hitchhiking on top of the millis() tracker
  //musicPlayer.useInterrupt(VS1053_FILEPLAYER_TIMER0_INT);
  
  // This option uses a pin interrupt. No timers required! But DREQ
  // must be on an interrupt pin. For Uno/Duemilanove/Diecimilla
  // that's Digital #2 or #3
  // See http://arduino.cc/en/Reference/attachInterrupt for other pins
  // *** This method is preferred
  if (! musicPlayer.useInterrupt(VS1053_FILEPLAYER_PIN_INT))
    Serial.println(F("DREQ pin is not an interrupt pin"));


//---------------------------------------------------  
  Serial.println(F("-----System ready ------"));
  //musicPlayer.startPlayingFile("/user1/alvin1.mp3");
  //musicPlayer.startPlayingFile("/system/ready.mp3");
  delay(500);
}
//----------------------------------------------------------------------------------------  
//----------------------------------------------------------------------------------------  
//----------------------------------------------------------------------------------------  
void loop() 
{
  Serial.println(F("-------Start of Loop-------"));
  Serial.print ("Free SRAM=[");Serial.print(freeRam()); Serial.println ("]");
  
  // Read the volume setting from the potentiometer 
  // The musicPlayer a range of about 100, where 100 for the  minimum and 0 is maximum
  // By swapping the location of the minimum and the maximum in the map function, 0 = quietest and 60 = loudest 
  int Volume = map(analogRead(A0), 0, 1023, 0, 100); 
  
  // set both left and right channels to the same volume 
  musicPlayer.setVolume(Volume, Volume);
  Serial.print ("Volume= ");  Serial.println(100-Volume); // 100-Volume to display larger number for geater volume
  
  // read the toothbrush sensors connected to A1 and A2 and scale the signal 0% to 100%
  int sensor1 = map(analogRead(A1), 0, 1023, 0, 100);
  Serial.print (F("user1's sensor= "));
  Serial.println(sensor1);
  
  int sensor2 = map(analogRead(A2), 0, 1023, 0, 100);
  Serial.print (F("user2's sensor= "));  Serial.println(sensor2);
  int deadband = 5;
 
  //---------------------------------------------------
  // user1
  //---------------------------------------------------  
  // if sensor1 < 70% and less than previous value, then the toothbrush has been removed, so play a tune
  if( sensor1 < 70   &&   (sensor1 < sensor1_previous_value -deadband))
  {
    Serial.println(F("Play a tune for user1"));  
       
    // Create the File variable path for the SD card file path
    File path = SD.open("/user1"); //Opens a directory on the SD card
    Serial.print ("path=[");Serial.print(path.name()); Serial.println ("]");
        
    // Create the File variable results to receive the filename from the selectRandomFileFrom function
    File results;  
    
    //Create the character array MP3 to store the random filename 
    const char* MP3 = selectRandomFileFrom( path, results );
    Serial.print ("user1's MP3=[");  Serial.print(MP3);  Serial.println ("]");

    // convert a constant string into a String object
    String stringPath =  String("/user1/");
    Serial.print ("stringPath=[");  Serial.print(stringPath);  Serial.println ("]");
    
    String stringRandomFileName = String(MP3); 
    Serial.print ("stringRandomFileName=[");  Serial.print(stringRandomFileName);  Serial.println ("]");
        
    String PathAndFileName = String(stringPath + MP3);
    Serial.print ("PathAndFileName=[");  Serial.print(PathAndFileName); Serial.println ("]");

    // Create the integer variable str_len to store the number of characters in the filename and then add one extra character for the null terminator)
    int str_len = PathAndFileName.length() + 1; 
    
    // Prepare the character array (the buffer) 
    char char_array[str_len];
    Serial.print ("str_len=[");  Serial.print(str_len);  Serial.println ("]");
    // Copy it over 
    PathAndFileName.toCharArray(char_array, str_len);
    Serial.print ("user1's file result=[");  Serial.print(char_array);  Serial.println ("]");
    
    // Start playing a file, then proceed while waiting for it to finish, if not able to play, print error
    if (! musicPlayer.startPlayingFile(char_array)) 
    {
      Serial.print("Could not open file: "); Serial.print ("user1's random file=["); Serial.print(char_array); Serial.println ("]");
    }

    // if the toothbrush is returned, then stop the tune !
    if( sensor1 > 70   &&   sensor1 > (sensor1_previous_value + deadband)) 
    {
      musicPlayer.stopPlaying();
    }
  }
  //--------------------------------------------------- 
  // user2  
  //---------------------------------------------------    
  // if > 70%, then the toothbrush is present, else it has been removed
  // sense when removed

  if( sensor2 < 70   &&   (sensor2 < sensor2_previous_value -deadband))
  {
    Serial.println("Play a tune for user2");     
    // Set the SD card file path
    File path = SD.open("/user2");
    File results;  
    char* MP3 = selectRandomFileFrom( path, results );
    String stringOne =  String("/user2/");    // converting a constant string into a String object  
    String PathAndFileName = String(stringOne + MP3);   
    // Length (with one extra character for the null terminator)
    int str_len = PathAndFileName.length() + 1; 
    // Prepare the character array (the buffer) 
    char char_array[str_len];
    // Copy it over 
    PathAndFileName.toCharArray(char_array, str_len); 
    Serial.print ("user2's file result= ");  Serial.println(char_array);
    
    // Start playing a file, then proceed while waiting for it to finish, if not able to play, print error
    if (! musicPlayer.startPlayingFile(char_array)) 
    {
      Serial.print("Could not open file: "); Serial.println ("user2's randomm file= ");Serial.println(char_array);
    }
  } 
 
  // if the toothbrush is returned, then stop the tune !
  if( sensor2 > 70   &&   sensor2 > (sensor2_previous_value + deadband)) 
  {
    musicPlayer.stopPlaying();
    const char* MP3 = "";
    delay(1000);
  }

  // if the toothbrush is returned, then stop the tune !
  if( sensor1 > 70   &&   sensor1 > (sensor1_previous_value + deadband)) 
  {
    musicPlayer.stopPlaying();
    const char* MP3 = "";
    delay(1000);
  }

  //-------------------------- 
   
  // File is playing in the background
  if (musicPlayer.stopped()) 
  {
    Serial.println("Done playing music");
    //while (1);
  }
  

  delay(1500);
  
  // save sensor readings
  sensor1_previous_value = sensor1;  
  sensor2_previous_value = sensor2;
}

//----------------------------------------------------------------------------------------  
//----------------------------------------------------------------------------------------  
//----------------------------------------------------------------------------------------  
////////////////////////////////////////////////////////////////////////////////////////////////////
/// 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
}

//-----------------------------------------------------------------------------------------------
int freeRam () 
{
  extern int __heap_start, *__brkval; 
  int v; 
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 
}

//-----------------------------------------------------------------------------------------------

Thank you for your help!

User avatar
adafruit_support_rick
 
Posts: 35092
Joined: Tue Mar 15, 2011 11:42 am

Re: VS1053 problems with playing random file

Post by adafruit_support_rick »

Yeah. Make all of the String objects global, instead of declaring them inline. Then call the reserve() method in setup() for each of them.

User avatar
anthonyw
 
Posts: 10
Joined: Thu Nov 22, 2012 9:09 am

Re: VS1053 problems with playing random file

Post by anthonyw »

I have made the String arrays and variables global
and reserved memory for the strings.

I am still loosing 31 bytes each time a tune is played.

Any suggestions?

Code: Select all

//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------  
//----------------------------------------------------------------------------------------  
/*
  Toothbrush Music player
  When a toothbrush is removed from a 3D printed holder, which has an imbedded light sensor,
  play a tune randomly selected from a folder on the SD card
  If the toothbrush is returned then withdrawn again, select a new tune.
  
  Designed  to work with the Adafruit VS1053 Codec Breakout 
  ----> https://www.adafruit.com/products/1381

  Written by Anthony Watts
  Dated: 19Sep2014
  
*/
//----------------------------------------------------------------------------------------  

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

// define the pins used
//#define CLK 13       // SPI Clock, shared with SD card
//#define MISO 12      // Input data, from VS1053/SD card
//#define MOSI 11      // Output data, to VS1053/SD card
// Connect CLK, MISO and MOSI to hardware SPI pins. 
// See http://arduino.cc/en/Reference/SPI "Connections"

// These pins are used for the breakout 
#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)

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

// create breakout object!
//Adafruit_VS1053_FilePlayer musicPlayer = Adafruit_VS1053_FilePlayer(SHIELD_CS, SHIELD_DCS, DREQ, CARDCS);
Adafruit_VS1053_FilePlayer musicPlayer = 
  Adafruit_VS1053_FilePlayer(SHIELD_RESET, SHIELD_CS, SHIELD_DCS, DREQ, CARDCS);

/* Analog Inputs  
  A0 = Volume potentiometer
  A1 = Toothbrush sensor 1 (user1)
  A2 = Toothbrush sensor 2 (user2)
*/

// Initialise global variables
int sensor1 = 100;
int sensor2 = 100;
int sensor1_previous_value = 100; 
int sensor2_previous_value = 100;
int Volume = 20;
int deadband = 5;
int str_len = 20;

String stringRandomFileName;
String PathAndFileName;

const char* MP3;
char char_array[20];
File path;
File results; 
 
//----------------------------------------------------------------------------------------  
//----------------------------------------------------------------------------------------  
//----------------------------------------------------------------------------------------  
void setup() 
{
  Serial.begin(9600);
  // F() macro saves arduino SRAM by reading constant text strings direct from Flash Program Memory
  Serial.println(F("------Arduino booting-----------------------"));

  // Determine the amount of free SRAM
  Serial.print (F("Free SRAM=["));Serial.print(freeRam()); Serial.println (F("]"));
  
  //---------------------------------------------------
  // Generate the random number generator seed 
  uint32_t seed = 0; 
  for ( uint8_t i = 10 ; i ; i-- ) 
  {
    seed = ( seed << 5 ) + ( analogRead( 3 ) * 3 );
  }
  randomSeed( seed );  //set random seed
  Serial.print(F("RandomSeed value = "));
  Serial.println(seed);
  
  //---------------------------------------------------  
  // Test the music player is OK
  Serial.println(F("Adafruit VS1053 Library Test"));
  if (! musicPlayer.begin()) 
  { 
     // initialise the music player
     Serial.println(F("Couldn't connect to VS1053 music player"));
     while (1); // don't do anything more
  }
  else
  {
     Serial.println(F("VS1053 music player OK"));
  }
  //---------------------------------------------------   
  // initialise the SD card
  Serial.println(F("Initializing SD card..."));
  SD.begin(CARDCS);
  delay(500);
  
  // test for SD card
  if (SD.begin(CARDCS)) 
  { Serial.println(F("SD card failed, or not present"));}
  else
  { Serial.println(F("SD card OK!"));}
  delay(500); 

  // list all files
  printDirectory(SD.open("/"), 0);
  delay(500); 
   
  //--------------------------------------------------- 
  // Set a default volume for left, right channels. lower numbers == louder volume!
  musicPlayer.setVolume(20,20);
  delay(500);  
  
  //--------------------------------------------------- 
  /***** Two interrupt options! *******/ 
  // This option uses timer0, this means timer1 & t2 are not required
  // (so you can use 'em for Servos, etc) BUT millis() can lose time
  // since we're hitchhiking on top of the millis() tracker
  //musicPlayer.useInterrupt(VS1053_FILEPLAYER_TIMER0_INT);
  
  // This option uses a pin interrupt. No timers required! But DREQ
  // must be on an interrupt pin. For Uno/Duemilanove/Diecimilla
  // that's Digital #2 or #3
  // See http://arduino.cc/en/Reference/attachInterrupt for other pins
  // *** This method is preferred
  // If DREQ is on an interrupt pin (on uno, #2 or #3) we can do background audio playing
  musicPlayer.useInterrupt(VS1053_FILEPLAYER_PIN_INT);  // DREQ int
  
  if (! musicPlayer.useInterrupt(VS1053_FILEPLAYER_PIN_INT))
  {Serial.println(F("DREQ pin is not an interrupt pin"));}

  //---------------------------------------------------  
  Serial.println(F("-----System ready ------"));
  musicPlayer.startPlayingFile("/system/ready.mp3");
  delay(500);

  // Allocate buffers in memory for manipulating strings to minimize RAM memory leaks.
  stringRandomFileName.reserve(12);
  PathAndFileName.reserve(24);
  
}
//----------------------------------------------------------------------------------------  
//----------------------------------------------------------------------------------------  
//----------------------------------------------------------------------------------------  
void loop() 
{
  Serial.println(F("-------Start of Loop-------"));
  Serial.print (F("Free SRAM=["));Serial.print(freeRam()); Serial.println (F("]"));
  
  // Read the volume setting from the potentiometer 
  // The musicPlayer a range of about 100, where 100 for the  minimum and 0 is maximum
  // By swapping the location of the minimum and the maximum in the map function, 0 = quietest and 60 = loudest 
  Volume = map(analogRead(A0), 0, 1023, 0, 100); 
  
  // set both left and right channels to the same volume 
  musicPlayer.setVolume(Volume, Volume);
  Serial.print (F("Volume= "));  Serial.println(100-Volume); // 100-Volume to display larger number for geater volume
  
  // read the toothbrush sensors connected to A1 and A2 and scale the signal 0% to 100%
  sensor1 = map(analogRead(A1), 0, 1023, 0, 100);
  Serial.print (F("user1's sensor= "));  Serial.println(sensor1);
  
  sensor2 = map(analogRead(A2), 0, 1023, 0, 100);
  Serial.print (F("user2's sensor= "));  Serial.println(sensor2);
 
  //---------------------------------------------------
  // user1
  //---------------------------------------------------  
  // if sensor1 < 70% and less than previous value, then the toothbrush has been removed, so play a tune
  if( sensor1 < 70   &&   (sensor1 < sensor1_previous_value -deadband))
  {
    Serial.println(F("Play a tune for user1"));  
       
    // Set the File variable path for the SD card file path
    path = SD.open("/user1"); //Opens a directory on the SD card
    
    // Create the character array MP3 to store the random filename 
    MP3 = selectRandomFileFrom( path, results );
    stringRandomFileName = String(MP3); 
    Serial.print (F("stringRandomFileName=["));  Serial.print(stringRandomFileName);  Serial.println (F("]"));
        
    PathAndFileName = "/user1/" + String( MP3);
    
    // Copy the String variable over to a character array
    PathAndFileName.toCharArray(char_array, str_len);
    Serial.print (F("user1's file result=["));  Serial.print(char_array);  Serial.println (F("]"));
    
    // Start playing a file, then proceed while waiting for it to finish, if not able to play, print error
    if (! musicPlayer.startPlayingFile(char_array)) 
    {
      Serial.print(F("Could not open file: ")); Serial.print (F("user1's random file=[")); Serial.print(char_array); Serial.println (F("]"));
    }

    Serial.print (F("Free SRAM=["));Serial.print(freeRam()); Serial.println (F("]"));

    // if the toothbrush is returned, then stop the tune !
    if( sensor1 > 70   &&   sensor1 > (sensor1_previous_value + deadband)) 
    {
      musicPlayer.stopPlaying();
    }
  }
  //--------------------------------------------------- 
  // user2  
  //---------------------------------------------------    
  // if > 70%, then the toothbrush is present, else it has been removed
  // sense when removed
/*
  if( sensor2 < 70   &&   (sensor2 < sensor2_previous_value -deadband))
  {
    Serial.println(F("Play a tune for user2"));     
    // Set the SD card file path
    File path = SD.open("/user2");
    File results;  
    char* MP3 = selectRandomFileFrom( path, results );
    
    String stringOne =  String("/user2/");    // converting a constant string into a String object  
    String PathAndFileName = String(stringOne + MP3);  
     
    // Length (with one extra character for the null terminator)
    str_len = PathAndFileName.length() + 1;
     
    // Prepare the character array (the buffer) 
    char char_array[str_len];
    
    // Copy it over 
    PathAndFileName.toCharArray(char_array, str_len); 
    Serial.print (F("user2's file result= "));  Serial.println(char_array);
    
    // Start playing a file, then proceed while waiting for it to finish, if not able to play, print error
    if (! musicPlayer.startPlayingFile(char_array)) 
    {
      Serial.print(F("Could not open file: ")); Serial.println (F("user2's randomm file= "));Serial.println(char_array);
    }
  } 
  */
  //--------------------------------------------------- 
  // common 
  //---------------------------------------------------
  // if the toothbrush is returned, then stop the tune !
  if( sensor2 > 70   &&   sensor2 > (sensor2_previous_value + deadband)) 
  {
    musicPlayer.stopPlaying();
    delay(1000);
  }

  // if the toothbrush is returned, then stop the tune !
  if( sensor1 > 70   &&   sensor1 > (sensor1_previous_value + deadband)) 
  {
    musicPlayer.stopPlaying();
    delay(1000);
  }

  //-------------------------- 
   
  if (musicPlayer.stopped()) 
  {
    Serial.println(F("Done playing music"));
  }
  
  delay(1500);
  
  // save sensor readings
  sensor1_previous_value = sensor1;  
  sensor2_previous_value = sensor2;
}

//----------------------------------------------------------------------------------------  
//----------------------------------------------------------------------------------------  
//----------------------------------------------------------------------------------------  
////////////////////////////////////////////////////////////////////////////////////////////////////
/// 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
}

//-----------------------------------------------------------------------------------------------
int freeRam () 
{
  extern int __heap_start, *__brkval; 
  int v; 
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 
}

//-----------------------------------------------------------------------------------------------

User avatar
adafruit_support_rick
 
Posts: 35092
Joined: Tue Mar 15, 2011 11:42 am

Re: VS1053 problems with playing random file

Post by adafruit_support_rick »

I think it might be the result of the temporary String objects you're creating. LIke String("/user1/") and String(MP3);

Try this:

Code: Select all

//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------  
//----------------------------------------------------------------------------------------  
/*
  Toothbrush Music player
  When a toothbrush is removed from a 3D printed holder, which has an imbedded light sensor,
  play a tune randomly selected from a folder on the SD card
  If the toothbrush is returned then withdrawn again, select a new tune.
  
  Designed  to work with the Adafruit VS1053 Codec Breakout 
  ----> https://www.adafruit.com/products/1381

  Written by Anthony Watts
  Dated: 19Sep2014
  
*/
//----------------------------------------------------------------------------------------  

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

// define the pins used
//#define CLK 13       // SPI Clock, shared with SD card
//#define MISO 12      // Input data, from VS1053/SD card
//#define MOSI 11      // Output data, to VS1053/SD card
// Connect CLK, MISO and MOSI to hardware SPI pins. 
// See http://arduino.cc/en/Reference/SPI "Connections"

// These pins are used for the breakout 
#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)

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

// create breakout object!
//Adafruit_VS1053_FilePlayer musicPlayer = Adafruit_VS1053_FilePlayer(SHIELD_CS, SHIELD_DCS, DREQ, CARDCS);
Adafruit_VS1053_FilePlayer musicPlayer = 
  Adafruit_VS1053_FilePlayer(SHIELD_RESET, SHIELD_CS, SHIELD_DCS, DREQ, CARDCS);

/* Analog Inputs  
  A0 = Volume potentiometer
  A1 = Toothbrush sensor 1 (user1)
  A2 = Toothbrush sensor 2 (user2)
*/

// Initialise global variables
int sensor1 = 100;
int sensor2 = 100;
int sensor1_previous_value = 100; 
int sensor2_previous_value = 100;
int Volume = 20;
int deadband = 5;
int str_len = 20;

String stringRandomFileName;
String PathAndFileName;

const char* MP3;
char char_array[20];
File path;
File results; 
 
//----------------------------------------------------------------------------------------  
//----------------------------------------------------------------------------------------  
//----------------------------------------------------------------------------------------  
void setup() 
{
  Serial.begin(9600);
  // F() macro saves arduino SRAM by reading constant text strings direct from Flash Program Memory
  Serial.println(F("------Arduino booting-----------------------"));

  // Determine the amount of free SRAM
  Serial.print (F("Free SRAM=["));Serial.print(freeRam()); Serial.println (F("]"));
  
  //---------------------------------------------------
  // Generate the random number generator seed 
  uint32_t seed = 0; 
  for ( uint8_t i = 10 ; i ; i-- ) 
  {
    seed = ( seed << 5 ) + ( analogRead( 3 ) * 3 );
  }
  randomSeed( seed );  //set random seed
  Serial.print(F("RandomSeed value = "));
  Serial.println(seed);
  
  //---------------------------------------------------  
  // Test the music player is OK
  Serial.println(F("Adafruit VS1053 Library Test"));
  if (! musicPlayer.begin()) 
  { 
     // initialise the music player
     Serial.println(F("Couldn't connect to VS1053 music player"));
     while (1); // don't do anything more
  }
  else
  {
     Serial.println(F("VS1053 music player OK"));
  }
  //---------------------------------------------------   
  // initialise the SD card
  Serial.println(F("Initializing SD card..."));
  SD.begin(CARDCS);
  delay(500);
  
  // test for SD card
  if (SD.begin(CARDCS)) 
  { Serial.println(F("SD card failed, or not present"));}
  else
  { Serial.println(F("SD card OK!"));}
  delay(500); 

  // list all files
  printDirectory(SD.open("/"), 0);
  delay(500); 
   
  //--------------------------------------------------- 
  // Set a default volume for left, right channels. lower numbers == louder volume!
  musicPlayer.setVolume(20,20);
  delay(500);  
  
  //--------------------------------------------------- 
  /***** Two interrupt options! *******/ 
  // This option uses timer0, this means timer1 & t2 are not required
  // (so you can use 'em for Servos, etc) BUT millis() can lose time
  // since we're hitchhiking on top of the millis() tracker
  //musicPlayer.useInterrupt(VS1053_FILEPLAYER_TIMER0_INT);
  
  // This option uses a pin interrupt. No timers required! But DREQ
  // must be on an interrupt pin. For Uno/Duemilanove/Diecimilla
  // that's Digital #2 or #3
  // See http://arduino.cc/en/Reference/attachInterrupt for other pins
  // *** This method is preferred
  // If DREQ is on an interrupt pin (on uno, #2 or #3) we can do background audio playing
  musicPlayer.useInterrupt(VS1053_FILEPLAYER_PIN_INT);  // DREQ int
  
  if (! musicPlayer.useInterrupt(VS1053_FILEPLAYER_PIN_INT))
  {Serial.println(F("DREQ pin is not an interrupt pin"));}

  //---------------------------------------------------  
  Serial.println(F("-----System ready ------"));
  musicPlayer.startPlayingFile("/system/ready.mp3");
  delay(500);

  // Allocate buffers in memory for manipulating strings to minimize RAM memory leaks.
  stringRandomFileName.reserve(12);
  PathAndFileName.reserve(24);
  
}
//----------------------------------------------------------------------------------------  
//----------------------------------------------------------------------------------------  
//----------------------------------------------------------------------------------------  
void loop() 
{
  Serial.println(F("-------Start of Loop-------"));
  Serial.print (F("Free SRAM=["));Serial.print(freeRam()); Serial.println (F("]"));
  
  // Read the volume setting from the potentiometer 
  // The musicPlayer a range of about 100, where 100 for the  minimum and 0 is maximum
  // By swapping the location of the minimum and the maximum in the map function, 0 = quietest and 60 = loudest 
  Volume = map(analogRead(A0), 0, 1023, 0, 100); 
  
  // set both left and right channels to the same volume 
  musicPlayer.setVolume(Volume, Volume);
  Serial.print (F("Volume= "));  Serial.println(100-Volume); // 100-Volume to display larger number for geater volume
  
  // read the toothbrush sensors connected to A1 and A2 and scale the signal 0% to 100%
  sensor1 = map(analogRead(A1), 0, 1023, 0, 100);
  Serial.print (F("user1's sensor= "));  Serial.println(sensor1);
  
  sensor2 = map(analogRead(A2), 0, 1023, 0, 100);
  Serial.print (F("user2's sensor= "));  Serial.println(sensor2);
 
  //---------------------------------------------------
  // user1
  //---------------------------------------------------  
  // if sensor1 < 70% and less than previous value, then the toothbrush has been removed, so play a tune
  if( sensor1 < 70   &&   (sensor1 < sensor1_previous_value -deadband))
  {
    Serial.println(F("Play a tune for user1"));  
       
    // Set the File variable path for the SD card file path
    path = SD.open("/user1"); //Opens a directory on the SD card
    
    // Create the character array MP3 to store the random filename 
    MP3 = selectRandomFileFrom( path, results );
    Serial.print (F("stringRandomFileName=["));  Serial.print(MP3);  Serial.println (F("]"));
        
    PathAndFileName = "/user1/";
    PathAndFileName += MP3;
    
     Serial.print (F("user1's file result=["));  Serial.print(PathAndFileName.c_str());  Serial.println (F("]"));
    
    // Start playing a file, then proceed while waiting for it to finish, if not able to play, print error
    if (! musicPlayer.startPlayingFile(PathAndFileName.c_str())) 
    {
      Serial.print(F("Could not open file: ")); Serial.print (F("user1's random file=[")); Serial.print(PathAndFileName.c_str()); Serial.println (F("]"));
    }

    Serial.print (F("Free SRAM=["));Serial.print(freeRam()); Serial.println (F("]"));

    // if the toothbrush is returned, then stop the tune !
    if( sensor1 > 70   &&   sensor1 > (sensor1_previous_value + deadband)) 
    {
      musicPlayer.stopPlaying();
    }
  }
  //--------------------------------------------------- 
  // user2  
  //---------------------------------------------------    
  // if > 70%, then the toothbrush is present, else it has been removed
  // sense when removed
/*
  if( sensor2 < 70   &&   (sensor2 < sensor2_previous_value -deadband))
  {
    Serial.println(F("Play a tune for user2"));     
    // Set the SD card file path
    File path = SD.open("/user2");
    File results;  
    char* MP3 = selectRandomFileFrom( path, results );
    
    PathAndFileName = "/user2/";
    PathAndFileName += MP3;  
     
    Serial.print (F("user2's file result= "));  Serial.println(PathAndFileName.c_str());
    
    // Start playing a file, then proceed while waiting for it to finish, if not able to play, print error
    if (! musicPlayer.startPlayingFile(PathAndFileName.c_str())) 
    {
      Serial.print(F("Could not open file: ")); Serial.println (F("user2's randomm file= "));Serial.println(PathAndFileName.c_str());
    }
  } 
  */
  //--------------------------------------------------- 
  // common 
  //---------------------------------------------------
  // if the toothbrush is returned, then stop the tune !
  if( sensor2 > 70   &&   sensor2 > (sensor2_previous_value + deadband)) 
  {
    musicPlayer.stopPlaying();
    delay(1000);
  }

  // if the toothbrush is returned, then stop the tune !
  if( sensor1 > 70   &&   sensor1 > (sensor1_previous_value + deadband)) 
  {
    musicPlayer.stopPlaying();
    delay(1000);
  }

  //-------------------------- 
   
  if (musicPlayer.stopped()) 
  {
    Serial.println(F("Done playing music"));
  }
  
  delay(1500);
  
  // save sensor readings
  sensor1_previous_value = sensor1;  
  sensor2_previous_value = sensor2;
}

//----------------------------------------------------------------------------------------  
//----------------------------------------------------------------------------------------  
//----------------------------------------------------------------------------------------  
////////////////////////////////////////////////////////////////////////////////////////////////////
/// 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
}

//-----------------------------------------------------------------------------------------------
int freeRam () 
{
  extern int __heap_start, *__brkval; 
  int v; 
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 
}

//-----------------------------------------------------------------------------------------------

User avatar
anthonyw
 
Posts: 10
Joined: Thu Nov 22, 2012 9:09 am

Re: VS1053 problems with playing random file

Post by anthonyw »

by moving the SDopen commands up into the setup() function
and creating two path files
i have reduced the memory leaks.
I still get the occasional memory leak when interrupting a tune.

Thanks for your help

Here is the latest versioin

Code: Select all

//----------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------  
//----------------------------------------------------------------------------------------  
/*
  Toothbrush Music player
  When a toothbrush is removed from a 3D printed holder, which has an imbedded light sensor,
  play a tune randomly selected from a folder on the SD card
  If the toothbrush is returned then withdrawn again, select a new tune.
  
  Designed  to work with the Adafruit VS1053 Codec Breakout 
  ----> https://www.adafruit.com/products/1381

  Written by Anthony Watts
  Dated: 20Sep2014
  
*/
//----------------------------------------------------------------------------------------  

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

// define the pins used
//#define CLK 13       // SPI Clock, shared with SD card
//#define MISO 12      // Input data, from VS1053/SD card
//#define MOSI 11      // Output data, to VS1053/SD card
// Connect CLK, MISO and MOSI to hardware SPI pins. 
// See http://arduino.cc/en/Reference/SPI "Connections"

// These pins are used for the breakout 
#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)

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

// create breakout object!
//Adafruit_VS1053_FilePlayer musicPlayer = Adafruit_VS1053_FilePlayer(SHIELD_CS, SHIELD_DCS, DREQ, CARDCS);
Adafruit_VS1053_FilePlayer musicPlayer = 
  Adafruit_VS1053_FilePlayer(SHIELD_RESET, SHIELD_CS, SHIELD_DCS, DREQ, CARDCS);

/* Analog Inputs  
  A0 = Volume potentiometer
  A1 = Toothbrush sensor 1 (gabby)
  A2 = Toothbrush sensor 2 (mitch)
*/

// Initialise global variables
int sensor1 = 100;
int sensor2 = 100;
int sensor1_previous_value = 100; 
int sensor2_previous_value = 100;
int Volume = 20;
int deadband = 5;
int str_len = 20;

String PathAndFileName;

char* MP3;
File path1;
File path2;
File results; 
 
//----------------------------------------------------------------------------------------  
//----------------------------------------------------------------------------------------  
//----------------------------------------------------------------------------------------  
void setup() 
{
  Serial.begin(9600);
  // F() macro saves arduino SRAM by reading constant text strings direct from Flash Program Memory
  Serial.println(F("------Arduino booting-----------------------"));

  // Determine the amount of free SRAM
  Serial.print (F("Free SRAM=["));Serial.print(freeRam()); Serial.println (F("]"));
  
  //---------------------------------------------------
  // Generate the random number generator seed 
  uint32_t seed = 0; 
  for ( uint8_t i = 10 ; i ; i-- ) 
  {
    seed = ( seed << 5 ) + ( analogRead( 3 ) * 3 );
  }
  randomSeed( seed );  //set random seed
  Serial.print(F("RandomSeed value = "));
  Serial.println(seed);
  
  //---------------------------------------------------  
  // Test the music player is OK
  Serial.println(F("Adafruit VS1053 Library Test"));
  if (! musicPlayer.begin()) 
  { 
     // initialise the music player
     Serial.println(F("Couldn't connect to VS1053 music player"));
     while (1); // don't do anything more
  }
  else
  {
     Serial.println(F("VS1053 music player OK"));
  }
  //---------------------------------------------------   
  // initialise the SD card
  Serial.println(F("Initializing SD card..."));
  SD.begin(CARDCS);
  delay(500);
  
  // test for SD card
  if (SD.begin(CARDCS)) 
  { Serial.println(F("SD card failed, or not present"));}
  else
  { Serial.println(F("SD card OK!"));}
  delay(500); 

  // list all files
  printDirectory(SD.open("/"), 0);
  delay(500); 
   
  //--------------------------------------------------- 
  // Set a default volume for left, right channels. lower numbers == louder volume!
  musicPlayer.setVolume(20,20);
  delay(500);  
  
  //--------------------------------------------------- 
  /***** Two interrupt options! *******/ 
  // This option uses timer0, this means timer1 & t2 are not required
  // (so you can use 'em for Servos, etc) BUT millis() can lose time
  // since we're hitchhiking on top of the millis() tracker
  //musicPlayer.useInterrupt(VS1053_FILEPLAYER_TIMER0_INT);
  
  // This option uses a pin interrupt. No timers required! But DREQ
  // must be on an interrupt pin. For Uno/Duemilanove/Diecimilla
  // that's Digital #2 or #3
  // See http://arduino.cc/en/Reference/attachInterrupt for other pins
  // *** This method is preferred
  // If DREQ is on an interrupt pin (on uno, #2 or #3) we can do background audio playing
  musicPlayer.useInterrupt(VS1053_FILEPLAYER_PIN_INT);  // DREQ int
  
  if (! musicPlayer.useInterrupt(VS1053_FILEPLAYER_PIN_INT))
  {Serial.println(F("DREQ pin is not an interrupt pin"));}

  //---------------------------------------------------  
  Serial.println(F("-----System ready ------"));
  musicPlayer.startPlayingFile("/system/ready.mp3");
  delay(500);

  // Allocate buffers in memory for manipulating strings to minimize RAM memory leaks.
  PathAndFileName.reserve(24);

  // Set the File variable path# for the SD card file paths
  path1 = SD.open("/gabby"); //Opens a directory on the SD card
  delay(500);
  path2 = SD.open("/mitch"); //Opens a directory on the SD card
  delay(500);
}
//----------------------------------------------------------------------------------------  
//----------------------------------------------------------------------------------------  
//----------------------------------------------------------------------------------------  
void loop() 
{
  Serial.println(F("-------Start of Loop-------"));
  Serial.print (F("Free SRAM=["));Serial.print(freeRam()); Serial.println (F("]"));
  
  // Read the volume setting from the potentiometer 
  // The musicPlayer a range of about 100, where 100 for the  minimum and 0 is maximum
  // By swapping the location of the minimum and the maximum in the map function, 0 = quietest and 60 = loudest 
  Volume = map(analogRead(A0), 0, 1023, 0, 100); 
  
  // set both left and right channels to the same volume 
  musicPlayer.setVolume(Volume, Volume);
  Serial.print (F("Volume= "));  Serial.println(100-Volume); // 100-Volume to display larger number for geater volume
  
  // read the toothbrush sensors connected to A1 and A2 and scale the signal 0% to 100%
  sensor1 = map(analogRead(A1), 0, 1023, 0, 100);
  Serial.print (F("gabby's sensor= "));  Serial.println(sensor1);
  
  sensor2 = map(analogRead(A2), 0, 1023, 0, 100);
  Serial.print (F("mitch's sensor= "));  Serial.println(sensor2);
 
  //---------------------------------------------------
  // gabby
  //---------------------------------------------------  
  // if sensor1 < 70% and less than previous value, then the toothbrush has been removed, so play a tune
  if( sensor1 < 70   &&   (sensor1 < sensor1_previous_value -deadband))
  {
    Serial.println(F("Play a tune for gabby"));  
       
    // Update the character array MP3 with a the random filename 
    MP3 = selectRandomFileFrom( path1, results );
    // Update the PathAndFileName string with the directory then append the filename
    PathAndFileName = "/gabby/";
    PathAndFileName += MP3;
    Serial.print (F("gabby's file result=["));  Serial.print(PathAndFileName.c_str());  Serial.println (F("]"));
    
    // Start playing a file, then proceed while waiting for it to finish, if not able to play, print error
    if (! musicPlayer.startPlayingFile(PathAndFileName.c_str())) 
    {
      Serial.print(F("Could not open file: ")); Serial.print (F("gabby's random file=[")); Serial.print(PathAndFileName.c_str()); Serial.println (F("]"));
    }
 
    // if the toothbrush is returned, then stop the tune !
    if( sensor1 > 70   &&   sensor1 > (sensor1_previous_value + deadband)) 
    {
      musicPlayer.stopPlaying();
      path1.close();
      results.close();
    }
  }

//---------------------------------------------------
  // mitch
  //---------------------------------------------------  
  // if sensor2 < 70% and less than previous value, then the toothbrush has been removed, so play a tune
  if( sensor2 < 70   &&   (sensor2 < sensor2_previous_value -deadband))
  {
    Serial.println(F("Play a tune for mitch"));  
 
    // Update the character array MP3 with a random filename 
    MP3 = selectRandomFileFrom( path2, results );
    // Update the PathAndFileName string with the directory then append the filename       
    PathAndFileName = "/mitch/";
    PathAndFileName += MP3;
    Serial.print (F("mitch's file result=["));  Serial.print(PathAndFileName.c_str());  Serial.println (F("]"));
    
    // Start playing a file, then proceed while waiting for it to finish, if not able to play, print error
    if (! musicPlayer.startPlayingFile(PathAndFileName.c_str())) 
    {
      Serial.print(F("Could not open file: ")); Serial.print (F("mitch's random file=[")); Serial.print(PathAndFileName.c_str()); Serial.println (F("]"));
    }
   
    // if the toothbrush is returned, then stop the tune !
    if( sensor2 > 70   &&   sensor2 > (sensor2_previous_value + deadband)) 
    {
      musicPlayer.stopPlaying();
      path2.close();
      results.close();
    }
  }

  //--------------------------------------------------- 
  // common 
  //---------------------------------------------------
  // if the toothbrush is returned, then stop the tune !
  if( sensor2 > 70   &&   sensor2 > (sensor2_previous_value + deadband)) 
  {
    musicPlayer.stopPlaying();
    delay(1000);
  }

  // if the toothbrush is returned, then stop the tune !
  if( sensor1 > 70   &&   sensor1 > (sensor1_previous_value + deadband)) 
  {
    musicPlayer.stopPlaying();
    delay(1000);
  }

  //-------------------------- 
   
  if (musicPlayer.stopped()) 
  {
    Serial.println(F("Done playing music"));
  }
  
  delay(1500);
  
  // save sensor readings
  sensor1_previous_value = sensor1;  
  sensor2_previous_value = sensor2;
}

//----------------------------------------------------------------------------------------  
//----------------------------------------------------------------------------------------  
//----------------------------------------------------------------------------------------  
////////////////////////////////////////////////////////////////////////////////////////////////////
/// 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
}

//-----------------------------------------------------------------------------------------------
int freeRam () 
{
  extern int __heap_start, *__brkval; 
  int v; 
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 
}

//-----------------------------------------------------------------------------------------------

User avatar
adafruit_support_rick
 
Posts: 35092
Joined: Tue Mar 15, 2011 11:42 am

Re: VS1053 problems with playing random file

Post by adafruit_support_rick »

I don't see anything that would leak. Except possibly for this:

Code: Select all

    // if the toothbrush is returned, then stop the tune !
    if( sensor1 > 70   &&   sensor1 > (sensor1_previous_value + deadband)) 
    {
      musicPlayer.stopPlaying();
      path1.close();
      results.close();
    }
You're calling path1.close (and path2.close) when you stop the tune. Since you're now opening path1 and path2 in setup, you don't want to close them.

Also, you're not actually doing anything with results - the assignment you make to result in selectRandomFileFrom won't get propagated back to results, since it's a call by value, not a call by reference.
You can change it this way:

Code: Select all

////////////////////////////////////////////////////////////////////////////////////////////////////
// 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
}
Change the calls to selectRandomFileFrom to add a '&' before results:

Code: Select all

MP3 = selectRandomFileFrom( path2, &results );

User avatar
anthonyw
 
Posts: 10
Joined: Thu Nov 22, 2012 9:09 am

Re: VS1053 problems with playing random file

Post by anthonyw »

I have implemented the changes you suggested and now I am not seeing memory leaks.
I worked on this program for many days, so to have these problems resolved is really great.
Thank you again.

I did a bit of research on call by value and call by reference, but I think I will need to do more to fully understand.

User avatar
adafruit_support_rick
 
Posts: 35092
Joined: Tue Mar 15, 2011 11:42 am

Re: VS1053 problems with playing random file

Post by adafruit_support_rick »

Great!

User avatar
staticairport
 
Posts: 4
Joined: Fri Sep 16, 2016 3:49 pm

Re: VS1053 problems with playing random file

Post by staticairport »

anthonyw: can you post your final de-bugged code that ended up working? I am doing a similar project, where I need a motion sensor to trigger Adafruit music maker to play a random mp3 file from my SD card.
Thanks so much!

User avatar
snhs
 
Posts: 21
Joined: Sun Dec 25, 2016 4:44 am

Re: VS1053 problems with playing random file

Post by snhs »

Hey Stat, were you able to pay the mp3 files triggered by the motion sensor. I am also trying to do the same thing, Initially just playing the mp3 files but they wont play. SD card shows the file names, vs1053 plays the tone but not the mp3.

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

Return to “General Project help”