MP3 Player with an RP2350/VS1053 - It's Alive!

With the new tweaked hardware architecture and some custom drivers, I now have my MP3 player able to interactively list and play music from the SD Card.
5 min read

This is part 3 about my MP3 player project. If you missed part 1, or part 2, you may want to browse those for context.

Once again, I’m trying to build an MP3 Player, that also includes FM Radio, GPS, and maybe some games.

Music from the SD Card

If you recall from part 2, I was having troubles using the SD card and screen at the same time, likely due to something in the display driver. To solve this, I’m instead using the built-in SD card on the VS1053 board I got from Adafruit.

To make that possible, I forked the driver I found, to enable it to take a Mutex containing a reference of the SPI bus, rather than owning it. That way, I could my modified shared_bus to switch between SD and the decoder.

This works fairly well, especially for constant bitrate MP3 files. I tried using straight variable bitrate .m4a files from my iTunes collection, and while they do play - you can tell when the bitrate goes up because it starts to slow the song down.

The simple solution is to just encode everything to a constant bitrate MP3. I can deal with that.

I’m figuring out a solution to indexing metadata so it’s more efficient to list files by album, artist, etc. Same goes for album art - I may have a tool that runs to properly convert and index files for display.

image of music menu

Streaming Music to the VS1053

One of the first things I noticed, is that it would take a while to start playing. Turns out - that’s actually due to the embedded ID3 tags in the files, where there’s a large album art image it’s streaming (and the mp3 decoder is ignoring).

So, I did a little parsing of the ID3 header (if present), to determine it’s length.

// buffer contains the first 1024 bytes from the file, as read from the SD card.
// we're streaming it to the VS1053 in 1024 byte sections, which are split by the driver into smaller chunks.
if &buffer[0..3] != b"ID3" {
    id3_size = 0;
} else {
    info!("ID3 tag detected");

    // bytes 6–9 contain the size of the tags
    let size =
        ((buffer[6] as usize & 0x7F) << 21) |
        ((buffer[7] as usize & 0x7F) << 14) |
        ((buffer[8] as usize & 0x7F) << 7)  |
        (buffer[9] as usize & 0x7F);

    id3_size = size + 10; // total tag size including header
    info!("ID3 tag size: {}", size);
}

Then, I can skip past the tags by seeking the file to that offset. Doing that, music plays almost instantly. I also included some logic to parse out the tags in the first chunk I read from the file (mainly, to pull the song name, artist, etc). At the moment, I only process the first 1024 bytes of the file, since I need to read the size of the ID3 tag structure anyways. For the most part, it seems the important tags are up front in the file.

I want to enable album art - but I’m thinking that’ll be a script you run to extract and generate a thumbnails database, so I don’t need to decode png/jpg files on the fly at the same time as loading the file for playback.

Architectural Considerations

I’m going to try and offload all the SD card logic to the 2nd RP2350 core, and communicating with it to tell it to play/pause, etc.

That way, I can draw the UI in real time, respond to user input to pause/play, while the second core is in it’s SD Read -> VS1053 write loop.

The channels I was using for communicating between the usb serial might work there, as it’ll likely be a few commands like: “Play this file”, “pause”, “skip to X timestamp”, “seek forward”, “seek back”.

Case Design & Hardware

I’m starting to consider how to fit all of this within a custom case. I really want to retain the fm radio, so I may see if I can use the line in r/l pins on the VS1053 to enable that to do the multiplexing, rather than the external DAC. That’d save a bit of space.

Also, the GPS/Compass aren’t yet integrated to the new prototype either - I need to see about space.

I’m also considering dumping the OLED for a slightly larger TFT screen, which might be better at showing album artwork. If I go larger screen, I can likely make the case a little larger to fit extra electronics.

Perhaps, I can design and have a case printed out of Aluminum for the ultimate premium feel? If so, maybe I’ll add clicky side buttons!

If it is aluminum, ditching the GPS (maybe an external module?), is probably the right move to avoid needing a plastic window on the case. Not sure how the FM radio will work quite yet. I might design a custom mother PCB rather than having all the individual pieces separately mounted inside.

image of main menu

Next Steps

  • Multi-core implementation (core 0: UI, core 1: music)
  • Improved music indexing / album art db
  • VS1053 Line In / Multiplexer for FM
  • PCB Designs
  • Case Designs
  • Load executables from SD Card (games, etc)

Feedback

Found a typo or technical problem? report an issue!

Subscribe to my Newsletter

Like this post? Subscribe to get notified for future posts like this.