MP3-Player Lib, with example

Hi,

that's only example code, it's not intended to be "complete" or "perfect" - take it as a starting point for your own projects.

Are your sure that you need an array ? Perhaps you can live without reading the whole directory. Or you don't need it at all.
Or, maybe use subirectories and only read ther content. Or alphabetically i.e. read only "'A*", 'B*", or...... maybe you have a better idea :)
 
just wondering if this will work with the ili9341_t3 library?

Yes, no Problem. The lib itself does not need any Hardware, but of course you need a source for the mp3 file, like SD. I will update the lib to use the SerialFlash.
 
Yes, no Problem. The lib itself does not need any Hardware, but of course you need a source for the mp3 file, like SD. I will update the lib to use the SerialFlash.

Cool! That will be helpful for those of with the prop shield that want to play longer pre-recorded sounds.
 
In theory it can already play it from flash ( long time ago i wrote that for my old serflash lib).
Play (unsigned int address_in_serflash, length unsigned int) should do it. (totally untested with SerFlash)

But it's better to wait a few days :)
 
I just tried that, just for fun. It works without any changes to my codec-lib "out of the box"...
Is it still worth the effort to add the SerialFlash support ?

Example code to play from serial flash:
Upload the file with TeensyTransfer"
Adjust the filename.

Code:
// Simple MP3 file player example
//
// Requires the prop-shield
// This example code is in the public domain.

#include <Audio.h>
#include <SerialFlash.h>
#include <play_sd_mp3.h>
//#include <play_sd_aac.h>


// GUItool: begin automatically generated code
//AudioPlaySdWav           playSdWav1;     //xy=154,422
AudioPlaySdMp3           playMp31; //xy=154,422
AudioMixer4              mixer1;         //xy=327,432
AudioOutputAnalog        dac1;           //xy=502,412
AudioConnection          patchCord1(playMp31, 0, mixer1, 0);
AudioConnection          patchCord2(playMp31, 1, mixer1, 1);
AudioConnection          patchCord3(mixer1, dac1);
// GUItool: end automatically generated code


#define PROP_AMP_ENABLE    5
#define FLASH_CHIP_SELECT  6

void setup() {
  AudioMemory(8); //4
  delay(2000);

  // Start SerialFlash
  if (!SerialFlash.begin(FLASH_CHIP_SELECT)) {
    while (1)
      {
        Serial.println ("Cannot access SPI Flash chip");
        delay (1000);
      }
  }

  //Set Volume
  mixer1.gain(0, 0.5);
  mixer1.gain(1, 0.5);

  //Start Amplifier
  pinMode(PROP_AMP_ENABLE , OUTPUT);
  digitalWrite(PROP_AMP_ENABLE , 1); 
}

void playFile(const char *filename)
{

  SerialFlashFile ff = SerialFlash.open(filename);
  Serial.print("Playing file: ");
  Serial.println(filename);  

  uint32_t sz = ff.size();
  uint32_t pos = ff.getFlashAddress();
  
  // Start playing the file.  This sketch continues to
  // run while the file plays.
  playMp31.play(pos,sz);

  // Simply wait for the file to finish playing.
  while (playMp31.isPlaying()) {yield();}
}


void loop() {
  playFile("rain.mp3");
  delay(1000);
}

Michael: You might want to try an *.aac file. Better quality at same bitrate. Or same quality with less bitrate... you could try 80KB/s or less - depends on your files. .. and use mono to save space!
To use aac, exchange all "mp3" in the code with "aac"...
 
