Audiolib-MP3

Status
Not open for further replies.

Frank B

Senior Member
@Paul,

I've modified the MP3 codec. It is now better and more easy to integrate into the the Audio-Library.

It does not use the second interrupt anymore, and is much more flexible. Furthermore, it does not rely on dynamically allocated memory anymore, but uses static mem. You'll see better, how much RAM is used when compiling.

Downside is, that it is a bit more complicated to use (but I can provide some helper-functions, for example to play a file from SD)

It works like a Queue-Object. There's a function "int pushData(uint8_t* data, size_t* length);" that takes some bytes of (encoded) data and buffers them in an internal memory. If enough free "output"-buffer are available - One mp3-frame - stereo - has 2304 Samples, the function decodes it.

The std update() transmits them later.

So, in summary, it will NOT provide any function to read files. BUT it is much more easy to use ANY TYPE of source for the compressed data.

This is how a loop to play could look like:

Code:
AudioPlayMP3Queue        playMP3_1;     //xy=111,349
AudioOutputPT8211        outputx;           //xy=452,356
AudioConnection          patchCord1(playMP3_1, 0, outputx, 0);
AudioConnection          patchCord2(playMP3_1, 1, outputx, 1);

[...]

void loop() {    
  if (len>0) {
    playMP3_1.pushData(sdbuf, &len);
  }
  else {
    len = readfile();
    if (len == 0) {
        while(1); // End Of File
    }
  }  
}

Paul, if you say, that this is ok, I invest some time for a good integration to the library and you can use it.

[h=1]https://github.com/FrankBoesing/Teensy-MP3[/h]
 
Last edited:
I wrote a super-simple webradio sketch (<300 Lines sourcecode + some lines for FIFO)
The only requirement is a T3.5, better T3.6 (more memory), an ESP12-E with newest AT-Commands Firmware ("AT+CIPUPDATE" for update), and the new Audiolib-MP3. No extra-hardware, except the ESP.
Works with std-audiolibrary, every output possible.

Since there is, obviously, no interest for the new lib - anyone interested in the webradio ???
(Would be a good example for the new lib, Paul.. :)
 
Last edited:
WebRadio Code on GitHub? Would be interesting if the ARDUINO coded ESP8266 could make it work - directly or emulating the AT command behavior. I just got 5 fresh ESP 12-F's - I just saw the silkscreen shows QIO for Tools setting.
 
Nope, not on github, yet.
Why fiddling with ESP... thats a black-box, not more. STD-AT-Commandset is sufficiant (but new version).
Fiddling with Arduino-ESP would have been 300% more work. Absolutely no reason to do it. And I don't like the myriads of warnings during compile..
Would be interesting if the ARDUINO coded ESP8266 could make it work
So, thats a "no", not interested. OK.
 
Last edited:
I wrote a super-simple webradio sketch (<300 Lines sourcecode + some lines for FIFO)
The only requirement is a T3.6, an ESP12-E with newest AT-Commands Firmware, and the new Audiolib-MP3. No extra-hardware, except the ESP.
Works with std-audiolibrary, every output possible.

Since there is, obviously, no interest for the new lib - anyone interested in the webradio ???
(Would be a good example for the new lib, Paul.. :)

I see some great applications for this, i'm building a home gym in my garage and i have a dream of responsive WS2812b RGB lighting pumping to the music (webradio would be perfect), all triggered from a presence detector :), one T3.6 could do the lot :)

I also want a lifesize cutout of Ben Stiller in Dodgeball with glowing red eyes that shouts "There's a good energy in the gym!" and other quotes periodically.

Ahhh...these pipedreams.

I just need more time for geeking =D
Just had a loft conversion and now it's time to sand, seal and paint 3 rooms and a 2 storey stairwell.......yeah thats every evening filled for a couple of months.....

maybe next year..
 
Yup.
At the moment, it plays "Tina Turner" from radio-station "Bayern 1" with 24MHz F_CPU :) Just a test - so, that means, the Teensy idles (almost) during playing mp3-webradio and can do a lot more..

Good luck for your loft-work :)
 
Last edited:
Nope, not on github, yet.
Why fiddling with ESP... thats a black-box, not more. STD-AT-Commandset is sufficiant (but new version).
Fiddling with Arduino-ESP would have been 300% more work. Absolutely no reason to do it. And I don't like the myriads of warnings during compile..

So, thats a "no", not interested. OK.

I didn't expect you would be interested - I was thinking if I saw it myself I might look at it.
 
