Sparkfun MP3 Shield Arduino Library

Posted in Arduino Libraries by Bill
28 Jan 2012

The Sparkfun MP3 Player Shield for Arduino is a inexpensive and easy way to add MP3 playback capability to your Arduino project. But it was lacking an easy to use Arduino Library to go along, so I fixed that. Introducing the SFEMP3Shield library just for this shield. Now playing an MP3 files is as easy as MP3player.playTrack(5); and all the work is done behind the scenes.

Most of this library comes from the existing example code, with the major new feature of being interrupt driven. So no need to worry about feeding the MP3 chip, whenever it’s ready for more the library will be ready to feed it. This allows the Arduino to perform other tasks while music is playing. The most basic use of the library is as follows:

 

#include <SPI.h>
#include <SdFat.h>
#include <SdFatUtil.h> 
#include <SFEMP3Shield.h>

SdFat sd;
SFEMP3Shield MP3player;

void setup() {

  Serial.begin(9600);

  //start the shield
  sd.begin(SD_SEL, SPI_HALF_SPEED);
  MP3player.begin();

  //start playing track 1
  MP3player.playTrack(1);
}

//do something else now
void loop() {

  Serial.println("I'm bored!");
  delay(2000);

}

That’s all it takes to get your Arduino to play an MP3 file using the shield.  How easy is that?

The library does have more functions and even error reporting. All of which can be found in the ReadMe file or in the Example Sketch included with the Library.

Source Code available on GitHub project pages: Sparkfun MP3 Player Shield Arduino Library

Or Direct Download here.

Using the SPI bus for something else as well?

I added some functions to make sure there will be no data collisions on the SPI bus caused by the MP3 decoder asking for more data at the wrong time. You need to wrap any SPI code you add to your project with these two functions. Here’s an example from my project that also has a shift register on the SPI bus:

  //disable interrupts to avoid collisions on the SPI bus between this code //and the MP3player library
  MP3player.pauseDataStream();

  //shift data
  tempIO = SPI.transfer(HIBYTE(output));
  tempIO<<8; 
  tempIO = SPI.transfer(LOBYTE(output));

  //latch output on shift registers
  digitalWrite(OUTLATCH,LOW);
  digitalWrite(OUTLATCH,HIGH);
  digitalWrite(OUTLATCH,LOW);

  //enable interrupts
  MP3player.resumeDataStream();

But you can’t stop the data stream to the MP3 Shield for too long before it runs out of data so be careful and try not to do too much stuff in between the functions.

 

Wanna be your own DJ?

New features! Requested in the comments below, there are now functions to skip around a playing track. You could fast forward, rewind, create loops, etc.

Here’s an example that will just open a file, jump to the 30 second mark (measured in milliseconds, 30 seconds = 30000 ms), and loop the song back every 750 ms:

MP3player.playTrack(1);

for(;;) {
MP3player.skipTo(30000);
delay(750);
}

If you want to know where you are in the current playback, do this:

time = MP3player.currentPosition();
Serial.println(time);

Both functions are not super accurate and depend on the bitrate of the file. The library should auto-detect the bitrate of the file but may fail on some MP3 files. If that happens, you have to set the bitrate manually like this:

MP3player.playTrack(1);
MP3player.setBitRate(192);

I can already see the cool DIY DJ equipment that could be made with this. Let me know if you have problems, and comment below if you ever make something cool with the library.

Troubleshooting

Pulled from the GitHub Project Page

