dfplayer mini, random/folder track?

I'm making a remote control (via nrf24l01) that among other things, uses a Dfplayer mini to play select tracks as a sort of sound board. However I'd also like to have several tracks play at random from separate folders.

One for the "random tracks"
Another for the sounds played from buttons on the remote.

So far I have it working where the following sketch plays track "0001.mp3" from folder "Mp3" via an analog switch on the remote.

I'd like to Play Tracks 1-10 via the remote buttons in from separate folder, While a random track (sound) plays once Every 3 min.

I'm using the Makuna Library. and I've tried placing tracks 1-10 in a folder "02" and changing:
"mp3.playMp3FolderTrack(1); // sd:/mp3/0001.mp3"
"mp3.playFolderTrack(2, 1);"

following This reference

Nothing I have tried has worked, I've tried moving files renaming them and the folder from 2 to 4 digit numbers and placing a random track play in the loop with a delay but it locks the button out during play.


Can anyone help? or offer better suggestions on how to do what I'm looking to do?

Thank you!

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <SoftwareSerial.h>
#include <DFMiniMp3.h>
#define led 3

RF24 radio(7, 8); // CE, CSN
const byte addresses[][6] = {"00001", "00002"};
int buttonValue;
// implement a notification class,
// its member methods will get called
//
class Mp3Notify
{
public:
static void PrintlnSourceAction(DfMp3_PlaySources source, const char* action)
{
if (source & DfMp3_PlaySources_Sd)
{
Serial.print("SD Card, ");
}
if (source & DfMp3_PlaySources_Usb)
{
Serial.print("USB Disk, ");
}
if (source & DfMp3_PlaySources_Flash)
{
Serial.print("Flash, ");
}
Serial.println(action);
}
static void OnError(uint16_t errorCode)
{
// see DfMp3_Error for code meaning
Serial.println();
Serial.print("Com Error ");
Serial.println(errorCode);
}
static void OnPlayFinished(DfMp3_PlaySources source, uint16_t track)
{
Serial.print("Play finished for #");
Serial.println(track);
}
static void OnPlaySourceOnline(DfMp3_PlaySources source)
{
PrintlnSourceAction(source, "online");
}
static void OnPlaySourceInserted(DfMp3_PlaySources source)
{
PrintlnSourceAction(source, "inserted");
}
static void OnPlaySourceRemoved(DfMp3_PlaySources source)
{
PrintlnSourceAction(source, "removed");
}
};

// instance a DFMiniMp3 object,
// defined with the above notification class and the hardware serial class
//
//DFMiniMp3<HardwareSerial, Mp3Notify> mp3(Serial1);

// Some arduino boards only have one hardware serial port, so a software serial port is needed instead.
// comment out the above definition and uncomment these lines
SoftwareSerial secondarySerial(10, 11); // RX, TX
DFMiniMp3<SoftwareSerial, Mp3Notify> mp3(secondarySerial);

void setup() {
pinMode(3, OUTPUT);
radio.begin();
radio.openWritingPipe(addresses[1]); // 00002
radio.openReadingPipe(1, addresses[0]); // 00001
radio.setPALevel(RF24_PA_MIN);
Serial.begin(115200);

Serial.println("initializing...");

mp3.begin();

uint16_t volume = mp3.getVolume();
Serial.print("volume ");
Serial.println(volume);
mp3.setVolume(24);

uint16_t count = mp3.getTotalTrackCount(DfMp3_PlaySource_Sd);
Serial.print("files ");
Serial.println(count);

Serial.println("starting...");
}

void waitMilliseconds(uint16_t msWait)
{
uint32_t start = millis();

while ((millis() - start) < msWait)
{
// calling mp3.loop() periodically allows for notifications
// to be handled without interrupts
mp3.loop();
delay(1);
}
}

void loop() {
delay(5);

radio.startListening();
buttonValue = analogRead(A2);
if ( radio.available()) {
while (radio.available()) {
radio.read(&buttonValue, sizeof(buttonValue));
}}
if (buttonValue>= 1013 && buttonValue<= 1015) {
digitalWrite(led, HIGH);
Serial.println("track 1");
mp3.playMp3FolderTrack(1); // sd:/mp3/0001.mp3
}
else {
digitalWrite(led, LOW);
}

}``