You would see only AT-Commands, plus the mp3-code. Since none of them work with arduino-esp, it is not helpful. In addition, the ESP has not enough RAM.
 
You would see only AT-Commands, plus the mp3-code. Since none of them work with arduino-esp, it is not helpful. In addition, the ESP has not enough RAM.

My thought was to have the Arduino code only process the incoming data in place of the AT command set to feed the data to the Teensy?

When I used the prior Arduino for ESP the warnings were not as numerous - I think that is a (hopefully temporary) feature of the newest ESP Arduino release.
 
I'll upload a first example this evening.
It will be a minimal-webradio code - for my "Flexiboard", but works - with a bit fiddling - without.
 
Tim, i've uploaded it. It's less than 300 lines.
Do you see any chance that the ESP can be more useful with other Firmware, Tim ?
 
Hi Frank,

I am very interested in your new library! Have been using the old lib a lot for playing MP3s and also M4A-files (those that originate from Itunes, as I understand those files use a lossy AAC). However, as your new lib does not support AAC (yet ;-)), it could be nice for people who want to play AAC to have an example how to do that with the old lib. The following script is based on the example from the old lib and also contains a spectrum analyser:

Thanks, Frank for that nice library!

Have fun with the MP3 lib,

Frank

Use three push buttons and an ILI9341 screen.
Script has been tested on Teensy 3.5 and 3.6 (should run on older Teensy 3.x)

Code:
/* Merged MP3 and AAC file player by Frank Boesing with Spectrum Analyser by Rheslip
// for Teensy 3.5
// first attempt
// DD4WH 23. Oktober 2016
//
// assumes cheap 2.4`` TFT with ILI 9341
//
// Simple advanced MP3 file player example
//
// Requires the audio shield:
//   http://www.pjrc.com/store/teensy3_audio.html
//   or dac / pwm / SD shield
//
// Example sketch by Dnstje.nl
// Act like a real MP3/AAC player up to 255 songs.
// Buttons at port 14 15 16, feel free to remap them.
// This sketch will also using: EEPROM, Bounce library, Serial, SD.
// 
// MP3/AAC library code by Frank Boesing.

*/
/*
#include <Adafruit_ST7735.h> // Hardware-specific library

//SPI connections for Banggood 1.8" display
#define sclk 5
#define mosi 4
#define cs   2
#define dc   3
#define rst  1  // you can also connect this to the Arduino reset
Adafruit_ST7735 tft = Adafruit_ST7735(cs, dc, mosi, sclk, rst);
*/



#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <Bounce.h> //Buttons
#include <EEPROM.h> // store last track
#include "font_Arial.h"

#include <play_sd_mp3.h> //mp3 decoder
#include <play_sd_aac.h> // AAC decoder

#include <ILI9341_t3.h>
#include <Metro.h>

Metro processor=Metro(500); // Set up a 0.5 second Metro

#define BACKLIGHT_PIN 0

#define TFT_DC      20
#define TFT_CS      21
#define TFT_RST     32  // 255 = unused, connect to 3.3V
#define TFT_MOSI     7
#define TFT_SCLK    14
#define TFT_MISO    12

// Use hardware SPI (on Uno, #13, #12, #11) and the above for CS/DC
//ILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC);

ILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCLK, TFT_MISO);

#define BUTTON1 33  //NEXT
#define BUTTON2 34  //Play Pause
#define BUTTON3 35  //PREV 

Bounce bouncer1 = Bounce(BUTTON1, 50); 
Bounce bouncer2 = Bounce(BUTTON2, 50); 
Bounce bouncer3 = Bounce(BUTTON3, 50);

const int chipSelect = 10;  // if using another pin for SD card CS.
int track;
int tracknum;
int trackext[255]; // 0= nothing, 1= mp3, 2= aac, 3= wav.
String tracklist[255];
File root;
char playthis[15];
boolean trackchange;
boolean paused;
int eeprom_adress = 1900;

int count=0;
const int nsum[16] = {1, 1, 2, 2, 3, 4, 5, 6, 6, 8, 12, 14, 16, 20, 28, 24};
int peak[512];
int barm[512];
int maximum[16];
unsigned long last_time = millis();

AudioPlaySdMp3           playMp31; 
AudioPlaySdAac           playAac1;  

AudioAnalyzeFFT1024  myFFT;

AudioOutputI2S           i2s1;   

AudioMixer4              mixleft;
AudioMixer4              mixright;
//mp3
AudioConnection          patch1(playMp31,0,mixleft,0);
AudioConnection          patch2(playMp31,1,mixright,0);
//aac

