Random feature in DF Player

Hello everyone,

I read a post in 2023 about the RandomAll() function only randomizing the first 255 tracks, no matter how many folders & MP3s are stored on the SD card.

https://forum.arduino.cc/t/dfr-mp3-mini-player-randomall-only-255-tracks/1077175/24

Terrypin, how did you work around this? If you wrote your own custom code for a truly random playback involving >255 MP3 files, may you share it here?

Thanks for your help!
Tom Hammond

Since the DFPlayer can’t scan or report the SD card contents, the microcontroller cannot discover the file structure automatically.

To handle this, you need to know or predefine the file organization in your code and then your code can randomly choose a folder and track from that list and command the DFPlayer to play it.

Without this, you cannot randomize beyond the first 255 tracks using built-in commands - it’s a firmware limitation.

This likely relates to the file management system integrated into the chip firmware, where the file system structure is defined by the firmware as:
01 Folder/001xxx.mp3, 01 Folder/002xxx.mp3, 02 Folder/001xxx.mp3, etc. Therefore, you should use a command for random playback from a specified folder, such as:

I’m reluctant to contradict you while I’m unable to physically double check; away from PC on hols. But the DFR inbuilt randomAll command ignores folder structure. It plays a track chosen randomly between the first and last tracks chronologically added to the mSD card.

My JukeBox has nearly 3,000 files within 26 folders. Switched to its random mode before power up, it will sometimes play tracks from any of those 26. So if I said otherwise a couple of years ago I was mistaken.

It’s possible that Tom was referring to the more challenging issue of playing a folder randomly without repetition?

You should since I spoke from memory, your example clearly shows I’m wrong in my assumption… may be better firmware exists nowadays?

PS: your old claim

Could still be my mistake, so I’ll look into it again next week. That is assuming I can still understand what was a complicated and messily coded project!

EDIT:

And having read through that old thread of mine I’m thinking maybe I abandoned the use of randomAll() and used the same ‘shuffling, no repetition’ method entirely?

Testing could be done by having 99 directorys each with ten files and have the sound say “directory xxx file yy” and fill in the DF player by writing directories one after the other in ascending order.

If the function is limited to the first 255 written files, you’ll never hear a directory above 26 and as you have 990 files, chances of getting one from the far end should be (990-255)/990=0,742

➜ almost 3/4 chances to get something from the far end if the random algorithm is good so we shouldn’t have to wait for too long to confirm if it works or not.

Generating the folder architecture and sound files can easily be done on a Mac at least with a small shell script using say and afconvert

If I get a chance I’ll give it a try.

Yes, I had a similar plan in mind, probably using my existing recordings of “zero” to “sixty” , or even simply my full file listing. However, before any such tests, I can at least now confirm my earlier growing suspicion. Using my Dropbox account I was able to downoad the likely sketch used in JukeBox to my iPhone. A methodical search found no use of randomAll(). Instead, basically, I selected a random folder and then used a shuffle & no repeat function to randomly play from it.

Doesn’t prove that randomAll() is constrained to 255 tracks, of course. It might have been my need to avoid repetition and ensure exhaustive coverage that motivated me against using it, despite its tempting simplicity.

Anyway, a simple sketch should resolve that question definitively.

So I wrote the script on my Mac to generate the sounds. I had to use lame instead of afconvert to generate the mp3, so lame needs to be installed first. (brew install lame)

here is the code

#!/bin/bash

# Make sure LAME is installed: brew install lame
# create a TEST directory and save this file as generate.sh inside
# open a terminal and change directory to TEST
# change file to be executable: chmod +x generate.sh
# execute the script: ./generate.sh


OUTDIR="./DFPLAYER"
mkdir -p "$OUTDIR"

for d in $(seq -w 1 99); do
  FOLDER="$OUTDIR/$d"
  mkdir -p "$FOLDER"

  for f in $(seq -w 1 9); do
    FILEPATH="$FOLDER/00$f.mp3"
    TEXT="directory $d file $f"

    # Generate AIFF from TTS in English
    say -v Alex "$TEXT" -o "$FOLDER/tmp.aiff"

    # Convert AIFF to MP3 using LAME (mono, low bitrate for speech)
    lame --preset voice -m m --quiet "$FOLDER/tmp.aiff" "$FILEPATH"

    rm "$FOLDER/tmp.aiff"
  done
done

echo "Done: files created in $OUTDIR"

