Go Down

Topic: DFPlayer detect when song is done playing (Read 4054 times) previous topic - next topic

pwhitrow

The chip name on the fakes are as I posted above mate, it was on the chips. Faint, but took a pic and enhanced it with photoshop filters until I could see the number. Just call me Columbo ;)

I can use the fake ones for other projects that don't need a loop feature so at least they won't go to waste, but it's bloody annoying!

xl97

Totally agree.

Mine had the number etched off.. (so I couldnt not grab any identifying marks/numbers)

Its a shame...  I only find the clones/fakes for $1.75.. and not the real ones.  :(

uxomm

@uxomm -
Did you get any updates about the loud speaker 'pop' upon power on/off has been addressed (using the stock DFRobot library at least).
No updates yet.
I should get updates from several threads regarding dfplayer. But everything is quiet (except for this thread). :)
Always decouple electronic circuitry.

xl97

I had/have updated a few threads on it..

Just wanted to make sure you knew this 'speaker pop' issue stems from the DFRobot default library..

xl97

At this point.. if you get a LEGIT DFPlayer board:

* Blue led
* YX5200 chip set
* silkscreen around the components on PCB

the only 'item' left to address is, how to accurately and consistently (via code, but using the BUSY PIN).. detect when a song has finished playing.

* internally it must have a pointer (or something) to know when the song has finished.. so it can start it over again during a 'loop' command.

