A lightweight embedded MP3 player built on the Raspberry Pi Pico W that reads audio files from a microSD card and supports browsing by songs, artists, genres, and playlists — without duplicating files.
This project focuses on efficient data handling and low-memory design suitable for microcontrollers.
- 🎧 MP3 playback from microSD card (SPI interface)
- 📂 Single-copy file storage (no duplication)
- 🔤 Browse Songs (sorted by title)
- 🎤 Browse Artists (grouped view)
- 🎼 Browse Genres (filtered via metadata)
- 📜 Playlist support using
.m3ufiles - ⚡ Fast startup using prebuilt metadata index
- 🧠 Memory-efficient (no database required)
Due to the limited resources of the RP2040 (264KB RAM), this project avoids heavy solutions like SQLite.
Instead, it uses:
- A flat file system (FAT32)
- A metadata index file (
songs.csv) - Pointer-based indexing in memory
songs[] -> master list of all songs
byTitle[] -> sorted view (Songs menu)
byArtist[] -> grouped view (Artists menu)
byGenre[] -> filtered view (Genre menu)
playlist[] -> dynamic list from .m3u files
All views reference the same MP3 file paths.
FAT32
/music/
song1.mp3
song2.mp3
song3.mp3
/index/
songs.csv
/playlists/
chill.m3u
workout.m3u
To avoid parsing MP3 files on-device, metadata is precomputed.
title,artist,genre,path
Song A,Artist X,Rock,/music/songA.mp3
Song B,Artist Y,Jazz,/music/songB.mp3
- Faster boot time
- Simpler firmware
- Lower CPU usage
Playlists are stored as standard .m3u files.
/music/song1.mp3
/music/song3.mp3
/music/song7.mp3
The player reads file paths and maps them to the internal song list.
> Songs
Artists
Genre
Playlists
| Menu | Action |
|---|---|
| Songs | Sort all songs by title |
| Artists | Group songs by artist |
| Genre | Filter songs by genre |
| Playlists | Load .m3u file and play list |
typedef struct {
char title[64];
char artist[48];
char genre[32];
char path[128];
} Song;- Initialize SPI + microSD
- Mount FAT filesystem
- Load
songs.csv - Populate
songs[] - Build indexes:
- Sorted (title)
- Grouped (artist)
- Filtered (genre)
To minimize memory usage:
- Use pointer arrays instead of copying structs
- Sort using
qsort - Build lightweight lookup tables
Example:
Song* byTitle[MAX_SONGS];- Raspberry Pi Pico W
- microSD card module (SPI)
- microSD card (FAT32)
- Audio output:
- DAC / PWM / I2S
- or MP3 decoder (e.g., VS1053)
- Pico SDK
- CMake
- ARM GCC toolchain
mkdir build
cd build
cmake ..
make- Hold BOOTSEL on Pico W
- Copy
.uf2file to device
- Avoid scanning
/musicat runtime for large libraries - Use
songs.csvfor fast initialization - Keep metadata structures small to fit RAM constraints
You can generate songs.csv using a Python script:
- Scan
/music - Extract ID3 tags
- Output CSV
Suggested library:
mutagen- Search functionality
- Album-based navigation
- Shuffle / repeat modes
- Display (OLED/LCD)
- Bluetooth audio
- WiFi sync using Pico W
MIT License
Ethan Macson
GitHub: https://github.com/EMacson
This project demonstrates:
- Embedded systems design
- Efficient data structures under memory constraints
- File system handling on microcontrollers
- Real-time audio pipeline considerations