The below is a list of basic questions to ask when attempting to determine the problem.

  • Did it initially PRINT the available RAM and Full Help Menu?
    • The MP3Shield_Library_Demo.ino example should initially provide a opening print indicating the amount of available SRAM and full menu help. If you don’t see this the problem is between your Target and IDE. And likely not this library
    • Is Serial Monitor set to the correct tty or com port and 115200 baud rate? Did you change the baud rate?
    • Reset the Arduino after Serial Monitor is open or send any key. It may have printed these prior to the Serial Monitor being started.
  • WHAT is the Error reported?
    • Is the Error Code is indicating a file problem.
    • Are the filenames 8.3 format? See below warning.
    • See also Error Codes
  • Did the SdCard LOAD?
    • Try reseating your SdCard.
  • Is it FAT(FAT16 or FAT32)?
    • If the Error Code is indicating problems with the INIT, VOLUME or Track not being successful. It is recommend to use SdFat Example Library’s QuickStart.ino as to see if it can access the card. Additionaly, SdInfo.ino may indicate if it can mount the card. Which may then need to formatted in FAT16 or FAT32. Where SdFormatter.ino can do this for you.
  • Are the needed files on the root?
    • Remember to put patch and audio track files on the SdCard after formatting.
    • Are the filenames 8.3 format? See below warning.
  • "Error code: 1 when \b trying to play track"
    • See the above Limitations. about Non-Blocking.
    • Remember to check your audio cables and volume.
  • Why do I only hear1 second of music, or less?
    • This symptom is typical of the interrupt not triggering the SFEMP3Shield::refill(). I bet repeatidly sendnig a track number will advance the play about one second at a time, then stop.
    • What board is it? Check Hardware Limitations. about Interrupts.
    • Are you trying the SFE provided test files ? Or some homemade mp3 files? The SFE test files are nice as they are Immediately LOUD.
    • Interrupt problems may cause mp3 files that have a quiet lead in (or ramp up of volume) to be falsely diagnosed as not playing at all. Where the first 1 second may not be loud enough to be heard.
  • Free RAM = 1090 Should be a base line of 1094
    • As a courtesy and good practice the provided example MP3Shield_Library_Demo.ino prints out the available remaining RAM, not statically allocated. And the actual available amount may depend on specific processor, IDE version, libraries and or other factors. A Uno built with IDE version 1.0.2 should have approximately 1094 bytes available from the example as is. And a Mega using a 2560 may show 6713, as it has more RAM.

Note

This library makes extensive use of SdFat Library as to retrieve the stream of audio data from the SdCard. Notably this is where most failures occur. Where some SdCard types and manufacturers are not supported by SdFat. Though SdFat Lib is at this time, supporting most known cards.

 

Warning

SdFatLib only supports 8.3 filenames. Long file names will not work. Use the 'd' menu command to display directory contents of the SdCard. "longfilename.mp3" will be converted to "longfi~1.mp3" . Where one can not predict the value of the 1. The DOS command of "dir \c /x" will list a cross reference, so that you know exactly, what is what.

Still Need Help?

Use the support forum to look for a solution or ask for help. Please don’t use the comments below to ask for help.

Creative Commons License
This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.

Share

Trackbacks / Pingbacks

  1. Ellentriek » Blog Archive » Tested Arduino Shields and the used libraries

