/* 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