BubbleHockey:
Can anyone help? or offer better suggestions on how to do what I'm looking to do?

Personally, I've found DFPlayerMini_Fast.h is a better written lib and much easier to work with.

Also, you can do something like this:

randomInt = random(1, 10);
myMP3.playFolder(1, randomInt);

while ensuring the names of all the files in the folder are prepended by a zero-padded 3 digit number AND the folder name consists of a zero-padded 2 digit number. See the DFPlayerMini_Fast.h readme for more info on this.

Power_Broker:
Personally, I've found DFPlayerMini_Fast.h is a better written lib and much easier to work with.

Also, you can do something like this:

randomInt = random(1, 10);

myMP3.playFolder(1, randomInt);



while ensuring the names of all the files in the folder are prepended by a zero-padded 3 digit number AND the folder name consists of a zero-padded 2 digit number. See the DFPlayerMini_Fast.h readme for more info on this.

Thank you, I was using the makuna because I was told the same thing about it and had gotten it working on another sketch in the different project so just copied it over.

However As per your suggestion I have starting playing around with the dfplayermini_fast.h and came up with this and it works. However I'm struggling on where to implement the code you suggested.

I HAVE switched to placing the button sounds to the MP3 folder (ie: sd:/mp3/001_alarm.mp3) files 001-010

In folder #2 I'll be placing all the random sounds I'd like to have play once every 3 min. without interrupting the abilities for the buttons to play sounds and execute any functions. (file example:: sd:/02/001_beep.mp3) There are 144 sounds I'd like to play randomly in that folder all named with same prefix scheme from 001-144.

Do I need something to recognize the folder(s) and get play count?

In the sketch below when I replace:
"myMp3.Play(1)"
with
"myMp3.play(2)"

nothing plays. track "2" is named: sd/mp3/002_scream.mp3

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#define led 3
#include <SoftwareSerial.h>
#include <DFPlayerMini_Fast.h>

SoftwareSerial mySerial(10, 11); // RX, TX
DFPlayerMini_Fast myMP3;

RF24 radio(7, 8); // CE, CSN
const byte addresses[][6] = {"00001", "00002"};
int buttonValue;

void setup() {
pinMode(3, OUTPUT);
radio.begin();
radio.openWritingPipe(addresses[1]); // 00002
radio.openReadingPipe(1, addresses[0]); // 00001
radio.setPALevel(RF24_PA_MIN);

Serial.begin(115200);
mySerial.begin(9600);

myMP3.begin(mySerial);

myMP3.volume(24);
delay(20);
}
void loop() {
delay(5);
radio.startListening();
buttonValue = analogRead(A2);
if ( radio.available()) {
while (radio.available()) {
radio.read(&buttonValue, sizeof(buttonValue));
}}
if (buttonValue>= 1013 && buttonValue<= 1015) {
digitalWrite(led, HIGH);
myMP3.play(2);
}
else {
digitalWrite(led, LOW);
}
}``

Here is your code properly formatted with correct code tags (replace your current sketch with this and use it as a baseline for future edits):

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <SoftwareSerial.h>
#include <DFPlayerMini_Fast.h>


#define led 3


SoftwareSerial mySerial(10, 11); // RX, TX
DFPlayerMini_Fast myMP3;
RF24 radio(7, 8); // CE, CSN

const byte addresses[][6] = {"00001", "00002"};
int buttonValue;


void setup()
{
  pinMode(led, OUTPUT);
  radio.begin();
  radio.openWritingPipe(addresses[1]); // 00002
  radio.openReadingPipe(1, addresses[0]); // 00001
  radio.setPALevel(RF24_PA_MIN);

  Serial.begin(115200);
  mySerial.begin(9600);

  myMP3.begin(mySerial);

  myMP3.volume(24);
  delay(20);
}