* but I dont think it works or works correctly when just using a one time play back command like:  .play(#)..

* if I was better/more advanced at high level C++ coding.. and had more time.. I might try and take a look at the library again...



jksemple

I've just started playing around with these DFPlayer modules using the DFRobotDFPlayermini library. I was trying to modify the getStarted example to play a series of MP3s end to end rather than 3 second bursts of each one. I was also frustrated that there didn't seem to be a reliable way to detect when an item has finished playing (without using the BUSY pin).

However, I found where you can switch on DEBUG mode within the library (remove the comment in front of #define _DEBUG in the .h file).  You can then see the command sequences being sent to the DFPlayer and what is being received back from it.  If the command is sent with a 'Reply required' bit set (as the library does) in the command the module acknowledges the receipt of the command immediately.  A little later it may send further messages reporting on the progress of the command.  For commands that start a song playing this will include the message that the song has finished.  In the example the arrival of these replies is detected and processed by
Code: [Select]
  if (myDFPlayer.available()) {
    printDetail(myDFPlayer.readType(), myDFPlayer.read());
  }
. However, once processed the information is no longer available. You need to set a busy flag when you start the sound playing and reset it e.g. within case DFPlayerPlayFinished:

Having added a flag I was still finding my sounds were not playing to the end. Every second sound was being cut short by the next sound being started.  This turned out to be because the Finished message is apparently being sent twice by the module.  The first message was clearing my busy flag so I was queuing up another sound but the second copy of the Finished message was then clearing the busy flag of the subsequent sound.  You can resolve this by changing the if (myDFPlayer) { } to while (myDFPlayer) { }.  All copies of the finished messages then get consumed before your code continues.

I can now play a series of sounds and reliably detect when each one finishes before queuing the next.

NB I also had noise problems with the on-board amplifier and have concluded the solution is not to use it and amplify the DAC signals externally.

xl97

I'll have to check and see if that fixes the issues I had in my particular sketch jumping from a .play() command to a .loop() command..

I would 'randomly' have the initial .play() clip get stuck in a loop..  (maybe what you suggested/pointed out is what was getting the internal 'pointer' all wonky)..

Also.. the on-board amp is fine....nice even.  You can fix the pop by commenting out an extra reset() call/line in the library files.


jksemple

I wasn't getting a pop. I found that if I used the on-board amp the power drain was causing the player to brown out and reset randomly. I couldn't fix it with a smoothing capacitor and anyway I'll be using a separate amp as I want stereo output.  I tried commenting out that reset() and it didn't make any difference to my problem.

xl97

Well if you werent getting the pop like the rest of us.. them commenting out the reset() call in one lib files wont do anything for you.

How are you powering the DFPlayer?

jksemple

I'm powering the Arduino from a 5V bench supply and then stepping down to 3.3v for the DFPlayer with a AMS111733 regulator because the datasheet said the preferred working voltage was 4.2v rather than 5v. To be fair I'm not sure whether I was getting the pop or not. Using the amplifier so destabilised the module that I gave up on it very quickly. I was also getting a loud 10Hz (roughly) ticking sound through the speaker while it was initialising the SD card which went when I took output from the DACs.

xl97

hmm...

I personally have only been running them @ 5v.

Do you have some 1k resistors on the speaker lines?

I was getting 'noise' through the speaker = 1k resistors on each line stopped this (well enough)

I was getting a huge 'pop' from the speaker upon power up and down (not during playback or anything)..  = this was traced back to a line in the library files (I posted on it a few times around here I thought?...but if your not getting the pop, then its no big deal)

I have not enabled the DAC to external headphones or amp... so I cant comment there is any differences.

Maybe your switching regulator is adding in more noise?  (I hear/read that switch regulators introduce a lot of noise)



jksemple

I don't think you mean 1k resistors in the speaker lines. That would stop the amplifier driving the speaker. I've seen people propose 1k resistors in the RX and TX lines but I'm using MOSFETs to convert 5v RX TX signals to 3.3v which is a better solution. I don't think the 3.3v regulator is the problem, more likely it is that the amp wants a bit more than 3.3v. I might try jacking up the GND of the regulator with a diode so it produces more like 4v just as an experiment but it's working fine for me at 3.3v if I ignore the amp and use the DAC output instead.

xl97

LMAO!..

Yes you are correct (my mistake).. on the RX/TX lines!!!  (not speaker lines!)  haha


Also.. so I'm clear you suggested minor updated/change..

Your saying if you use this:

You have no issues with reliably detecting an audio clip upon completion?

Code: [Select]
while(myDFPlayer.available()) {
    //do whatever checking you want here
  }




I have been using it like so in the past (with random success).. although pretty stable.. when trying to transition from a .play(#) command...  (checking for it to be finished).. and then going to a .loop(#) command...

it would work flawlessly sometimes.. and other times.. it would get stuck on the .play(#) file... trying to loop that!??

Code: [Select]
if(myDFPlayer.readType()==DFPlayerPlayFinished && myDFPlayer.readCurrentFileNumber()==2) {
    Serial.println(F("audio finished..."));
    myDFPlayer.loop(3);
}



Check the readType doesnt inherently do anything by itself.... right?

So you need to actually check for a specific 'state' of the readType response..

If the DFPlayer throws out '2' 'finished' responses.... the first one will 'trigger' a false positive...... no?

And if it doesnt 'always' kickback 2 responses... then how to you always consistently know when any given clip is complete?

There are also some other ways I have seen people try to check for 'completeness/finished state'


Code: [Select]
//if(myDFPlayer.readType()==DFPlayerPlayFinished){
             
//if(myDFPlayer.readState() != 513 && myDFPlayer.readType()==DFPlayerPlayFinished){
             
//if(myDFPlayer.readState() != 513){




I had posted a sketch on the DFRobot fourms (garbage)...  to see if anyone could duplicate the same error I was getting (as described above)

https://www.dfrobot.com/forum/viewtopic.php?f=8&t=4086

I'd circle back to it if your updated code/approach fixes that.


The funny things is..

internally the DFPlayer MUST reliably detecting when a song is complete (whether its sending callbacks once or twice).. because you call a .loop(#) command.. internally the boards know when its done..... and (for the most part) seamlessly plays it again.



jksemple

What I'm saying is that the DFPlayer sometimes returns multiple messages.  The example code processes a single message within the if ().  If you request a track and then wait for a Finished message, when it arrives the example code just processes the first Finished message.  If you assume you can go ahead and request another track, the second Finished message is still lurking and the next time you call myDFPlayer.available() it will appear that the DFPlayer is telling you that the second track has finished while in fact it is just a repeat of the first Finished.

By replacing the if ( ) with a while( ) the code will process all the messages that are queued up before returning control back to your code.

I agree it's very odd behaviour and difficult to accept is some sort of bug in the silicon.  I don't rule out that the library has a bug and is returning the same message twice under some circumstances.  When I get time I'll put my logic analyser on the output of the DFPlayer to confirm if the message is really being repeated.

However, using the library as it is you can rely on the first Finished message being a reliable indication that the track has finished.  The second is the false one.  One way of fixing the library (if the DFPlayer is indeed returning duplicate messages) could be to save each message that has been processed and discard any message that is exactly the same.

I haven't tried using the loop command so I can't comment on strange behaviour there but I suspect it's
down to the same root cause - repeated replies.

jksemple

I should have added that you still need to set a global flag (e.g. below "Play Finished" in printDetail) when the DFPlayer tells you that the track has finished so that you know when you can start the next track.

The other point I meant to add is that the Finished message contains a reference to the track that has finished. It would be nice to use this to cross-check which track has now finished however it appears to be returning the index number of the track on the SD card which is not necessarily the number that you requested to play.  If you requested to play a track in the MP3 folder (playMp3Folder() command = 0x12) or play a track in a numbered folder (playFolder() command = 0x0F) the file number returned is different. So I reckon the best solution is to ignore the returned file number and just suppress duplicate replies.

Go Up