AudioConnection          patch1a(playAac1, 0, mixleft, 1);
AudioConnection          patch2a(playAac1, 1, mixright, 1);
AudioConnection          patch3(mixleft, 0, myFFT, 0);
AudioConnection          patch5(mixleft, 0, i2s1, 0);
AudioConnection          patch6(mixright, 0, i2s1, 1);
AudioControlSGTL5000     sgtl5000_1;     //xy=240,153


void setup() {
  Serial.begin(115200);

  sgtl5000_1.enable();
  sgtl5000_1.volume(0.4); // für großen Kopfhörer 0.7, für kleinen 0.4

  SPI.setMOSI(7);
  SPI.setSCK(14);
  //setup pins with pullups
  pinMode(BUTTON1,INPUT_PULLUP);
  pinMode(BUTTON3,INPUT_PULLUP);
  pinMode(BUTTON2,INPUT_PULLUP);  
  // reads the last track what was playing.
  track = EEPROM.read(eeprom_adress); 

  // Audio connections require memory to work.  For more
  // detailed information, see the MemoryAndCpuUsage example
  AudioMemory(16);
  //put the gain a bit lower, some MP3 files will clip otherwise.
  mixleft.gain(0,0.7);
  mixright.gain(0,0.7);

  pinMode( BACKLIGHT_PIN, OUTPUT );
  analogWrite( BACKLIGHT_PIN, 1023 );

  tft.begin();
  tft.setRotation( 3 );
  tft.fillScreen(ILI9341_BLACK);
  tft.setCursor(10, 1);
  tft.setTextSize(2);
  tft.setTextColor(ILI9341_WHITE);
  tft.setFont(Arial_14);
  tft.print("Teensy MP3 Spec Analyser");

  uint16_t time = millis();
  time = millis() - time;

  //Start SD card
  if (!(SD.begin(chipSelect))) {
    // stop here, but print a message repetitively
    while (1) {
      Serial.println("Unable to access the SD card");
      delay(500);
    }
  }
  //Starting to index the SD card for MP3/AAC.
  root = SD.open("/");

  while(true) {

    File files =  root.openNextFile();
    if (!files) {
      //If no more files, break out.
      break;
    }
    String curfile = files.name(); //put file in string
    //look for MP3 or AAC files
    int m = curfile.lastIndexOf(".MP3");
    int a = curfile.lastIndexOf(".AAC");
    int a1 = curfile.lastIndexOf(".MP4");
    int a2 = curfile.lastIndexOf(".M4A");
    //int w = curfile.lastIndexOf(".WAV");

    // if returned results is more then 0 add them to the list.
    if(m > 0 || a > 0 || a1 > 0 || a2 > 0 ){  

      tracklist[tracknum] = files.name();
      if(m > 0) trackext[tracknum] = 1;
      if(a > 0) trackext[tracknum] = 2;  
      if(a1 > 0) trackext[tracknum] = 2;
      if(a2 > 0) trackext[tracknum] = 2;
      //  if(w > 0) trackext[tracknum] = 3;
      tracknum++;  
    }
    // close 
    files.close();
  }
  //check if tracknum exist in tracklist from eeprom, like if you deleted some files or added.
  if(track > tracknum){
    //if it is too big, reset to 0
    EEPROM.write(eeprom_adress,0);
    track = 0;
  }
  tracklist[track].toCharArray(playthis, sizeof(tracklist[track]));
}

//########################################
// end setup
//########################################


void playFileMP3(const char *filename)
{
  trackchange = true; //auto track change is allowed.
  // Start playing the file.  This sketch continues to
  // run while the file plays.
  printTrack();
  EEPROM.write(eeprom_adress,track); //meanwhile write the track position to eeprom address 0
  playMp31.play(filename);
  // Simply wait for the file to finish playing.
  while (playMp31.isPlaying()) {
//   float vol = analogRead(15);
//   vol = vol / 1024;
//   sgtl5000_1.volume(vol);
    spectrum();
   // update controls!
    controls();
  }
}

void playFileAAC(const char *filename)
{
  trackchange = true; //auto track change is allowed.
  // Start playing the file.  This sketch continues to
  // run while the file plays.
  // print track no & trackname
  printTrack ();
  EEPROM.write(eeprom_adress,track); //meanwhile write the track position to eeprom address 0
  playAac1.play(filename);
//   float vol = analogRead(15);
//   vol = vol / 1024;
//   sgtl5000_1.volume(vol);

  // Simply wait for the file to finish playing.
  while (playAac1.isPlaying()) {
    // update controls!
    spectrum();
    controls();
  }
}