void loop()
{
  delay(5);
  
  radio.startListening();
  buttonValue = analogRead(A2);
  
  if (radio.available())
    while (radio.available())
      radio.read(&buttonValue, sizeof(buttonValue));
     
  if (buttonValue >= 1013 && buttonValue <= 1015)
  {
    digitalWrite(led, HIGH);
    myMP3.play(2);
  }
  else
    digitalWrite(led, LOW);
}

Here's something from the library's readme that you need to understand to make your code work:

Important Notes:
If you use the playFromMP3Folder() or playAdvertisement() functions, the files to be played must be organised in an extremely precise manner. The "MP3 Folder" must be in the root of the storage device (such as a MicroSD card) and it must be called "mp3". The folder name is probably not case-sensitive. Likewise, the "Advertisement" folder used for short interruptions to main audio playback must also be in the root of the storage device, and it must be called "advert". In addition, audio filenames must be prepended by a zero-padded 4-digit number if the files are in the root or "mp3" folders. If the files are played from folders other than root or "mp3", the folder names must be zero-padded 2-digit numbers while their contents must be audio files with names prepended by a zero-padded 3-digit number.

As for where to put my code snippet, you would insert it where you have "myMp3.play(2)".

Power_Broker:
As for where to put my code snippet, you would insert it where you have "myMp3.play(2)".

Ok, so I think I did not fully explain or miscommunicated something along the way.

I now got the buttons working, playing each file from folder "02" on the sd card. by adding in

int16_t numSdTracks();
int16_t numFolders();
void playFolder(uint8_t folderNum, uint8_t trackNum);

and

myMP3.playFolder(2, 1); // in place of myMp3.play(2) (moving button sounds again over to folder 02)

However:
The remaining questions are;
Why did calling "myMp3.play(2)" from the mp3 folder play nothing and "myMp3.play(1)" does. (I have double checked and all files are on the SD card correctly as the readme states) I'm trying to really understand what Im doing as I'm still learning.

And:
For the random play I would like to be in addition to the buttons. so It would be something running in the background while we are waiting for the buttons to be pushed. Again, playing 1 random track every 3 min.

I've tried placing the code in the loop and get this error: "'randomInt' was not declared in this scope"

Looking at the readme, I only see "void randomAll();"
But I want it to restrict random play to only one folder (mp3 folder if possible) and have it not effect the use of the other buttons and inputs in the sketch. (when i was using DFMiniMp3.h and using a delay in the loop it did)

Thanks

BubbleHockey:
Why did calling "myMp3.play(2)" from the mp3 folder play nothing and "myMp3.play(1)" does.

Do you have two tracks in the folder "mp3"?

BubbleHockey:
For the random play I would like to be in addition to the buttons. so It would be something running in the background while we are waiting for the buttons to be pushed. Again, playing 1 random track every 3 min.

You'll need a timer (FireTimer.h can help with that) and "myMp3.isPlaying()" to determine if X-amount of time has passed since the last song has played. You then use "random()" to figure out what song to play and "myMp3.isPlaying()" to keep from playing one song before the current song finishes.

BubbleHockey:
I've tried placing the code in the loop and get this error: "'randomInt' was not declared in this scope"

Did you declare "randomInt"?

BubbleHockey:
Looking at the readme, I only see "void randomAll();"
But I want it to restrict random play to only one folder (mp3 folder if possible) and have it not effect the use of the other buttons and inputs in the sketch. (when i was using DFMiniMp3.h and using a delay in the loop it did)

In that case, you'll pass the output of "random()" to "myMp3.play()" instead of "myMp3.playFolder()"

I think you may want to use the new Advertise function that PowerBroker worked into the new DFMiniFast.h library. You can sent the FireTimer or use the millis() function to have the file go off every 3 minutes, and that would not restart the whole 1st folder all over again, but pause it and then play once your 2nd Folder (now named Advert) would go off, as it then resumes right where it left off from the interruption. What you CANNOT do is use the random() function in the Advert folder- it doesn't work that way. But if you truly have 144 startle sounds in your 2nd folder- does it really have to be random? Is someone going to realize that 144 tracks are going off in order and wait for them to repeat?