if your Mac does not have English as its main default language, you have to switch temporarily the language (don't even reboot) and launch terminal after that so that the say command does speak in "proper" English (and not with the French accent or saying "UN" instead of "ONE" when trying to read out "1".

The arduino sketch could be something like that (typed here, totally untested)

#include "SoftwareSerial.h"
#include "DFRobotDFPlayerMini.h"

const byte rxPin = 10;       // Arduino RX → DFPlayer TX
const byte txPin = 11;       // Arduino TX → DFPlayer RX
const byte busyPin = 9;      // DFPlayer BUSY pin

SoftwareSerial mySerial(rxPin, txPin);
DFRobotDFPlayerMini myDFPlayer;

void setup() {
  pinMode(busyPin, INPUT);
  mySerial.begin(9600);
  Serial.begin(115200);

  if (!myDFPlayer.begin(mySerial)) {
    Serial.println("Unable to begin:");
    while (true) yield();
  }

  myDFPlayer.volume(20);
}

void loop() {
  // play a random file from the SD
  myDFPlayer.randomAll();

  // allow DFPlayer to start playback
  delay(50);

  // synchronous wait until file is done playing
  while (digitalRead(busyPin) == LOW) delay(10);

  // small pause before next random play
  delay(100);
}

The file generation takes a bit of a long time and is over 10 Megs so I can't attach it here but here is what it sounds like from directory 96, file 5

005.mp3.zip (16.7 KB)

If someone has a ready to use setup with a DF Player mini, may be s/he can report back?

Tom,

Not at PC until next week, but my approach was basically as follows. Instead of randomAll() I used random() to first select a folder and then used code to shuffle its entire contents and index those in an array , which was itself then randomised.

See how far you can get. If others haven’t already got that working how you need, I’ll get back to you next week.

As I said above

➜ I assume you have a fixed list of your files or that they are organized in a way that lets you generate the right info to select the folder and then a specific file in that folder and if you change the content of your SD card, you'll have to modify the code and upload again?

a simple approach could be

#include "SoftwareSerial.h"
#include "DFRobotDFPlayerMini.h"

const byte rxPin = 10;
const byte txPin = 11;
const byte busyPin = 9;

SoftwareSerial mySerial(rxPin, txPin);
DFRobotDFPlayerMini myDFPlayer;

struct Directory {
  byte numberOfFiles;
};

const Directory directories[] = {
  {3},  // folder 1 has 3 files
  {5},  // folder 2 has 5 files
  {2}   // folder 3 has 2 files
};

const byte numDirectories = sizeof directories / sizeof *directories;

byte shuffledDirs[numDirectories];

void shuffleArray(byte *array, byte n) {
  for (byte i = n - 1; i > 0; i--) {
    byte j = random(i + 1);
    byte tmp = array[i];
    array[i] = array[j];
    array[j] = tmp;
  }
}

void playDirectory(byte dirIndex) {
  byte numFiles = directories[dirIndex].numberOfFiles;
  byte fileOrder[numFiles];
  for (byte i = 0; i < numFiles; i++) fileOrder[i] = i + 1;
  shuffleArray(fileOrder, numFiles);

  for (byte i = 0; i < numFiles; i++) {
    myDFPlayer.playFolder(dirIndex + 1, fileOrder[i]);
    delay(50);
    while (digitalRead(busyPin) == LOW) delay(10);
  }
}

void setup() {
  pinMode(busyPin, INPUT);
  mySerial.begin(9600);
  Serial.begin(115200);

  if (!myDFPlayer.begin(mySerial)) {
    Serial.println("Unable to begin:");
    while (true) yield();
  }

  myDFPlayer.volume(20);

  for (byte i = 0; i < numDirectories; i++) shuffledDirs[i] = i;
  shuffleArray(shuffledDirs, numDirectories);
}

void loop() {
  for (byte i = 0; i < numDirectories; i++) {
    playDirectory(shuffledDirs[i]);
  }
  shuffleArray(shuffledDirs, numDirectories);
}

where we shuffle the directories (fisher Yates algorithm) and then for each directory selected we shuffle the entries.

This way we play each song only once until all songs are played, all "randomly" (a randomSeeed() call in setup() might be useful)

Thanks much for your help Jackson, Terry, and Jim. I feel more confident getting this randomize stuff figured out.

If I understand, I can divide up my MP3 files into groups of 255 into individual folders. Then I can use Jackson's sample code to randomize the folders to select one, then randomize the files in that folder to select a file.

Another technique could be to randomize the folders to select one, then use the RandomAll command to randomize the files in the selected folder.

I appreciate the help!

May I ask one more question, I realize are clones of DP Player, some are inferior to others. Here are the ones that I ordered:

https://www.aliexpress.us/item/3256802489389597.html

Does this seem to be one of the "decent" ones that have decent firmware on it?

Thanks,
Tom

That does not guarantee you don't get repeated tracks within one folder. (difference between shuffled and randomized playback).

for the quality, it's hard to say by just looking at the picture on aliexpress. They might have stollen it from elsewhere...

Up to 255

@tomhammond

Back at PC now but looks like JML has it all squared away. Let me know if there's any further help you need from me.

@J-M-L
I too confirm that randomAll() does operate across all tracks. Regardless of their number or structure.

I already had useful resources at hand so first added my 'Big Band' folder of 253 individual MP3 tracks to a new mSD card. Followed by an arbitrary five copies of my 1-60 spoken numbers folder 'msd4 60Numbers-1to60\ ‘ (made for earlier projects). Then played a simple sketch like yours until I heard one of those. The first was "two" (which could be the 255th chronologically indexed track), but another couple of minutes got me a "twenty three" QED. :slightly_smiling_face:

what were the file names for the 60 spoken numbers ?

First ten:

0001-one550.mp3
0002-two.mp3
0003-three300.mp3
0004-four.mp3
0005-five.mp3
0006-six.mp3
0007-500.mp3
0008-eight.mp3
0009-.mp3
0010-.mp3

OK so the file saying "23" was names like 0023-.mp3

it's likely indeed that it has been copied over to the SD way later than 0002-two.mp3 as modern file systems tend to copy files in alphabetical order and the DF player does not care about the name but really just in which order the file was copied over.

So indeed very likely QED

The files were in chronological order. I added them to ensure that. And if File Explorer wasn’t limited to a precision of one second it would show that, when sorted by Date Created. So hearing 23 played proved beyond any doubt that randomAll() is not limited to 255 files.

Indeed - that’s the conclusion