NetMF MP3 Player Part 3

Building on the file listing code from the previous post in the next class we built a basic multi threaded music player using an enhanced version of the Vs1053B driver based on the softelectrotech.and bluecone code.

The code uses five interrupt ports (I used 5 buttons on the 4 analog ports on the Seeedstudio V2 Base shield and D5 to make it easier to fit the Mp3 shield)

As the Vs1053 driver is now running asynchronously it fires an event when the current track has finished playing

   public class Program
   {
      static string[] MusicFiles;
      static Vs1053B player = new Vs1053B(Pins.GPIO_PIN_D2, Pins.GPIO_PIN_D6, Pins.GPIO_PIN_D7, Pins.GPIO_PIN_D8);
      static byte volume = 200;
      static int trackNumber = 1;
      static public string TrackFilename { get { return MusicFiles[trackNumber - 1]; } }

      public static void Main()
      {
         MusicFiles = Directory.GetFiles(@"\SD");

         foreach( string file in MusicFiles)
         {
            Debug.Print(file);
         }

         InterruptPort playPause = new InterruptPort(Pins.GPIO_PIN_D5, false, Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeLow);
         playPause.OnInterrupt += playPause_OnInterrupt;

         InterruptPort volumeUp = new InterruptPort(Pins.GPIO_PIN_A0, false, Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeLow);
         volumeUp.OnInterrupt += volumeUp_OnInterrupt;

         InterruptPort volumeDown = new InterruptPort(Pins.GPIO_PIN_A1, false, Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeLow);
         volumeDown.OnInterrupt += volumeDown_OnInterrupt;

         InterruptPort previousTrack = new InterruptPort(Pins.GPIO_PIN_A2, false, Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeLow);
         previousTrack.OnInterrupt += previousTrack_OnInterrupt;

         InterruptPort nextTrack = new InterruptPort(Pins.GPIO_PIN_A3, false, Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeLow);
         nextTrack.OnInterrupt += nextTrack_OnInterrupt;

         player.SetVolume(volume);
         player.Filename = TrackFilename;
         player.onMusicFinished += player_onMusicFinished;

         player.Play();

         Thread.Sleep(Timeout.Infinite);
      }

      static void player_onMusicFinished()
      {
         trackNumber += 1;

         if (trackNumber > MusicFiles.Length)
         {
            trackNumber = 1;
         }
         Debug.Print("player_onMusicFinished " + trackNumber + " of " + MusicFiles.Length);

         player.Filename = TrackFilename;
      }

      static void previousTrack_OnInterrupt(uint data1, uint data2, DateTime time)
      {
         trackNumber -= 1;

         if (trackNumber < 1)          {             trackNumber = MusicFiles.Length;          }          Debug.Print("previousTrack_OnInterrupt " + trackNumber + " of " + MusicFiles.Length);          player.CancelPlayback();          player.Filename = TrackFilename;       }       static void nextTrack_OnInterrupt(uint data1, uint data2, DateTime time)       {          trackNumber += 1;          if (trackNumber > MusicFiles.Length)
         {
            trackNumber = 1;
         }
         Debug.Print("nextTrack_OnInterrupt " + trackNumber + " of " + MusicFiles.Length);

         player.CancelPlayback();
         player.Filename = TrackFilename;
      }

      static void playPause_OnInterrupt(uint data1, uint data2, DateTime time)
      {
         Debug.Print("playPause_OnInterrupt ");
         if (player.IsPaused())
         {
            player.Resume();
         }
         else
         {
            player.Pause();
         }
      }

      static void volumeDown_OnInterrupt(uint data1, uint data2, DateTime time)
      {
         Debug.Print("volumeDown_OnInterrupt " + volume);
         if (volume > 0)
         {
            volume -= 1;
         }
         player.SetVolume(volume);
      }

      static void volumeUp_OnInterrupt(uint data1, uint data2, DateTime time)
      {
         Debug.Print("volumeUp_OnInterrupt " + volume);
         if (volume < 255)
         {
            volume += 1;
         }
         player.SetVolume(volume);
      }
   }

Next steps are to ignore contact bounce on the buttons and play MP3 files in a more consistent order
musicplayerv2

Netduino with Mp3 Shield and 5 button UI

Netduino Mp3 player with 5 button UI

NetMF MP3 Player Part 2

Building on the file listing code from the previous post in the next class we wrote the simplest possible NetMF code to play all of MP3 files on an SD Card. The Mp3 player shields I have all use a Vs1053B chip to decode the MP3 byte stream. This sample uses the driver code from softelectrotech.

public static void Main()
{
   Vs1053B player = new Vs1053B(Pins.GPIO_PIN_D2, Pins.GPIO_PIN_D6, Pins.GPIO_PIN_D7, Pins.GPIO_PIN_D8);
   string[] MusicFiles = Directory.GetFiles(@"\SD");
   player.SetVolume(180, 180);

   // Print a list of all the files on the SD card.
   foreach (string file in MusicFiles)
   {
      Debug.Print(file);
   }

   foreach (string file in MusicFiles)
   {
      Debug.Print("Play start " + file);

      player.Play(file, true);

      Debug.Print("Play finish " + file);
   }
}

Some of the students observed the order of the files was not what they were expecting. The order of the files appeared to depend on how they were copied to the memory card.

\SD\05 Sunday Bloody Sunday.mp3
\SD\06 Bad.mp3
\SD\07 Where the Streets Have No Name.mp3
\SD\08 I Will Follow.mp3
\SD\09 The Unforgettable Fire.mp3
\SD\10 Sweetest Thing [The Single Mix].mp3
\SD\11 Desire.mp3
\SD\12 When Love Comes to Town.mp3
\SD\13 Angel of Harlem.mp3
\SD\14 All I Want Is You.mp3
\SD\01 Pride (In the Name of Love).mp3
\SD\02 New Year's Day.mp3
\SD\03 With or Without You.mp3
\SD\04 I Still Haven't Found What I'm Looking For.mp3
Playback
Play start \SD\05 Sunday Bloody Sunday.mp3
Play finish \SD\05 Sunday Bloody Sunday.mp3
Play start \SD\06 Bad.mp3

All of the students observed that the tacks were being played synchronously which didn’t allow you to change the volume or interrupt the playback to pause the current track or change the track being played.

The next steps were to ensure the music files were sorted into a consistent order and that playback was not synchronous.

MusicPlayerSyncBasic code