Power_Broker:
Do you have two tracks in the folder "mp3"?

You'll need a timer (FireTimer.h can help with that) and "myMp3.isPlaying()" to determine if X-amount of time has passed since the last song has played. You then use "random()" to figure out what song to play and "myMp3.isPlaying()" to keep from playing one song before the current song finishes.

Did you declare "randomInt"?

In that case, you'll pass the output of "random()" to "myMp3.play()" instead of "myMp3.playFolder()"

OK, so after a lot of reading and even more playing around. I got a few things to work but not like i want them to. Mostly I'm having trouble declaring randomInt or getting the DFPlayerMini_Fast.h to play random files from JUST the MP3 folder. Obviously randomall(); plays all folders.
I know its something silly I'm overlooking but I'm struggling.

So for the sake of hopefully understanding what I'm missing and doing wrong, I've taken away all the remote and just focusing on getting the random files to play via the mp3 folder every 3 min (9 seconds in sketch), and Created this sketch using a simple millis() function. It works fine but obviously it only plays track 001 from the MP3 folder.

Please help! :slight_smile:

#include <SoftwareSerial.h>
#include <DFPlayerMini_Fast.h>

const unsigned long eventInterval = 9000;
unsigned long previousTime = 0;

SoftwareSerial mySerial(10, 11); // RX, TX
DFPlayerMini_Fast myMP3;

void setup() {
int16_t numSdTracks();
int16_t numFolders();

Serial.begin(115200);
mySerial.begin(9600);

myMP3.begin(mySerial);

myMP3.volume(24);
}

void loop() {

unsigned long currentTime = millis();

if ( currentTime - previousTime >= eventInterval) {

myMP3.play(1);
previousTime = currentTime;
}

}``

halloweenrick:
What you CANNOT do is use the random() function in the Advert folder- it doesn't work that way. But if you truly have 144 startle sounds in your 2nd folder- does it really have to be random? Is someone going to realize that 144 tracks are going off in order and wait for them to repeat?

I did see some post a while ago about the Advert folder and random, so I had thrown that out a while ago.
It IS important that it is random despite the large amount of files. as I do not want to always hear the same tracks in order every time the system comes online, as they are sound files for a droid, and I want this to have a more organic feel, rather then an ordered set program. (even tho it is).

I'm honestly not sure how to help with this thread anymore. I already provided the code that will allow you to play a random file in a folder and explained how to properly name the files.

BubbleHockey, I think you are getting confused between the RandomAll() function in PowerBroker's DF Mini Fast library code, and using Random as an Arduino function in the IDE.
You are correct in that RandomAll does work in the DF Mini Fast Library, and that it plays all files randomly on the MP3 player.
What PowerBroker and I want you to do is define Random as a function in Arduino IDE code, then call THAT random number in your Folder 1.
To simplify further, let's take the example code of the DF Mini Fast Library and add a Random number function. I have done that for you below. It does compile for me, and I do have a DF Mini player here I will can check if need be. I will need some time to load some files onto a MicroSd card. Please run this code and see if it works as you intend in calling a Random file from your Folder 1. Try to run it several times and see if you get a different MP3 playing each time you run it.

#include <SoftwareSerial.h>
#include <DFPlayerMini_Fast.h>

SoftwareSerial mySerial(10, 11); // RX, TX
DFPlayerMini_Fast myMP3;
long randomInt = random(1,10);
void setup()
{
  Serial.begin(115200);
  mySerial.begin(9600);

  myMP3.begin(mySerial);
    
  Serial.println("Setting volume to max");
  myMP3.volume(30);
  delay(20);
  
  Serial.println("Playing track 1 for 5 sec");
  myMP3.playFolder(1, randomInt);
  delay(5000);

  Serial.println("Sleeping for 5 sec");
  myMP3.sleep();
  delay(5000);

  Serial.println("Waking up");
  myMP3.wakeUp();

  Serial.println("Looping track 1");
  myMP3.loop(1);
}

void loop()
{
  //do nothing
}]