void controls() {
  bouncer1.update();
  bouncer2.update();
  bouncer3.update();
  if ( bouncer1.fallingEdge()) { 
    nexttrack();
  }
  if ( bouncer2.fallingEdge()) {  
    pausetrack();
  }
  if ( bouncer3.fallingEdge()) { 
    prevtrack();
  }  
}

void loop() {

  if(trackext[track] == 1){
    Serial.println("MP3" );
    playFileMP3(playthis);
  }else if(trackext[track] == 2){
    Serial.println("aac");
    playFileAAC(playthis);
  }

  if(trackchange == true){ //when your track is finished, go to the next one. when using buttons, it will not skip twice.
    nexttrack();
  }
  //delay(100);
} //end loop

void nexttrack(){
  Serial.println("Next track!");
  trackchange=false; // we are doing a track change here, so the auto trackchange will not skip another one.
  playMp31.stop();
  playAac1.stop();
  track++;
  if(track >= tracknum){ // keeps in tracklist.
    track = 0;
  }  
  tracklist[track].toCharArray(playthis, sizeof(tracklist[track])); //since we have to convert String to Char will do this    
}

void prevtrack(){
  Serial.println("Previous track! ");
  trackchange=false; // we are doing a track change here, so the auto trackchange will not skip another one.
  playMp31.stop();
  playAac1.stop();
  track--;
  if(track <0){ // keeps in tracklist.
    track = tracknum-1;
  }  
  tracklist[track].toCharArray(playthis, sizeof(tracklist[track])); //since we have to convert String to Char will do this    
}

void pausetrack(){
  paused = !paused;
    playMp31.pause(paused);
    playAac1.pause(paused);
    
  //paused = playMp31.pause(!paused);
  //paused = playAac1.pause(!paused);

}


void randomtrack(){
  Serial.println("Random track!");
  trackchange=false; // we are doing a track change here, so the auto trackchange will not skip another one.
  if(trackext[track] == 1) playMp31.stop();
  if(trackext[track] == 2) playAac1.stop();

  track= random(tracknum);

  tracklist[track].toCharArray(playthis, sizeof(tracklist[track])); //since we have to convert String to Char will do this    
}

void printTrack () {
  tft.fillRect(0,222,320,17,ILI9341_BLACK);
  tft.setCursor(0, 222);
  tft.setTextColor(ILI9341_WHITE);
  tft.setTextWrap(true);
  tft.setTextSize(2);
  tft.print("Track: ");
  tft.print (track); 
  tft.print (" "); tft.print (playthis);
 } //end printTrack
 
 void spectrum() {
     if (myFFT.available()) {
    int scale;
//    scale = 2 + (1023 - analogRead(15)) / 7;
    scale = 8;
  for (int16_t x=0; x < 300; x+=1) {

     int bar = sqrt(abs(myFFT.output[x])) * scale;
     if (bar >190) bar=190;
     bar = 0.4 * bar + 0.6 * barm[x]; 
     if (bar > peak[x]) peak[x]=bar;
//     tft.drawFastVLine(x, 210-bar,bar, ILI9341_PURPLE);
     tft.drawFastVLine(x+10, 210-bar,bar, ILI9341_PINK);

     tft.drawFastVLine(x+10, 20, 210-bar-20, ILI9341_BLACK);    

     tft.drawPixel(x+10,210-peak[x], ILI9341_YELLOW);

     if(peak[x]>0) peak[x]-=1;
     barm[x] = bar;
  }
    count = 0;
  } //end if
//          if (processor.check() == 1)
//    {
      tft.setTextSize(1);
      tft.setCursor(240, 50);
      tft.print (AudioProcessorUsageMax());
      tft.setCursor(240, 70);
      tft.print (AudioMemoryUsageMax());
      AudioProcessorUsageMaxReset();
      AudioMemoryUsageMaxReset();
//    }
   } // end void spectrum
 
Hi Frank,

I am very interested in your new library! Have been using the old lib a lot for playing MP3s and also M4A-files (those that originate from Itunes, as I understand those files use a lossy AAC). However, as your new lib does not support AAC (yet ;-)), it could be nice for people who want to play AAC to have an example how to do that with the old lib. The following script is based on the example from the old lib and also contains a spectrum analyser:

Thanks, Frank for that nice library!

Have fun with the MP3 lib,

Frank