Last edited:
Evidently I missed a few updates (I don't seem to have play_sd_mp3.h), so I will need to root around for these, or wait until 1.28 beta 2 is released.

Thanks!
 
Michael,

it is not part of Teensyduino - you can find it on Github. Link is in the first post of this thread.
 
Michael,

it is not part of Teensyduino - you can find it on Github. Link is in the first post of this thread.

Got it. Thanks.

I'll look into converting the file to aac mono files.

Note, mp3/imdct.c contains calls to Serial without using

Code:
#include <Arduino.h>

in the header. I also found it annoying if I had the Teensy serial monitor running that it wouldn't print a newline every so often. I put in this quick and dirty patch, but perhaps just removing the Serial calls all together would be best:

Code:
-gnome-king-> cvs diff -r1.1 mp3/imdct.c
Index: mp3/imdct.c
===================================================================
RCS file: /home/michaelmeissner/global/cvs/meissner/arduino/libraries/Arduino-Teensy-Codec-lib/mp3/imdct.c,v
retrieving revision 1.1
retrieving revision 1.3
diff -p -c -r1.1 -r1.3
*** mp3/imdct.c 5 Apr 2016 11:52:38 -0000       1.1
--- mp3/imdct.c 5 Apr 2016 12:26:11 -0000       1.3
***************
*** 44,49 ****
--- 44,50 ----
  
  #include "coder.h"
  //#include "assembly.h"
+ #include "Arduino.h"          /* add from meissner */
  
  /**************************************************************************************
   * Function:    AntiAlias
***************
*** 187,197 ****
--- 188,209 ----
  {
        int i, d, mOut;
        int y0, y1, y2, y3, y4, y5, y6, y7, y8;
+       static int serial_cnt = 0;
        Serial.print("!");
+       if (++serial_cnt == 79)
+         {
+           Serial.println ("");
+           serial_cnt = 0;
+         }
        if (es == 0) {
                /* fast case - frequency invert only (no rescaling) - can fuse into overlap-add for speed, if desired */
                if (blockIdx & 0x01) {
                        Serial.print(".");
+                       if (++serial_cnt == 79)
+                         {
+                           Serial.println ("");
+                           serial_cnt = 0;
+                         }
                        y += NBANDS;
                        y0 = *y;        y += 2*NBANDS;
                        y1 = *y;        y += 2*NBANDS;
 
There shouldnt be any prints - perhaps i uploaded a testversion by accident...
I look at this, this evening.
 
Ha, I believe I've managed to do that at least once in every library I've written.

Yep, been there, done that.

BTW, I did convert it to AAC, and the AAC encoding is 2.1 megabytes vs. the 4.4 megabytes for mp3 (and 3.3 megabytes for ogg). Note, I haven't yet converted it to mono.
 
FIXED the prints are removed.

Yep, been there, done that.

BTW, I did convert it to AAC, and the AAC encoding is 2.1 megabytes vs. the 4.4 megabytes for mp3 (and 3.3 megabytes for ogg). Note, I haven't yet converted it to mono.

Note, for mono you don't need two mixers - you can remove one connection.
 
Last edited:
FIXED the prints are removed.



Note, for mono you don't need two mixers - you can remove one connection.
Yep, I figured that (and bumping the 0.5 to 1.0 in the remaining mixer). I just hadn't delved into the sound converter's options to produce a mono stream before having to leave for work.
 
Yep, I figured that (and bumping the 0.5 to 1.0 in the remaining mixer). I just hadn't delved into the sound converter's options to produce a mono stream before having to leave for work.

if you want it loud, yes :)

I don't know if helps, but for UBUNTU the conversion is :
Code:
sudo apt-get install libav-tools libavcodec-extra-54 libavformat-extra-54

avconv -i in.mp3 -c:v copy -ac 1 out.aac

But this converts to 64kbps (MONO) only. For small speakers this might be ok (i'd test it!) For better quality, the bitrate (kbps) should be higher..
I havn't found out, how to set the bitrate, or "quality" setting, yet...

ffmpeg should work, too.

You can use sox to convert to mono, too.
Code:
sox in.mp3 out.flac remix 1,2
then from flac (a lossless format) to aac, somehow...
 
Last edited:
Google helps...
Code:
 avconv -i x.mp3 -map_metadata -1 -c:v copy -ac 1 -b 96k o.aac

It removes the metadata which can really big (embedded jpegs for example) , and sets the bitrate to 96kbps (one channel = mono).

There are better-quality codecs for aac (from german fraunhofer institute) too, but i stopped "googling" at this point...
 
Last edited:
Prop Shield - Code example which iterates trough all *.acc and *.mp3 and plays them.

Code:
// AAC + MP3 file player example
//
// Requires the prop-shield
// This example code is in the public domain.

#include <string.h>

#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#include <play_sd_mp3.h>
#include <play_sd_aac.h>

// GUItool: begin automatically generated code
//AudioPlaySdWav           playSdWav1;     //xy=154,422
AudioPlaySdMp3           playMp3; //xy=154,422
AudioPlaySdAac           playAac; //xy=154,422
AudioMixer4              mixer1;         //xy=327,432
AudioOutputAnalog        dac1;           //xy=502,412
AudioConnection          patchCord1(playMp3, 0, mixer1, 0);
AudioConnection          patchCord2(playMp3, 1, mixer1, 1);
AudioConnection          patchCord3(playAac, 0, mixer1, 2);
AudioConnection          patchCord4(playAac, 1, mixer1, 3);
AudioConnection          patchCord5(mixer1, dac1);
// GUItool: end automatically generated code


#define PROP_AMP_ENABLE    5
#define FLASH_CHIP_SELECT  6

float volume = 0.5f;

void setup() {
  
  AudioMemory(10);
  delay(2000); 

  // Start SerialFlash
  if (!SerialFlash.begin(FLASH_CHIP_SELECT)) {
    while (1)
    {
      Serial.println ("Cannot access SPI Flash chip");
      delay (1000);
    }
  }

  //Start Amplifier
  pinMode(PROP_AMP_ENABLE , OUTPUT);
  digitalWrite(PROP_AMP_ENABLE , 1);

}

void playFile(const char *filename)
{
  int filetype;
  uint32_t sz, pos;

  SerialFlashFile ff = SerialFlash.open(filename);

  if (strcasestr(filename, ".aac") ) filetype = 1;
  else if (strcasestr(filename, ".mp3")) filetype = 2;
  else
    filetype = 0;

  if (filetype > 0) {

    Serial.print("Playing file: ");
    Serial.println(filename);

    sz = ff.size();
    pos = ff.getFlashAddress();

    switch (filetype) {
      case 1 :
        mixer1.gain(0, 0.0f);
        mixer1.gain(1, 0.0f);
        mixer1.gain(2, volume);
        mixer1.gain(3, volume);
        playAac.play(pos, sz);
        break;
      case 2 :
        mixer1.gain(0, volume);
        mixer1.gain(1, volume);
        mixer1.gain(2, 0.0f);
        mixer1.gain(3, 0.0f);
        playMp3.play(pos, sz);
        break;
    }
  }
}


void loop() {

  char filename[64];
  uint32_t filesize;

  if (!playAac.isPlaying() && !playMp3.isPlaying()) {
    if (SerialFlash.readdir(filename, sizeof(filename), filesize)) {
      playFile(filename);
    } else {
      SerialFlash.opendir();
    }
  }
}


Needs > 100KB of Teensy-Flash and takes some time to compile.. :)

Edit: Just for fun-test: It's able to play my 64kbps aac file with Teensy @ 24MHz !
So..you see, CPU Usage is less than 25% (compared to 96MHz) for this type of files in flash.. (RAM Usage (dynamic, only while playing > 34KB)

Edit: No, 16MHz ...
 
Last edited:
I fear this is impossible, though I can drop back and punt if necessary (and use two boards), but is it possible to use this library, along with sending data to APA102 leds at the same time?
The idea would be to essentially interrupt the data going to the amp momentarily to send SPI data to the buffered 5V output on the prop shield.

The code below will not run as-is. deleting the code within the play function that addresses the LEDS will cause the audio to play as expected.
WILDLY GARBAGE code would look like this - please note bolded // comments at ends of lines are intended to point out my likely pitfalls:


Code:
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#include <FastLED.h>

#define NUM_LEDS 12
CRGB leds[NUM_LEDS];
#include <play_sd_mp3.h>


AudioPlaySdMp3           playMp31; //xy=154,422
AudioMixer4              mixer1;         //xy=327,432
AudioOutputAnalog        dac1;           //xy=502,412
AudioConnection          patchCord1(playMp31, 0, mixer1, 0);
AudioConnection          patchCord2(playMp31, 1, mixer1, 1);
AudioConnection          patchCord3(mixer1, dac1);

#define PROP_AMP_ENABLE    5
#define FLASH_CHIP_SELECT  6
//#define FLASH_CHIP_SELECT 21  // Arduino 101 built-in SPI Flash

void setup() {
  Serial.begin(115200);
  FastLED.addLeds<APA102, BGR>(leds, NUM_LEDS);
    pinMode(7, OUTPUT);
  delay(1000);

  // Start SerialFlash
  if (!SerialFlash.begin(FLASH_CHIP_SELECT)) {
    while (1) {
      Serial.println ("Cannot access SPI Flash chip");
      delay (1000);
    }
  }

  //Set Volume
  mixer1.gain(0, 0.2);
  mixer1.gain(1, 0.2);

   AudioMemory(20);
  dac1.analogReference(EXTERNAL); 
  delay(50);            
  pinMode(5, OUTPUT);
  digitalWrite(5, HIGH); 
  delay(10);         
  pinMode(7,OUTPUT);
  digitalWrite(7,LOW); [B]//I'm turning off access to 5V buffer in an attempt to prevent SPI data from SerialFlash from bitspamming the LEDS[/B]
}

void playFile(const char *filename)
{
  SerialFlashFile ff = SerialFlash.open(filename);
  Serial.print("Playing file: ");
  Serial.println(filename);

  uint32_t sz = ff.size();
  uint32_t pos = ff.getFlashAddress();

  // Start playing the file.  This sketch continues to
  // run while the file plays.
  playMp31.play(pos,sz);

  // Simply wait for the file to finish playing.
  while (playMp31.isPlaying()) {

Serial.println("sending audio");
 

    for(int n = 0; n < NUM_LEDS; n++) {
    leds[n] = CRGB::Red;
    
    SPI.beginTransaction(SPISettings(12000000, MSBFIRST, SPI_MODE0)); [B]//I have tried both 12000000 and 24000000 in an ignorance fueled attempt to make it work.  If this is utterly meaningless in this context, forgive my ignorance[/B]
    digitalWrite(7, HIGH);  // enable access to LEDs [B](PJRC comment)[/B]
    FastLED.show();
    digitalWrite(7, LOW);
    SPI.endTransaction();   // allow other libs to use SPI again [B]PJRC comment[/B]
      leds[n] = CRGB::Black;
  }
[B] //side note: I can put all sorts of code within this WHILE and it will run as expected - from serial output to analogReads and other code that I only WANT to run while the audio is playing.  I strongly suspect that I am only having an issue because I'm attempting to double up on the SPI, doing the proper transactional mojo while the mp3 library is simply not doing the transactions (and nearly never would need to unless you're trying to make one board do everything like this), so I suspect it is either impossible to do what I want, or that it would require a cunning rewrite of the library.[/B]
  

    yield();
  }
}


void loop() {
   
 playFile("growle.mp3");
}

This is for a prop that needs to be done by next week. Other things it will do include occasionally accessing temperature and time data and occasionally pulling a pin high, then immediately low (delaymicroseconds) that triggers a one shot 555 circuit that makes a solenoid go a bit nuts (the effect I want).

Given that I'm only driving 12 leds, and that the refresh rate need never be higher than 4hz, perhaps it would be better to pull off from a few other pins and bitbang the colors? If I COULD make this work, however, it would be delightful.

I'd sincerely appreciate any assistance anyone might be able to give!
 
I've never used this type of LEDs or FASTLED.h, and don't know if it is doable.
The MP3 itself is fast, and i'm sure it does interfere with FASTLED.
But it needs to read from SD, which uses the SPI. The time it blocks the SPI is much shorter than with RAW or WAV, because it reads so much less data.
But, again, i have no idea how these LEDs work :)
 
I realize this is a old thread (2014), but was wondering if there was a newer effort for MP3 and other formats using the new 3.5/3.6 for more memory and speed on the CPU side. Any new libraries planned for using FFT processing of audio data and audio board? Very interested in following this development.
 
I realize this is a old thread (2014), but was wondering if there was a newer effort for MP3 and other formats using the new 3.5/3.6 for more memory and speed on the CPU side. Any new libraries planned for using FFT processing of audio data and audio board? Very interested in following this development.

Which formats are you missing ?
More memory is not needed, decoding works 100% good - and (automatically) faster with the newer teensys. At the moment, I have no plans re: new features - but if you have n amazing idea, I'll look at it.
FFT can be done with the std-audio-library, just use the design tool.

FLAC could take advantage of more memory - but I've never heard of a user who uses it.

Perhaps, some day, I'll add the "OPUS" Codec (with ENcoding, too, eventually) (and, mayby earlier if some users (more than one or two ;-) ) request it)

Then, it's open source - you can fork it, or, better, provide some pull-request @ github.


The newer version of the lib makes it easier to integrate it into the official audio-library some day. And, a big plus, it's independend of the source for the compressed data (uses a internal in-queue).
At the moment, it lacks support for AAC - i'll add it in the next weeks/month (only a few requests til now...) - (it's likely that i'll drop support for the *.m4a containers - they're CRAP and unusable with the new lib-architecture)

