/*****************************************************************************
VS100X-based MP3 player
Plays mp3 files that must be in the SD formatted as FAT32
Uses a module based on a VS100X chip and a 20x4 LCD
*******************************************************************************/
#include <SPI.h>
#include <SD.h>
#include <AGMp3.h>
#include <LiquidCrystal.h>
// Pins for the lcd
#define LCD_RS 3
#define LCD_Enable 4
#define LCD_D4 A0
#define LCD_D5 A1
#define LCD_D6 A2
#define LCD_D7 A3
//Encoder pins
#define ENC_A 8
#define ENC_B 10
//Button pins
#define button_FORAWARD 0
#define button_BACK 1
// Minimum volume in db
#define MIN_VOL 60
// Maximum no of entries in a catalog
#define MAX_ENTRIES 15
// No of characters in each entry
#define MAX_LONG 20
#define MAX_LONGMAS1 21
// Defining characters for song progress
byte bar1[8] = { B10001, B10001, B10001, B10001, B10001, B10001, B10001, B10001 };
byte bar2[8] = { B11001, B11001, B11001, B11001, B11001, B11001, B11001, B11001 };
byte bar3[8] = { B11101, B11101, B11101, B11101, B11101, B11101, B11101, B11101 };
byte bar4[8] = { B11111, B11111, B11111, B11111, B11111, B11111, B11111, B11111 };
byte bar5[8] = { B11111, B11111, B11111, B11111, B11111, B11111, B11111, B11111 };
byte barV[8] = { B00001, B00001, B00001, B00001, B00001, B00001, B00001, B00001 };
// Initialiding liquid crystal display
LiquidCrystal lcd(LCD_RS, LCD_Enable, A0, A1, A2, A3);
//Creating object MP3
AGMp3Player MP3player;
//Catalog file
File fText;
char FileName[31];
byte temp;
byte result;
//Variab
char strArtist[MAX_LONGMAS1];
char strAlbum[MAX_LONGMAS1];
char strTitle[MAX_LONGMAS1];
// Variables to know the current and previous catalog entry, as well as the tenth of entries
byte Entry = 0;
byte Entry A = 0;
byte maxEntries = 0;
// Variables to control the encoder
byte posOn = 0;
byte encoderAon = LOW;
// Actual volume
byte vol = 20;
// Catalog of entries
char catalog[MAX_ENTRIES][MAX_LONGMAS1];
byte level, artist, album, track = 0;
char strLine [30];
void errorCard() {
lcd.setCursor(0, 4);
lcd.print("Error in SD card or card not present.");
}
void showProgress() {
byte pos = MP3player.getPosition() ;
if ( pos == posOn )
return;
posOn = pos;
byte pos10 = pos / 10 ;
lcd.setCursor(0, 4);
for (byte i = 0; i < 10; i++)
lcd.write(5);
lcd.setCursor(0, 4);
for (byte i = 0; i < pos10; i++)
lcd.write(4);
lcd.write((pos - 10 * pos10) / 2);
lcd.setCursor(12, 4);
lcd.print("Vol:");
lcd.print(map(vol, 0, MIN_VOL, 10, 0), DEC);
//lcd.print(FreeRam(),DEC);
lcd.print(" ");
}
// Debouncing of the buttons
int buttonClick (byte button) {
if (digitalRead(button) == LOW) {
delay(100);
return digitalRead(button) == LOW;
}
return 0;
}
// Reads a line of text from the file
char* readLine(File myFile, char* line) {
byte idx = 0;
uint16_t letter = myFile.read();
// we eliminate carriage and if returns
while (myFile.available() && (l == 13 || letter == 10))
letter = myFile.read();
while (myFile.available() && (letter != 13)) {
if (letter == '�') {
letter = 'n' + 125;
}
line[idx] = letter;
letter = myFile.read();
idx++;
}
line[idx] = 0;
return line;
}
// reads a catalog file and stores it in the catalog variable
void readFile(char* number) {
byte index = 0;
byte len = 0;
memset(strLine, 0, sizeof(strLine));
memset(catalog, 0, sizeof(catalog));
if (fText = SD.open(number)) {
while ( fText.available() ) {
leerLinea(fText, strLine);
len = min(strlen(strLinea), MAX_LONG);
if ( len > 0 ) {
strncpy(catalog[indice], strLinea, len);
indice++;
}
}
fText.close();
maxEntries = index;
entryA = -1;
entry = 0;
encoderAOn = HIGH;
}
else {
errorCard();
}
}
// Routine to read the encoder and modify the catalog entry
void leerEncoder() {
byte n = digitalRead(ENC_A);
if ((encoderAOn == LOW) && (n == HIGH)) {
if (digitalRead(ENC_B) == LOW) {
entrance = max(entrance - 1, 0);
} else {
entrance = min(entrance + 1, maxEntradas - 1);
}
}
encoderAOn = n;
}
// Routine to read the encoder and modify the Volume
void readEncoderVol() {
byte n = digitalRead(ENC_A);
if ((encoderAOn == LOW) && (n == HIGH)) {
if (digitalRead(ENC_B) == LOW) {
vol = min(vol + 5, MIN_VOL);
MP3player.setVolume(vol, vol);
} else {
vol = max(vol - 5, 0);
MP3player.setVolume(vol, vol);
}
}
encoderAOn = n;
}
void setup() {
pinMode(9, OUTPUT);
pinMode(button_FORAWARD, INPUT);
pinMode(button_BACK, INPUT);
pinMode(ENC_A, INPUT);
pinMode(ENC_B, INPUT);
digitalWrite(ENC_A, HIGH);
digitalWrite(ENC_B, HIGH);
digitalWrite(button_FORAWARD, HIGH);
digitalWrite(button_BACK, HIGH);
if ( MP3player.initialize() != 0 ) {
errorCard();
}
MP3player.setVolume(vol, vol);
lcd.begin(16, 4);
memset(strArtist, 0, MAX_LONGMAS1);
memset(strArtist, 0, MAX_LONGMAS1);
memset(strAlbum, 0, MAX_LONGMAS1);
lcd.createChar(0, bar1);
lcd.createChar(1, bar2);
lcd.createChar(2, bar3);
lcd.createChar(3, bar4);
lcd.createChar(4, bar5);
lcd.createChar(5, barV);
readFile("artist.txt");
}
void printLCD (byte col, byte fila, byte numEntry) {
if ( numEntry <= maxEntry - 1) {
char line[MAX_LONGMAS1];
memset(line, 0, sizeof(line));
strncpy(line, catalogo[numEntrada], 20 - col);
lcd.setCursor(col, file);
lcd.print(line);
}
}
void showCatalog(byte force) {
if ( (entrance != entranceA) || force) {
lcd.clear();
switch (nivel) {
case 0:
lcd.write('z' + 4);
printLCD (1, 0, entrance);
printLCD (1, 1, entrance + 1);
printLCD (1, 2, entrance + 2);
printLCD (1, 3, entrance + 3);
break;
case 1:
lcd.print(strArtiste);
lcd.setCursor(0, 1);
lcd.print(' ');
lcd.write('z' + 4);
printLCD (2, 1, entrance);
printLCD (2, 2, entrance + 1);
printLCD (2, 3, entrance + 2);
break;
case 2:
lcd.print(strArtist);
lcd.setCursor(0, 1);
lcd.print(strAlbum);
lcd.setCursor(0, 2);
lcd.print(' ');
lcd.write('z' + 4);
printLCD (2, 2, entrance);
printLCD (2, 3, entrance + 1);
break;
case 3:
lcd.print(strArtist);
lcd.setCursor(0, 1);
lcd.print(strAlbum);
lcd.setCursor(0, 2);
lcd.print(strTitle);
break;
}
entranceA = entrance;
}
}
void update(byte foward) {
byte result;
switch (level) {
case 0:
readFile("artistas.txt");
if (!foward) {
entrance = artist - 1;
}
break;
case 1:
if (forward) {
artist = entrance + 1;
strcpy(strArtist, catalog[entrance]);
}
sprintf(fileName, "ARTIST%02d/album.txt", artist);
readFile(fileName);
if (!forward) {
entrance = album - 1;
}
break;
case 2:
if (forward) {
album = entrance + 1;
strcpy(strAlbum, catalog[entrance]);
}
sprintf(fileName, "ARTIST%02d/ALBUM%02d/track.txt", artist, album);
readFile(fileName);
if (!forward) {
entrance = track - 1;
}
break;
case 3:
track = entrance + 1;
strcpy(strTitle, catalog[entrance]);
sprintf(fileName, "ARTIST%02d/ALBUM%02d/track%03d.mp3", artist, album, track);
result = MP3player.tocaMP3(fileName);
if (result == 0) {
errorCard();
}
break;
}
showCatalog(true);
}
void loop() {
if (buttonClick(button_FORAWARD) ) {
if ( levels < 3) {
levels++;
update(1);
}
else if (MP3player.isPla()) {
MP3player.paraMp3();
}
}
if (buttonPulsado(button_BACK) ) {
if ( MP3player.isPlaying() ) {
MP3player.forMp3();
}
if ( level > 0) {
level--;
}
update(0);
}
if ( (level == 3) && !MP3player.iisPlaying() ) {
if ( entrance < maxEntry ) {
entrance++;
} else {
level = 2;
}
update(0);
}
if (MP3player.isPlaying()) {
readEncoderVol();
} else {
readEncoder();
}
showCatalog(false);
showProgress();
}
i did use the sparkfun mp3 shield library from sparkfun