Use three push buttons and an ILI9341 screen.
Script has been tested on Teensy 3.5 and 3.6 (should run on older Teensy 3.x)

Code:
/* Merged MP3 and AAC file player by Frank Boesing with Spectrum Analyser by Rheslip
// for Teensy 3.5
// first attempt
// DD4WH 23. Oktober 2016
//
// assumes cheap 2.4`` TFT with ILI 9341
//
// Simple advanced MP3 file player example
//
// Requires the audio shield:
//   http://www.pjrc.com/store/teensy3_audio.html
//   or dac / pwm / SD shield
//
// Example sketch by Dnstje.nl
// Act like a real MP3/AAC player up to 255 songs.
// Buttons at port 14 15 16, feel free to remap them.
// This sketch will also using: EEPROM, Bounce library, Serial, SD.
// 
// MP3/AAC library code by Frank Boesing.

*/
/*
#include <Adafruit_ST7735.h> // Hardware-specific library

//SPI connections for Banggood 1.8" display
#define sclk 5
#define mosi 4
#define cs   2
#define dc   3
#define rst  1  // you can also connect this to the Arduino reset
Adafruit_ST7735 tft = Adafruit_ST7735(cs, dc, mosi, sclk, rst);
*/



#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <Bounce.h> //Buttons
#include <EEPROM.h> // store last track
#include "font_Arial.h"

#include <play_sd_mp3.h> //mp3 decoder
#include <play_sd_aac.h> // AAC decoder

#include <ILI9341_t3.h>
#include <Metro.h>

Metro processor=Metro(500); // Set up a 0.5 second Metro

#define BACKLIGHT_PIN 0

#define TFT_DC      20
#define TFT_CS      21
#define TFT_RST     32  // 255 = unused, connect to 3.3V
#define TFT_MOSI     7
#define TFT_SCLK    14
#define TFT_MISO    12

// Use hardware SPI (on Uno, #13, #12, #11) and the above for CS/DC
//ILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC);

ILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCLK, TFT_MISO);

#define BUTTON1 33  //NEXT
#define BUTTON2 34  //Play Pause
#define BUTTON3 35  //PREV 

Bounce bouncer1 = Bounce(BUTTON1, 50); 
Bounce bouncer2 = Bounce(BUTTON2, 50); 
Bounce bouncer3 = Bounce(BUTTON3, 50);

const int chipSelect = 10;  // if using another pin for SD card CS.
int track;
int tracknum;
int trackext[255]; // 0= nothing, 1= mp3, 2= aac, 3= wav.
String tracklist[255];
File root;
char playthis[15];
boolean trackchange;
boolean paused;
int eeprom_adress = 1900;

int count=0;
const int nsum[16] = {1, 1, 2, 2, 3, 4, 5, 6, 6, 8, 12, 14, 16, 20, 28, 24};
int peak[512];
int barm[512];
int maximum[16];
unsigned long last_time = millis();

AudioPlaySdMp3           playMp31; 
AudioPlaySdAac           playAac1;  

AudioAnalyzeFFT1024  myFFT;

AudioOutputI2S           i2s1;   

AudioMixer4              mixleft;
AudioMixer4              mixright;
//mp3
AudioConnection          patch1(playMp31,0,mixleft,0);
AudioConnection          patch2(playMp31,1,mixright,0);
//aac

AudioConnection          patch1a(playAac1, 0, mixleft, 1);
AudioConnection          patch2a(playAac1, 1, mixright, 1);
AudioConnection          patch3(mixleft, 0, myFFT, 0);
AudioConnection          patch5(mixleft, 0, i2s1, 0);
AudioConnection          patch6(mixright, 0, i2s1, 1);
AudioControlSGTL5000     sgtl5000_1;     //xy=240,153