On the other hand, there seems to be no interest re: the new lib, and thus the priority on my "hobby" to-do list is pretty low.
 
Last edited:
Reading audio MP3 files

Which formats are you missing ?
More memory is not needed, decoding works 100% good - and (automatically) faster with the newer teensys. At the moment, I have no plans re: new features - but if you have n amazing idea, I'll look at it.
FFT can be done with the std-audio-library, just use the design tool.

FLAC could take advantage of more memory - but I've never heard of a user who uses it.

Perhaps, some day, I'll add the "OPUS" Codec (with ENcoding, too, eventually) (and, mayby earlier if some users (more than one or two ;-) ) request it)

Then, it's open source - you can fork it, or, better, provide some pull-request @ github.


The newer version of the lib makes it easier to integrate it into the official audio-library some day. And, a big plus, it's independend of the source for the compressed data (uses a internal in-queue).
At the moment, it lacks support for AAC - i'll add it in the next weeks/month (only a few requests til now...) - (it's likely that i'll drop support for the *.m4a containers - they're CRAP and unusable with the new lib-architecture)

On the other hand, there seems to be no interest re: the new lib, and thus the priority on my "hobby" to-do list is pretty low.

(currently, i'm working on this :
View attachment 9422
:)

Hi Frank,

What I am working on is the ability to read PM3 audio files (instead of WAV) from the SD card and doing FFT processing for frequecy analysis. As a newbie to C/sketch coding, I am using Paul's Audio library (PArt _3_02_Fourier_Transform) to get started which works fine for "predetermined" .wav file names. So my questions are: 1) can this code be used with MP3 files and 2) is there some way to read a list of audio MP3 file names for play selection. From the contents of this thread, it does sound like MP3 files can be processed, but what is the best library code to use (different than audio.h?). For question 2, does it require some rudimentary form of OS on the Teensy side to list MP3 files for selection? Not sure what I am up against to do this. If you have any suggestions, I would greatly appreciate the help.
 