Warning: count(): Parameter must be an array or an object that implements Countable in /homepages/46/d285670699/htdocs/bill/wp-includes/comment.php on line 879
  1. 590 Comments.

    • wayneNo Gravatar says:

      Hey Bill, just got my Uno/MP3 working with your lib, love it, good work.
      Can’t wait to dive in (pcb pun) and look at the other areas in user comments.
      Wayne

    • GeoffNo Gravatar says:

      I LOVE your library. Thank you so much for developing it. I’m building my first project on arduino with it. What I am planning is to use a pot to select various tracks on a SD card and I have got it working for the most part, however after a few track selects (changing tracks once every few seconds … my project will be for a child), everything seems to crash. I have the serial monitor going to see what the pot is reading and that stops as well as the music playback. They don’t always stop at the same time however. Here is my code. I’d appreciate any help I can get!

      Thanks

      #include
      #include
      #include
      #include

      SFEMP3Shield MP3player;

      int potPin = A5;

      void setup (){

      pinMode (potPin, INPUT);
      MP3player.begin();
      MP3player.SetVolume(1, 1);
      Serial.begin(9600);

      }

      boolean checkMovement (int oldPinValue){
      volatile int currentValue = analogRead(potPin);
      currentValue = constrain(currentValue, 0, 1000);
      volatile int val = map (currentValue, 0, 1000, 1, 5);
      if (oldPinValue == val){
      return(false);
      }
      else {
      MP3player.stopTrack();
      return(true);
      }
      }

      void loop (){
      volatile int tempPin = analogRead(potPin);
      volatile int pinValue = analogRead(potPin);
      pinValue = constrain (pinValue, 0, 1000);
      volatile int track = map (pinValue, 0, 1000, 1, 5);
      Serial.println(track);
      Serial.println(tempPin);
      delay(500);
      if (checkMovement (track) == false){
      }
      else {

      MP3player.playTrack(track);
      }

      }

    • BillNo Gravatar says:

      Hey guys,

      Usually I am able to provide same day responses to your comments, but this week I am swamped trying to complete construction of 3 science demos before a museum event this weekend. As soon as that is over, I’ll come back and address all your questions / problems.

      Sorry for that wait….
      Bill

    • BabakNo Gravatar says:

      Bill, don’t sweat it – free, as in beer! You’ve done the community a great service by providing these libraries in the first place.

    • Donald PappaNo Gravatar says:

      First, let me say thanks for your library. You have maDE it much easier for us beginners. I realize your quite busy with questions, but if you have the time consider my problem. I am trying to operate a servo using the below code which operates on the output of an audio file (its a talking skull). However, as a beginner I hve n clue how to combine the two or even if it is possible. Any suggestions or is this beyond a noobs abilities.

      1
      /* Skull
      2
      created 2011
      3
      by Boris Landoni
      4

      5
      This example code is in the public domain.
      6

      7
      http://www.open-electronics.org
      8

      9
      http://www.futurashop.it
      10

      11
      */
      12

      13
      #include
      14

      15
      Servo myservo; // create servo object to control a servo
      16

      17
      int potpin = 0; // analog pin used to connect the potentiometer
      18
      int val; // variable to read the value from the analog pin
      19

      20
      void setup()
      21
      {
      22
      myservo.attach(9); // attaches the servo on pin 9 to the servo object
      23
      }
      24

      25
      void loop()
      26
      {
      27
      val = (analogRead(potpin)*3); // reads the value of the potentiometer
      28
      val = map(val, 0, 1023, 50, 0); // scale it to use it with the servo
      29
      myservo.write(val); // sets the servo position according to the scaled value
      30
      delay(15); // waits for the servo to get there
      31
      }

      • BillNo Gravatar says:

        Donald, my best advice is to generate a script of when during the file playing back you want the servo to move. Then in your code you could compare the current time code of the track playing with your script and tell the servo to move. If your still stuck, send me an email to the address on the bottom of the page and I’ll help you further.

    • YazidNo Gravatar says:

      just a noob question.

      may i know where can i find all the schematic for this shield?

      i mean where do i want to connect all the jumper from arduino to the shield.

    • riza karaNo Gravatar says:

      Hello Bill . thank you for your code.

      how can i do load spectrumAnalyzer.plg with your code.

    • ThomasNo Gravatar says:

      Hello Bill,

      one short question (but maybe a long answer): is it possible to have the library play a single file in a seamless loop? Maybe a command “loop” that can be given instead of “play”?

      With this command the library should start reading bytes from after the ID3 tag as soon as it runs out of data at the end of the file. Currently I can’t get this to work properly.

      • BillNo Gravatar says:

        Easy answer: In your loop, use the isPlaying() function to see if a track is playing, and if not start playback again. I’ve done this and it is nearly seamless, but you have to check if it’s playing often.

        • ThomasNo Gravatar says:

          Ok, I’ll try it that way; I was hoping however there would be a way to include this in the interrupt driven routines because my Arduino has a lot of other things to do as well.

        • ThomasNo Gravatar says:

          I’ve solved this one myself in your library.

          I added a variable “looping” and a function to (un)set it. In the refill routine I added an alternative for when the buffer can’t be filled anymore: instead of closing the file and resetting, it jumps back to start_of_music.

          Won’t post it here publicly because of inappropriate use of statics and such, that can cause problems in any other application than mine, but I can send it to you if you like.

          note: it still discards the last few bytes of the file, I should do something to fix that. Maybe later.

    • xl97No Gravatar says:

      Awesome library!!

      Now if you could do the same for the WaveHC library from Adafruit! (true SPI) hehe

    • LeeNo Gravatar says:

      This library is such a great help, thank you!

      I am trying to use the library with both the MP3 shield and with sparkfun’s ADJD-S311 color sensing breakout board. I am having issues with getting the MP3 files to play correctly in unison with the breakout board code. I’ve narrowed it down to these lines affecting it:

      colorSensor.init();
      colorSensor.ledOn(); //turn LED on

      //Calibrate white
      //Need to hold white card in front (1-3mm) of it to calibrate from
      colorSensor.calibrate();

      Which are function out of the SDFat library.

      Is there a work around to getting the MP3 to play correctly?

      • ToddNo Gravatar says:

        Have you checked for pin compatability yet?
        Here are the color sensor example code pins.
        I see they use pin 9 which is already used by the MP3 player.

        // Pin definitions:
        int sdaPin = A4; // serial data, hardwired, can’t change
        int sclPin = A5; // serial clock, hardwired, can’t change
        int ledPin = 2; // LED light source pin, any unused pin will work

        // RGB LED pins, should all be PWM output pins:
        int redledPin = 9;
        int greenledPin = 10;
        int blueledPin = 11;

        • LeeNo Gravatar says:

          The code I found for the color sensor called the LED pins as follows:

          //if using an RGB LED (Needs PWM Pins)
          int redPin = 3;
          int greenPin = 5;
          int bluePin = 6;

          Found here:http://bildr.org/2012/01/adjd-s311_arduino/

          I don’t call out pins at all in the code I’m using. I’m using the bare basics of the code to try and get it to work. Here is the entirety of the code that causes it to play incorrectly:

          #include
          #include
          #include
          #include
          #include
          #include

          SFEMP3Shield MP3player;

          int sensorLed_pin = 2; //LED on the ADJDS-311
          ADJDS311 colorSensor(sensorLed_pin);

          void setup() {

          Serial.begin(9600);

          //start the shield
          MP3player.begin();

          MP3player.playTrack(001);

          colorSensor.init();
          colorSensor.ledOn(); //turn LED on

          //Calibrate white
          //Need to hold white card in front (1-3mm) of it to calibrate from
          colorSensor.calibrate();
          }

          //do something else now
          void loop() {

          Serial.println(“I’m bored!”);
          delay(2000);

          }

          This allows the track to play, but incorrectly. Any ideas if its something in my code, or maybe something I can change within the libraries?

          Thanks.

          • ToddNo Gravatar says:

            I would try two things. Still check pin compatibility. In an example code I have, the shield uses these pins.
            #define MP3_XCS 6
            #define MP3_XDCS 7
            #define MP3_DREQ 2
            #define MP3_RESET 8

            I would try changing your LED pins.

            The second thing I would try doing all the color stuff first and putting MP3player.playTrack(001); last in your setup.

            My last thought is it is potentially a memory issue. good luck.

          • BillNo Gravatar says:

            Pins 3 and 6 are connected to parts of the shield, so any library that uses these pins will cause problems.

    • MeEvilBreakfastNo Gravatar says:

      This is an excellent library… without it, this project I’m working on wouldn’t be possible (as I’m quite coding-deficient).

      I just one one question that I can’t figure out (and I’ve looked at lots of sources)

      What pins, exactly, does the shield make use of, including the sdfat library? I see by looking at your library that it uses pins 2, 6, 7, and 8, but it’s hard to tell what else the shield needs.

      I’m building a suit that incorporates the shield, and some sensors, and I really just need 2 or 3 digital pins.

      Thanks~

      • BillNo Gravatar says:

        Your safest bet is to use any of the 5 analog pins as digital pins (yes, you can use and analog pin like a digital pin) because they are not touched by the shield at all. There are a few digital pins not used by the software library I wrote, but they are still connected to parts of the shield that would cause problems if you started using for something else.

        • Thanks for the quick reply!

          That is highly unfortunate that the shield needs so many pins. I’m already using 5 analog pins (3 for an accelerometer, one for a piezo, and one for random number generator seed). It looks like digital pin 5 isn’t used for anything shield related (there doesn’t appear to be any traces leading anywhere). If so, I can just use that, and the sixth analog pin.

    • riza karaNo Gravatar says:

      how can i read data output DAC when playing mp3.
      i need voice amplitude data

      Thanks

    • WendyNo Gravatar says:

      Hey Bill,

      First of all a huge compliment on you making this library. It makes the whole mp3 Player shield a lot more legible!

      But, I am writing a comment because I’m having trouble. Your little sketch (serial monitor I’m bored) works like a charm.
      When I try the example sketch – all becomes mute. I hear the speakers do plop when I click on the serial monitor button (as if they play an empty file).

      This is what the Serial monitor gives me as output :
      Y4 ü 00 0 1
      (I pressed 1 and 2 to play the files)

      – I don’t even get this:
      if(result != 0) {
      Serial.print(“Error code: “);
      Serial.print(result);
      Serial.println(” when trying to start MP3 player”);
      }

      Serial.println(“Hello”);
      Serial.println(“Send a number 1-9 to play a track or s to stop playing”);)

      – I have tried Serial monitor with other sketches, it behaves as it should.

      – I run Linux Ubuntu, use and Arduino Duemilenova, run Arduino 1.0 software, all the libraries are where they should be

      In the past I had a problem with a library because Linux is case sensitive and Windows is not
      (one leter!!)

      • WendyNo Gravatar says:

        A day later, some fresh eyes.. The solution here was very simple:
        – The baud rate of the first sketch (serial monitor I’m bored), in the sketch and in the serial monitor, was 9600.
        – The baud rate of the MP3Shield_Library_demo_sketch is
        115200 —> my Serial monitor window was at it’s standard Baud Rate, 9600.

        So shield and the serial monitor window were communicating at a different speed and they could not understand each other…

        (this makes me think of the voice of Twitchy the squirrel: http://en.wikipedia.org/wiki/Hoodwinked!)

        When I changed the baud rate of my Serial Monitor window, everything worked like a charm..

        🙂

    • […] MP3 Player Shield – Excellent library of Bill Porter, which simplifies the code and usage a lot. You should unzip the library and put the two subfolders […]

    • Mike SchwagerNo Gravatar says:

      It appears as if the SFEMP3 library when using Arduino 1.0 will try to include the files from the Arduino library first, notably libraries/SD/utility/SdInfo.h

      That file is missing some definitions, notably CMD12 and CMD18. So when I try to compile, I get the errors:

      …Documents/Arduino/libraries/SdFat/Sd2Card.cpp: In member function ‘uint8_t Sd2Card::cardCommand(uint8_t, uint32_t)’:
      …Documents/Arduino/libraries/SdFat/Sd2Card.cpp:178: error: ‘CMD12’ was not declared in this scope
      …Documents/Arduino/libraries/SdFat/Sd2Card.cpp: In member function ‘bool Sd2Card::readStart(uint32_t)’:
      …Documents/Arduino/libraries/SdFat/Sd2Card.cpp:461: error: ‘CMD18’ was not declared in this scope
      …Documents/Arduino/libraries/SdFat/Sd2Card.cpp: In member function ‘bool Sd2Card::readStop()’:
      …Documents/Arduino/libraries/SdFat/Sd2Card.cpp:480: error: ‘CMD12’ was not declared in this scope

      I can get it to compile correctly if I include those variable definitions, but I wonder if there’s another way to specify that I want to use the version of the SdFat library that you deliver, and not that comes from Arduino (without mucking about in the Arduino heirarchy)?

      Thanks, and thanks for an awesome library.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.