void setup() {
  Serial.begin(115200);

  sgtl5000_1.enable();
  sgtl5000_1.volume(0.4); // für großen Kopfhörer 0.7, für kleinen 0.4

  SPI.setMOSI(7);
  SPI.setSCK(14);
  //setup pins with pullups
  pinMode(BUTTON1,INPUT_PULLUP);
  pinMode(BUTTON3,INPUT_PULLUP);
  pinMode(BUTTON2,INPUT_PULLUP);  
  // reads the last track what was playing.
  track = EEPROM.read(eeprom_adress); 

  // Audio connections require memory to work.  For more
  // detailed information, see the MemoryAndCpuUsage example
  AudioMemory(16);
  //put the gain a bit lower, some MP3 files will clip otherwise.
  mixleft.gain(0,0.7);
  mixright.gain(0,0.7);

  pinMode( BACKLIGHT_PIN, OUTPUT );
  analogWrite( BACKLIGHT_PIN, 1023 );

  tft.begin();
  tft.setRotation( 3 );
  tft.fillScreen(ILI9341_BLACK);
  tft.setCursor(10, 1);
  tft.setTextSize(2);
  tft.setTextColor(ILI9341_WHITE);
  tft.setFont(Arial_14);
  tft.print("Teensy MP3 Spec Analyser");

  uint16_t time = millis();
  time = millis() - time;

  //Start SD card
  if (!(SD.begin(chipSelect))) {
    // stop here, but print a message repetitively
    while (1) {
      Serial.println("Unable to access the SD card");
      delay(500);
    }
  }
  //Starting to index the SD card for MP3/AAC.
  root = SD.open("/");

  while(true) {

    File files =  root.openNextFile();
    if (!files) {
      //If no more files, break out.
      break;
    }
    String curfile = files.name(); //put file in string
    //look for MP3 or AAC files
    int m = curfile.lastIndexOf(".MP3");
    int a = curfile.lastIndexOf(".AAC");
    int a1 = curfile.lastIndexOf(".MP4");
    int a2 = curfile.lastIndexOf(".M4A");
    //int w = curfile.lastIndexOf(".WAV");

    // if returned results is more then 0 add them to the list.
    if(m > 0 || a > 0 || a1 > 0 || a2 > 0 ){  

      tracklist[tracknum] = files.name();
      if(m > 0) trackext[tracknum] = 1;
      if(a > 0) trackext[tracknum] = 2;  
      if(a1 > 0) trackext[tracknum] = 2;
      if(a2 > 0) trackext[tracknum] = 2;
      //  if(w > 0) trackext[tracknum] = 3;
      tracknum++;  
    }
    // close 
    files.close();
  }
  //check if tracknum exist in tracklist from eeprom, like if you deleted some files or added.
  if(track > tracknum){
    //if it is too big, reset to 0
    EEPROM.write(eeprom_adress,0);
    track = 0;
  }
  tracklist[track].toCharArray(playthis, sizeof(tracklist[track]));
}

//########################################
// end setup
//########################################


void playFileMP3(const char *filename)
{
  trackchange = true; //auto track change is allowed.
  // Start playing the file.  This sketch continues to
  // run while the file plays.
  printTrack();
  EEPROM.write(eeprom_adress,track); //meanwhile write the track position to eeprom address 0
  playMp31.play(filename);
  // Simply wait for the file to finish playing.
  while (playMp31.isPlaying()) {
//   float vol = analogRead(15);
//   vol = vol / 1024;
//   sgtl5000_1.volume(vol);
    spectrum();
   // update controls!
    controls();
  }
}

void playFileAAC(const char *filename)
{
  trackchange = true; //auto track change is allowed.
  // Start playing the file.  This sketch continues to
  // run while the file plays.
  // print track no & trackname
  printTrack ();
  EEPROM.write(eeprom_adress,track); //meanwhile write the track position to eeprom address 0
  playAac1.play(filename);
//   float vol = analogRead(15);
//   vol = vol / 1024;
//   sgtl5000_1.volume(vol);

  // Simply wait for the file to finish playing.
  while (playAac1.isPlaying()) {
    // update controls!
    spectrum();
    controls();
  }
}

void controls() {
  bouncer1.update();
  bouncer2.update();
  bouncer3.update();
  if ( bouncer1.fallingEdge()) { 
    nexttrack();
  }
  if ( bouncer2.fallingEdge()) {  
    pausetrack();
  }
  if ( bouncer3.fallingEdge()) { 
    prevtrack();
  }  
}

void loop() {

  if(trackext[track] == 1){
    Serial.println("MP3" );
    playFileMP3(playthis);
  }else if(trackext[track] == 2){
    Serial.println("aac");
    playFileAAC(playthis);
  }

  if(trackchange == true){ //when your track is finished, go to the next one. when using buttons, it will not skip twice.
    nexttrack();
  }
  //delay(100);
} //end loop

void nexttrack(){
  Serial.println("Next track!");
  trackchange=false; // we are doing a track change here, so the auto trackchange will not skip another one.
  playMp31.stop();
  playAac1.stop();
  track++;
  if(track >= tracknum){ // keeps in tracklist.
    track = 0;
  }  
  tracklist[track].toCharArray(playthis, sizeof(tracklist[track])); //since we have to convert String to Char will do this    
}

