Home Forums Sparkfun MP3 Shield Library Support Forum Setting volume when track is finishing

Viewing 9 posts - 1 through 9 (of 9 total)
  • Author
    Posts
  • #1890
    Anonymous
    Inactive

    Hello,

    first of all thank you Michael and Bill for sharing this lib and congratulations for the excelent work!

    I’m using your lib with a Teensy++ 2.0 board and a generic MP3 player board with VS1053B (not the sparkfun one). The lib works very well and I could easily change the pin configuration for using with Teensy board. Your example works fine.

    Now I’m stuck with the following problem:

    Description: I use a rotary encoder switch to increase or reduce volume while playing a track. The encoder is interrupt driven. The code to change volume is the same from “parse_menu” function of example code. The encoder interrupt set a flag that is checked in main loop and the volume is increased or decreased correctly. The problem happens when the track finishes. If I keep rapidly turning the encoder (changing volume) when the track finishes the program freezes! I supposed is something related with firing an interrupt whem the VS1053 buffer is almost empty. It’s just a guess, I don’t know really.

    I don’t know what can I do to further investigate this problem.

    My application is a MP3 player for playback birding sounds, so some of the tracks have very short durations (less than 10 seconds) and this problem is annoying in such cases (where probably the track will end while adjusting volume).  I also implemented a repeat function (checking the status of the player in main loop), when track finishes it starts again. For now I disabled repeat function because of this problem.

    The code to change volume is

    if (MP3player.getState()==playback){
    union twobyte mp3_vol; // create key_command existing variable that can be both word and double byte of left and right.
    mp3_vol.word = MP3player.getVolume(); // returns a double uint8_t of Left and Right packed into int16_t
    if (EncoderDir == 0) { // note dB is negative
    // assume equal balance and use byte[1] for math
    if (mp3_vol.byte[1] >= 254) { // range check
    mp3_vol.byte[1] = 254;
    } else {
    mp3_vol.byte[1] += 2; // keep it simpler with whole dB’s
    }
    } else {
    if (mp3_vol.byte[1] <= 2) { // range check
    mp3_vol.byte[1] = 2;
    } else {
    mp3_vol.byte[1] -= 2;
    }
    }
    // push byte[1] into both left and right assuming equal balance.
    MP3player.setVolume(mp3_vol.byte[1], mp3_vol.byte[1]); // commit new volume

    Best regards,

     

    Miguel Moreto

    Electrical Engineering professor at Technological Federal University of Parana

    Pato Branco, Parana, Brazil.

    #1892
    Anonymous
    Inactive

    I forgot to tell you I’m using library version 1.01.01 and arduino 1.0.2.

    The check “if (MP3player.getState()==playback)” is done because when not playing I use the rotary encoder to do something else, change tracks.

    Regards,

    Miguel

    #1898

    Are you running the MP3 library as INT or polled?

    I interpret your above to say spinning the dial works when playing back. But when idle (not playing back) and you spin the dial it locks up. Not sure how that relates to the MP3 and its interrupt.

    Is it that you are spinning it (this works as expected) and while it is spinning the track finishes and then it locks up.

    Need to add prints to debug where it was last as it locked up.

    It sounds like it should be the same as sending from the Serial Monitor “1+++++++++++++++++++”…

    Which all get queued up so it plays 1 and then processes the +’s.

    The getState and its under the hood resources  was added to help prevent refills from occurring when not playing after each of the commands, such as setVolume. It may be somehow the refill is still being enabled when there is no file open. Or the interrupt of the dial is interrupting the refill or sending of the command to the MP3.

    Not sure this is a very specific issue. Not sure if it is the MP3 library at fault.

    #1899
    Anonymous
    Inactive

    Hello Michael,

    thanks for your quickly reply!

    I’m running the lib with interrupt, not polled.

    Spinning the dial works when playing and also when not playing.

    Is it that you are spinning it (this works as expected) and while it is spinning the track finishes and then it locks up.

    Exactly! It only locks up the processor (not only VS1053, but entire firmware) if I spin the dial when the track finishes.

    I will insert several prints and do a better debug.

    I already tried sending “1+++++++++++++++++++” like you said and could not reproduce the behavior (worked as expected), so I believe is something related with external interrupt.

     Not sure this is a very specific issue. Not sure if it is the MP3 library at fault.

    I’m not sure either, but maybe you have handled this before, that’s why a post here.

    Best regards,

    Miguel

    #1900
    Anonymous
    Inactive

    Ok, I made some tests with several Serial.println statements and now I can tell you more about what is happening.

    I will explain with a timed sequence of events that may happen if you quikly spin the encoder generating interrupts that enable volume increase or decrease:

    1) Spin the encoder right before the track ends

    2) one interrupt is generated and the main loop enters in the portion of code to change volume.

    3) The code to change volume uses methods getVolume and setVolume.

    4) These methods calls Mp3ReadRegister and Mp3WriteRegister. In these functions the problem happens in this portion of code:

    if(playing_state == playback) {

    //see if it is already ready for more
    refill();

    //attach refill interrupt off DREQ line, pin 2
    enableRefill();
    }

    5) The above call to refill() happens to be the last one, the refill function will call disableRefill() and flushdata.

    6) After calling refill() the program jumps back and the function enableRefill() is executed. It should not be in this case.

    7) DREQ interrupt is re-enabled and refill() function (callback) keeps executing endless, this is why my program stucks. I don’t know why the interrupt keeps firing if the codec does not need more data (noise in DREQ pin maybe?)

     

    Anyway I conclude that if a MP3WriteRegister or MP3ReadRegister occurs in such a way that the call to refill() function is the last one, we have a not predicted situation, with strange behavior.

    In order to check if this is the cause of the problem, I modified the library code in those 2 functions, including a new playing_state check:

    if(playing_state == playback) {

    //see if it is already ready for more
    refill();

    //attach refill interrupt off DREQ line, pin 2
    if(playing_state == playback) {
    enableRefill();
    }
    }

    After that I spinned the encoder as fast as I could and it worked as expected, without freezing.

    I don’t know if this solution is the best one, but it seems to work. What do you think?

    Feel free to ask if my text was not clear or if you have any other question.

    Best regards!

    Miguel

    #1901

    Very well thought out and investigated.

    Not sure why your interrupts are firing like you stated. but none the less it draws out an issue. Where the added playing_state is reasonable.

    I would suggest try moving the check into the void SFEMP3Shield::enableRefill() itself.

    void SFEMP3Shield::enableRefill() {
     if(playing_state == playback) {
     #if defined(USE_MP3_REFILL_MEANS) && USE_MP3_REFILL_MEANS == USE_MP3_Timer1
     Timer1.attachInterrupt( refill );
     #elif defined(USE_MP3_REFILL_MEANS) && USE_MP3_REFILL_MEANS == USE_MP3_SimpleTimer
     timer.enable(timerId_mp3);
     #elif !defined(USE_MP3_REFILL_MEANS) || USE_MP3_REFILL_MEANS == USE_MP3_INTx
     attachInterrupt(MP3_DREQINT, refill, RISING);
     #endif
     }
    }

    This may be more comprehensive, as there are other locations of enableRefill(). Which are typically paired with a preceding refill(). Subsequently  ::skip()’s and “”skipTo()’s ; enableRefill() and playing_state=playback, need to be swapped.

    The state-fullness of the playing brings out a whole lot of problems, such as this.

    #1902
    Anonymous
    Inactive

    Hello Michael,

    I modified the code as you suggested and it is working fine.

    Should I open an issue in github about this?

    Regards,

    Miguel

    #1903

    No need. I have pushed the changes into the work-in-progress release of 1.0.1 on my github. Let me know if there are issues. I will need to QA it a little more. But expect it will be fine.

    I plan on merging the latest SdFatLib in to and then releasing it on the main github.

    Thanks for the feed back and assistance.

    #2021

    FYI –

    During my QA of the changes related to this I found the resumeDataStream() function was broken. The current release of 1.02.00 has this fixed. By simply swapping the order of enableRefill(); and playing_state = playback; as with the others previously mentioned.

    Have fun.

Viewing 9 posts - 1 through 9 (of 9 total)
  • You must be logged in to reply to this topic.