Hackster is hosting Hackster Holidays, Ep. 6: Livestream & Giveaway Drawing. Watch previous episodes or stream live on Monday!Stream Hackster Holidays, Ep. 6 on Monday!
Shahariar
Published © CC BY-ND

Sony DIY Retro MP3 Player

A plain vanilla MP3 player build with Sony Spresense board which has a display + 5 buttons for controlling volume/play/pause/changing songs.

IntermediateFull instructions provided4 hours2,714
Sony DIY Retro MP3 Player

Things used in this project

Hardware components

Spresense boards (main & extension)
Sony Spresense boards (main & extension)
×1
SparkFun 7 Segment Bubble Display
×1
4x6 cm double sided protoboar
×1
Pushbutton switch 12mm
SparkFun Pushbutton switch 12mm
×5
Resistor 1k ohm
Resistor 1k ohm
×2
Resistor 10k ohm
Resistor 10k ohm
×1
Resistor 2.21k ohm
Resistor 2.21k ohm
×1
Resistor 4.75k ohm
Resistor 4.75k ohm
×1
Resistor 22.1k ohm
Resistor 22.1k ohm
×1
1N4007 – High Voltage, High Current Rated Diode
1N4007 – High Voltage, High Current Rated Diode
×1
Male Header 40 Position 1 Row (0.1")
Male Header 40 Position 1 Row (0.1")
×1
Female Header 8 Position 1 Row (0.1")
Female Header 8 Position 1 Row (0.1")
×1
SparkFun Electret Microphone Breakout
SparkFun Electret Microphone Breakout
×1

Software apps and online services

Arduino IDE
Arduino IDE

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)

Story

Read more

Schematics

Spresense mp3 player

https://easyeda.com/suntop/sony-spresense-mp3

Code

code

C/C++
ver 0.0.1 with play/stop and vol up/down, song prev/next - looping not added yet (diy)
#include <SDHCI.h>
#include <Audio.h>
#include "SevSeg.h"  

SDClass SD;
AudioClass *theAudio;
SevSeg BubbleDisp;


File mp3file;
bool ErrEnd = false;
int volume = -320; // vol 120n to -1020
int track =1; // currently selected mp3 track 1.mp3, 2.mp3, 3.mp3
int err; // some sony variable, dont worry about it
int track_max =6; // highest number of tracks in sd card eg 99.mp3 

int switch_val = 0; // adc switches value
bool mid_switch = 0; // play/pause
bool bol_switch = 0; // vol up
bool bor_switch = 0; // vol down
bool tol_switch = 0;// prev song
bool tor_switch = 0;// next song

 // display messages //
  char Word1[5] = {'N','o','S','d'}; 
  char Word2[5] = {'U','o','l','-'};
  char Word3[5] = {'_','E','r','r'};
  char Word4[5] = {'S','t','O','P'};
  char Word5[5] = {'P','L','A','Y'};
  char Word6[5] = {'S','o','n','Y'};
  char Word7[5] = {'S','o','n','g'};
  char Word8[5] = {'U','S','b','2'};
  char Word9[5] = {'C','O','P','Y'};
  char Word10[5] = {'F','I','L','E'};
  char Word11[5] = {'t','o','S','D'};
  char Word12[5] = {' ','t','o',' '};
  char Word13[5] = {'b','i','r','d'};
  char Word14[5] = {' ','P','C',' '};
  char Word15[5] = {'L','O','A','d'};

static void audio_attention_cb(const ErrorAttentionParam *atprm)
{
   if (atprm->error_code >= AS_ATTENTION_CODE_WARNING)
    {      ErrEnd = true;   }
}


void setup()
{
  
  Bubble_Disp_Init();
  for(int i =0;i<5;i++)
  {BubbleDisp_DisplayText(Word6, 0);}

  // start audio system //
  theAudio = AudioClass::getInstance();
  theAudio->begin(audio_attention_cb);
  theAudio->setRenderingClockMode(AS_CLKMODE_NORMAL);
  theAudio->setPlayerMode(AS_SETPLAYER_OUTPUTDEVICE_SPHP, AS_SP_DRV_MODE_LINEOUT);
  err_t err = theAudio->initPlayer(AudioClass::Player0, AS_CODECTYPE_MP3, "/mnt/sd0/BIN", AS_SAMPLINGRATE_AUTO, AS_CHANNEL_STEREO);
  mp3file = SD.open(String(String(track)+".mp3"));
  err = theAudio->writeFrames(AudioClass::Player0, mp3file);
  theAudio->setVolume(volume);
  theAudio->startPlayer(AudioClass::Player0);
}


void loop()
{

// run music //     
    while(mid_switch==0)
   {
     BubbleDisp_DisplayText(Word5, 0);
     BubbleDisp_DisplayNumber(track,0);
     Vol_Ctrl();
     Scan_Switches();
     Song_Change();
     
     err = theAudio->writeFrames(AudioClass::Player0, mp3file);     
        if (err == AUDIOLIB_ECODE_FILEEND)
          {music_end_led();mid_switch=1;}
   }

// stop music //
    while(mid_switch==1)
    {
      theAudio->stopPlayer(AudioClass::Player0);
      mp3file.close();
       while(mid_switch==1)
       {
        BubbleDisp_DisplayText(Word4, 0);
        Scan_Switches();
       }      
    }
    
// re-start music //
     mp3file = SD.open(String(String(track)+".mp3"));
     err = theAudio->writeFrames(AudioClass::Player0, mp3file);
     theAudio->setVolume(volume);
     theAudio->startPlayer(AudioClass::Player0);
 
     usleep(40000);
} // end of loop


//////////// disp functions ///////////////

void Bubble_Disp_Init(void)

{
   int displayType = COMMON_CATHODE; 

  
       //This pinout is for a bubble dispaly
       //Declare what pins are connected to the GND pins (cathodes)
       int digit1 = 16; //1 4 6 10
       int digit2 = 25; 
       int digit3 = 19; 
       int digit4 = 21; 
       
       //Declare what pins are connected to the segments (anodes)
       int segA = 23; 
       int segB = 24; 
       int segC = 18; 
       int segD = 27; 
       int segE = 17; 
       int segF = 26; 
       int segG = 28; 
       int segDP= 20; 
   
  int numberOfDigits = 4; // 4 digit display
  BubbleDisp.Begin(displayType, numberOfDigits, digit1, digit2, digit3, digit4, segA, segB, segC, segD, segE, segF, segG, segDP);
  BubbleDisp.SetBrightness(80); // 100% brightness level
 
}



void BubbleDisp_DisplayNumber (int number, int dp)
{
   char tempString[10]; //Used for sprintf
   sprintf(tempString, "%4d", number); //Convert number into a string
   for(int i =0;i<100;i++)
  {
   BubbleDisp.DisplayString(tempString, dp); //(number, decimal point)
  } 
}

void BubbleDisp_DisplayText (char text[], int dp)
{
   for(int i =0;i<50;i++)
  {
   BubbleDisp.DisplayString(text, 0); //(numberToDisplay, decimal point location)
  }
}

// user input switches //
// press and hold until disp goes blank/msg chages 
// sd card operations take time //
void Scan_Switches (void)
{
switch_val = analogRead(A3);
if (switch_val>740 && switch_val<790)
{mid_switch ^=1;}  
if (switch_val>400 && switch_val<450)
{bol_switch =1;}
if (switch_val>240 && switch_val<300)
{bor_switch =1;}
if (switch_val>650 && switch_val<700)
{tol_switch =1;}
if (switch_val>550 && switch_val<600)
{tor_switch =1;};
}

// volume control //
void Vol_Ctrl(void)
{

  while(bol_switch ==1)
  { 
    volume = volume+20; bol_switch =0;
    BubbleDisp_DisplayText(Word2, 0);
    BubbleDisp_DisplayText(Word2, 0); 
    err = theAudio->writeFrames(AudioClass::Player0, mp3file);     
    BubbleDisp_DisplayNumber((1000+volume)/20,0);
    BubbleDisp_DisplayNumber((1000+volume)/20,0);
    theAudio->setVolume(volume);    
    Scan_Switches();
    
  }
   while(bor_switch ==1)
  { 
     volume = volume-20; bor_switch =0;
     BubbleDisp_DisplayText(Word2, 0);
     BubbleDisp_DisplayText(Word2, 0);
     err = theAudio->writeFrames(AudioClass::Player0, mp3file);     
     BubbleDisp_DisplayNumber((1000+volume)/20,0);
     BubbleDisp_DisplayNumber((1000+volume)/20,0);
     theAudio->setVolume(volume);
     Scan_Switches();
   }
   
  
   
}

// music control //
void Song_Change(void)
{
if (tol_switch==1&& track>1)
{
  track = track-1;
  BubbleDisp_DisplayNumber(track,0);
  tol_switch =0;
  theAudio->stopPlayer(AudioClass::Player0);
  BubbleDisp_DisplayText(Word15, 0);
  mp3file.close();
  mp3file = SD.open(String(String(track)+".mp3"));
  BubbleDisp_DisplayText(Word15, 0);
  err = theAudio->writeFrames(AudioClass::Player0, mp3file);
  theAudio->startPlayer(AudioClass::Player0);

}

if (tor_switch==1&& track<track_max)
{
  track = track+1;
  BubbleDisp_DisplayNumber(track,0);
  tor_switch =0;
  theAudio->stopPlayer(AudioClass::Player0);
  BubbleDisp_DisplayText(Word15, 0);
  mp3file.close();
  mp3file = SD.open(String(String(track)+".mp3"));
  BubbleDisp_DisplayText(Word15, 0);
  err = theAudio->writeFrames(AudioClass::Player0, mp3file);
  theAudio->startPlayer(AudioClass::Player0);

}



}

// unused fn for LED effect //


void music_running_led()
{
     digitalWrite(LED0, HIGH);
    delay(100);
    digitalWrite(LED1, HIGH);
    delay(100);
    digitalWrite(LED2, HIGH);
    delay(100);
    digitalWrite(LED3, HIGH);
    delay(300);

    digitalWrite(LED0, LOW);
    delay(100);
    digitalWrite(LED1, LOW);
    delay(100);
    digitalWrite(LED2, LOW);
    delay(100);
    digitalWrite(LED3, LOW);
    delay(300);
 
}

void music_end_led ()
{
  for (int j =0;j<2;j++)
  {
    digitalWrite(LED0, HIGH);
    digitalWrite(LED1, HIGH);
    digitalWrite(LED2, HIGH);
    digitalWrite(LED3, HIGH);
    delay(150);
    digitalWrite(LED0, LOW);
    digitalWrite(LED1, LOW);
    digitalWrite(LED2, LOW);
    digitalWrite(LED3, LOW);
    delay(150);
  }
}

  
  // start sd card mass storage for copying music
  // there is a 3 sec bug in this part , after that music stops thus disabled//
 /*  if (!SD.begin()) 
   { BubbleDisp_DisplayText(Word1, 0);} // no SD
   else if(SD.beginUsbMsc())
   {BubbleDisp_DisplayText(Word3, 0);} // error msc
    else{
    while(switch_val<100)
    {
    BubbleDisp_DisplayText(Word8, 0);
    BubbleDisp_DisplayText(Word9, 0);
    BubbleDisp_DisplayText(Word10, 0);
    BubbleDisp_DisplayText(Word8, 0);
    BubbleDisp_DisplayText(Word9, 0);
    BubbleDisp_DisplayText(Word10, 0);
    switch_val = analogRead(A3);
    }
    SD.endUsbMsc();
    SD.end();
    delay(600);
    SD.begin();
    switch_val =0;
    mid_switch =0;
   }
   */

BIN.zip

C Header File
unzip and paste the BIN folder on the root directory of sdcard (with the mp3 songs)
No preview (download only).

SevSeg.zip

C Header File
sev seg
No preview (download only).

bootloader

C Header File
ver 1.2.0 is buggy, use 1.1.3 or below
No preview (download only).

Credits

Shahariar

Shahariar

74 projects • 266 followers
"What Kills a 'Great life' is a 'Good Life', which is Living a Life Inside While Loop"

Comments