void prevtrack(){
  Serial.println("Previous track! ");
  trackchange=false; // we are doing a track change here, so the auto trackchange will not skip another one.
  playMp31.stop();
  playAac1.stop();
  track--;
  if(track <0){ // keeps in tracklist.
    track = tracknum-1;
  }  
  tracklist[track].toCharArray(playthis, sizeof(tracklist[track])); //since we have to convert String to Char will do this    
}

void pausetrack(){
  paused = !paused;
    playMp31.pause(paused);
    playAac1.pause(paused);
    
  //paused = playMp31.pause(!paused);
  //paused = playAac1.pause(!paused);

}


void randomtrack(){
  Serial.println("Random track!");
  trackchange=false; // we are doing a track change here, so the auto trackchange will not skip another one.
  if(trackext[track] == 1) playMp31.stop();
  if(trackext[track] == 2) playAac1.stop();

  track= random(tracknum);

  tracklist[track].toCharArray(playthis, sizeof(tracklist[track])); //since we have to convert String to Char will do this    
}

void printTrack () {
  tft.fillRect(0,222,320,17,ILI9341_BLACK);
  tft.setCursor(0, 222);
  tft.setTextColor(ILI9341_WHITE);
  tft.setTextWrap(true);
  tft.setTextSize(2);
  tft.print("Track: ");
  tft.print (track); 
  tft.print (" "); tft.print (playthis);
 } //end printTrack
 
 void spectrum() {
     if (myFFT.available()) {
    int scale;
//    scale = 2 + (1023 - analogRead(15)) / 7;
    scale = 8;
  for (int16_t x=0; x < 300; x+=1) {

     int bar = sqrt(abs(myFFT.output[x])) * scale;
     if (bar >190) bar=190;
     bar = 0.4 * bar + 0.6 * barm[x]; 
     if (bar > peak[x]) peak[x]=bar;
//     tft.drawFastVLine(x, 210-bar,bar, ILI9341_PURPLE);
     tft.drawFastVLine(x+10, 210-bar,bar, ILI9341_PINK);

     tft.drawFastVLine(x+10, 20, 210-bar-20, ILI9341_BLACK);    

     tft.drawPixel(x+10,210-peak[x], ILI9341_YELLOW);

     if(peak[x]>0) peak[x]-=1;
     barm[x] = bar;
  }
    count = 0;
  } //end if
//          if (processor.check() == 1)
//    {
      tft.setTextSize(1);
      tft.setCursor(240, 50);
      tft.print (AudioProcessorUsageMax());
      tft.setCursor(240, 70);
      tft.print (AudioMemoryUsageMax());
      AudioProcessorUsageMaxReset();
      AudioMemoryUsageMaxReset();
//    }
   } // end void spectrum

It works fine on a Teensy 3.2.
Fun to see that part of my code still works. I was worried since 2 years ago I didnt had a audioboard yet. after I had it I had to change alot of lines to let sd and audio working. After I seen my messy code again, I like to rewrite it again lol. (just the track search and button thing, not the library I mean).
Good job on the fft, I never could get a nice readout.

c57cbe79ba.jpg
 
I've started using the Audiolib-MP3 library and am having some trouble.
Some of my MP3 files play just fine, others stop after reading two blocks of 1024 bytes.
On the ones that stop, pushData continues to return -1 without updating the length.

Here's the loop() code:

Code:
if (sdFile.available()) {
  sdLen = sdFile.read(sdBuf, sizeof(sdBuf));
  Serial.printf("Read %ld\n", sdLen);
}
if (sdLen > 0) {
  if ((err = playMP3_1.pushData(&sdBuf[0], &sdLen)) < -1) {
    Serial.printf("MP3 decode error ", err);
  }
  if (err == 0) {
    Serial.printf("Channels: %d\n", playMP3_1.numChannels());
  }
}

On the MP3 files that play, I get two "Read 1024" messages followed by a "Channels" message, then a stream of "Read 1024" while the MP3 plays.
On the ones that do not play, I only get two "Read 1024" messages.
I've looked for a common reason for the ones not to play, like strange bit rate, long "title" field, or "contributing artist", or other ID3 tag. It doesn't seem to matter -- some files with ID3 tags play, some without ID3 tags play. Bit rate doesn't seem to matter either. I have two files at 64 Kbps, one plays and one does not.

