I have a DFPlayer mini board, to give some audio playback for some projects.
I am also using the DFRobot library.. (unless someone has a better/newer library they can recommend?)
Triggering an audio clip playback is fairly straight forward.. what I can not grasp/get working so far is how to automatically detect when an audio clip has finished playing, as to trigger an another clip to play programmatically.
I tried to do some searches, and while topics were returned, nothing yielded any info on detecting when a file was complete/had finished playing.
Here is a quick sketch I threw together to illustrate where I want to listen/check for the current audio file (2 or 002.wav) and trigger audio file 3 or 003.wav to LOOP..
Summary:
power on (boot sound plays)
listen for button press.
-- if pressed (button state change)
-- then play the power on sound (002.wav)
if button still pressed, wait for power on sound to finish and automatically loop audio clip 003.wav (and continue to loop) while button is being pressed..
when button is release (button state change)..
-- play power down sound (004.wav)
I either can NOT get the 003.wav to loop immediately after the 002.wav completes..
-OR-
The looping of 003.wav starts too fast and cuts off the 002.wav before it finishes.
//import needed libraries
#include "Arduino.h"
#include "SoftwareSerial.h"
#include "DFRobotDFPlayerMini.h"
//project vars
const int buttonPin = 19; //Pin (A5) the pin that the pushbutton is attached to
int buttonState = 0; // current state of the button
int lastButtonState = 1; // previous state of the button
boolean doCompletionCheck = false;
//FSM state control/vars
#define S_IDLE 1
#define S_POWERON 2
#define S_POWERDOWN 3
//FSM init vars
static int state = S_IDLE; // initial state is 1, the "idle" state.
//instantiate class instances
SoftwareSerial mySoftwareSerial(10, 11); // RX, TX (DFPlayer connections)
DFRobotDFPlayerMini myDFPlayer;
void setup() {
//debug (monitor)
Serial.begin(115200);
//talk to DFPlayer
mySoftwareSerial.begin(9600);
//declare pin & state
pinMode(buttonPin, INPUT); // initialize the button pin as a input
digitalWrite(buttonPin, HIGH); //use interal pull up resistors
//check on DFPlayer state (ready for use?)
Serial.println(F("Initializing DFPlayer ... (May take 3~5 seconds)"));
if (!myDFPlayer.begin(mySoftwareSerial)) { //Use softwareSerial to communicate with mp3.
Serial.println(F("Unable to begin:"));
Serial.println(F("1.Please recheck the connection!"));
Serial.println(F("2.Please insert the SD card!"));
while (true); //keep checking,...repeat
}
Serial.println(F("DFPlayer Mini online."));
//why?
myDFPlayer.setTimeOut(500); //Set serial communictaion time out 500ms
//----Set volume----
myDFPlayer.volume(9); //Set volume value (0~30).
Serial.print(F("CURRENT VOLUME: ")); //read current volume
Serial.println(myDFPlayer.readVolume()); //read current volume
//----Set different EQ----//
myDFPlayer.EQ(DFPLAYER_EQ_ROCK);
//----Set source device, we use SD as default----//
myDFPlayer.outputDevice(DFPLAYER_DEVICE_SD);
//play boot sound on power-up
myDFPlayer.play(1);
Serial.print(F("INTIT STATE: "));
Serial.println(state);
//delay to let boot sound play and start 'listening' for interaction
delay(3000);
}
void loop() {
//FSM state listener
switch (state) {
case S_IDLE:
//check main button state
buttonState = digitalRead(buttonPin);
//** button state HAS changed (compare) **//
if (buttonState != lastButtonState) {
//-- button state changed and is: pressed (ie: down) --//
if (buttonState == LOW) {
//any time button is pressed down, trigger power on sound
state = S_POWERON;
//-- button state changed and is: not pressed (ie: up) --//
}else {
//any time button is released, trigger power down sound
state = S_POWERDOWN;
}
//** button state has NOT changed **//
}else{
//check if -still- pressed
if(buttonState == LOW) {
//Serial.println(F("READ STATE: "));
//Serial.println(myDFPlayer.readState());
if(doCompletionCheck == true){
Serial.println(F("watching audio file for completion"));
//dedicated function attempt for checking track completion
trackComplete(2, 3, 'l');
/*
if(myDFPlayer.readType()==DFPlayerPlayFinished && myDFPlayer.readCurrentFileNumber()==2) {
Serial.println(F("audio finished..."));
myDFPlayer.loop(3);
doCompletionCheck = false;
}
*/
}
}else{
//Serial.println(F("BUTTON STILL -NOT- PRESSED........ "));
}
}
//update/save the current button state for next loop/cycle
lastButtonState = buttonState;
break;
case S_POWERON:
//play power up
myDFPlayer.play(2);
doCompletionCheck = true;
//return to button checking
state = S_IDLE;
break;
case S_POWERDOWN:
myDFPlayer.play(4);
//return to button checking
state = S_IDLE;
break;
}
}
//playMode options: p = play or l = loop
void trackComplete(int currTrack, int newTrack, uint8_t playMode) {
Serial.print(F("Current Track that is playing: "));
Serial.print(myDFPlayer.read());
Serial.print(F(" / "));
Serial.println(myDFPlayer.readCurrentFileNumber());
Serial.print(F("Checking for completetion of track: "));
Serial.println(currTrack);
Serial.println(F(""));
Serial.println(F(""));
//if(myDFPlayer.readType() == DFPlayerPlayFinished && myDFPlayer.read() == currTrack) {
if(myDFPlayer.readType() == DFPlayerPlayFinished && myDFPlayer.readCurrentFileNumber() == currTrack) {
//if(myDFPlayer.readType() == DFPlayerPlayFinished) {
doCompletionCheck = false;
Serial.print(F("TRACK MATCH: "));
Serial.print(myDFPlayer.readCurrentFileNumber());
//vs.
Serial.print(F(" / "));
Serial.println(myDFPlayer.read());
Serial.println(F("Setting completion listener off---->"));
switch (playMode) {
case 'p':
myDFPlayer.play(newTrack);
break;
case 'l':
delay(800);
myDFPlayer.loop(newTrack);
break;
}
}
//back to button checking
state = S_IDLE;
}
Seems like I can not get a consistent results from the DFPlayerFinished and currentTrack functions.. to reliably know when the 002.wav audio clip has finished so I can automatically trigger a looped file after that.
Are you supposed to send a stop() command or something before playing/looping another file?
Anyone see what I'm doing wrong? or have some experience with these DFPlayers? (and how to detect when a clip has finished?)
Bonus question #2:
Whenever I power on my Arduino or power it down.. I get a loud POP from the speaker connected to the DFPlayer.. how can I fix this? I have it set up as shown in the link.. with an additional 1k resistor on both RX & TX lines..
Thanks
-xl