Are there any caveats for using stop()? I have a "next" button in my mp3 player. Upon a button press I call stop() then play() on the next file. After a several presses the player locks up.

The code used to look like:
AudioNoInterrupts(); /* needed to make multiple changes */
mixer1.gain(0, 0); /* turn off MP3 output */
mixer1.gain(1, 0); /* turn off MP3 output */
playMP3_1.stop();
AudioInterrupts();
...
playMP3_1.play(fn);
AudioNoInterrupts();
mixer1.gain(0, 1);
mixer1.gain(1, 1);
AudioInterrupts();

After several "next" presses I get a constant squeal and buttons stop responding.
I've modified the code around the stop() call so it now looks like:

AudioNoInterrupts(); /* needed to make multiple changes */
mixer1.gain(0, 0); /* turn off MP3 output */
mixer1.gain(1, 0); /* turn off MP3 output */
playMP3_1.stop();
AudioInterrupts();
/* drain an audio block (128 samples at 44.1 KHz) */
cnt = 30;
while(--cnt >= 0) {
delayMicroseconds(100);
}
/* wait up to 0.5 seconds for MP3 to stop playing */
cnt = 5000;
while((--cnt >= 0) && playMP3_1.isPlaying()) {
delayMicroseconds(100);
}
...
playMP3_1.play(fn);
AudioNoInterrupts();
mixer1.gain(0, 1);
mixer1.gain(1, 1);
AudioInterrupts();

The good news is with this modification I no longer get the squeal. The bad news is that it still becomes unresponsive after several "next" button pushes.
 
Back
Top