I've tried changing the block size of the read. I get the same behavior at 512 bytes. The MP3 files that played at 1024 bytes play at 512 bytes, nothing else plays.
With 2048 bytes, nothing plays, not even the ones that play at 512 and 1024 bytes.

Has anyone seen this behavior?
 
Last edited:
Any chance that you can send me one of the not-working files ?
Please note, that the newer MP3-Lib does not handle ID3 Tags - it just tries to read until a decodeable block is found. Perhaps this does not work well. I didn't test mp3-files much since i was a bit focused on decoding a stream.


Or, maybe, it better to use the old lib in this case ?
 
When I get home I'll do some more testing and get you a file. The files use long names but I'm just opening a directory and using 'openNextFile()' to get a file handle. I'll have to print out the 8.3 name and then figure out which long file name it is really referencing.

I think maybe this code change in AudioPlayMP3Queue::decode will get it to work, but I haven't tested it yet:

Code:
        do {
                // ***** Check SYNC-START *****
                // find start of next MP3 frame, return error if not found
                offset = myMP3FindSyncWord(p, framebuf_BytesCount);
                if (offset < 0) {
                        if (framebuf_BytesCount >= 4) {
                                //move unused part of framebuffer to the start
                                memmove(framebuf, p+(framebuf_BytesCount - 4), 4);
                                framebuf_BytesCount = 4;
                        }
                        return ERR_MP3_INDATA_UNDERFLOW;
                }
 
It went a little farther with the code change. I would hear snippets of content but nothing more than a half-second or so, interspersed with silence. After a few seconds I heard a sine wave and the program stopped responding to serial input.
I'm attaching a file that does not play.

View attachment aa5tb_089.zip
 
That's a 8000Hz file. The lib can play 44.1kHz files only. That's a limitation of the audio-library which is 44.1 kHz fixed.
You can convert the files to 44.1Khz of course - best is to remove the ID3-Tag in this case, too, if you're using this lib (Or remove them with your Sketch before playing the file).
The older lib handles ID3 Tags.
 
Last edited:
I believe there's still an active (USA jurisdiction) patent on using samples rates below 32 kHz. It expires later this year.
 
Yup, but that didn't stop Thomson and others who funded the development from applying for plenty of patents in the USA and other countries.

https://wiki.multimedia.cx/index.php/MP3_Patents

In the early to mid 1990, the USA had legal loopholes called "submarine" patents. I don't know exactly how it worked, but the net result was companies could delay their patent, which also delayed its expiration. In the USA, it's also legal (but risky) to apply for a patent up to 1 year after the invention is made available to the public. Most of the rest of the world doesn't allow this. That's why prior art is 20 years in most places, but 21 in the USA.

Since the MP3 decoding algorithm was published in 1993, even the 21 years would have everything enter the public domain by 2014... except for these submarine patents. Well, also the 1993 standard didn't include the lower sample rates. Those were added a couple years later with an addendum.

Somehow I had thought the low sample rate patent was among the very last to expire near the end of this year. But that page says it expires on May 26, 2018.

At least according to that list, other than low sample rates, the last patent expires next month, on April 16th.
 
That's a 8000Hz file. The lib can play 44.1kHz files only. That's a limitation of the audio-library which is 44.1 kHz fixed.
You can convert the files to 44.1Khz of course - best is to remove the ID3-Tag in this case, too, if you're using this lib (Or remove them with your Sketch before playing the file).
The older lib handles ID3 Tags.

Thanks, I have about 1,500 files to convert now.
It looks like
ffmpeg -i i.mp3 -map_metadata -1 -ac 1 -ar 44100 -b 96k o.mp3
would do the job, I'll have to experiment.
Or do you have any suggestions?
 
Thanks, I have about 1,500 files to convert now.
It looks like
ffmpeg -i i.mp3 -map_metadata -1 -ac 1 -ar 44100 -b 96k o.mp3
would do the job, I'll have to experiment.
Or do you have any suggestions?
converting 1500 files can be done with a batch or shell-script..
 
converting 1500 files can be done with a batch or shell-script..

Thanks,
ffmpeg -i i.mp3 -map_metadata -1 -ac 1 -ar 44100 -b:a 96k o.mp3​
did the trick.
I tried both with and without '-map_metadata -1' and both worked without issue.
The teensy 3.6, 1,500 MP3 files, and Windows machine are at home.
Linux machine with ffmpeg is at work.

Tomorrow I'll bring the microSD card into work and convert all the files.

Some of the files have blanks in their name, so the script isn't as straight-forward as I'd like.
 
Status
Not open for further replies.
Back
Top