A MIDI keyboard player and soundfont explorer for Raspberry Pi, built around the Pirate Audio Line Out HAT. Connect a MIDI keyboard, select from a curated soundfont library, and browse 128 GM tones — all controlled from the HAT's 4-button interface and 240x240 LCD.
- Raspberry Pi Zero 2 WH (or any Pi with 40-pin GPIO)
- Pirate Audio Line Out HAT — ST7789 240x240 LCD + 4 buttons + I2S DAC
- HiFiBerry-compatible DAC output via I2S (exclusive ALSA access, no dmix)
- USB or Bluetooth MIDI keyboard (tested with SINCO SMK25 Mini, Yamaha E50)
Browse and load from a curated library of 10 soundfonts covering General MIDI, retro keyboards, vocal/choral, and specialty synths. Soundfonts are loaded with a dual-layer strategy: the GM base font loads first to provide full preset coverage across all 16 MIDI channels, then the specialty font layers on top. This prevents FluidSynth segfaults that occur when specialty fonts lack presets for certain channels (especially channel 9 drums).
A two-level preset browser organized by the 16 standard GM categories:
| Category | Programs | Category | Programs |
|---|---|---|---|
| Piano | 0-7 | Reed | 64-71 |
| Chromatic Perc | 8-15 | Pipe | 72-79 |
| Organ | 16-23 | Synth Lead | 80-87 |
| Guitar | 24-31 | Synth Pad | 88-95 |
| Bass | 32-39 | Synth FX | 96-103 |
| Strings | 40-47 | Ethnic | 104-111 |
| Ensemble | 48-55 | Percussive | 112-119 |
| Brass | 56-63 | Sound FX | 120-127 |
Select a category to see its 8 tones, then select a tone to change the sound immediately. The selected tone persists across menu navigation and soundfont changes. When a specialty soundfont is loaded, program_change searches the soundfont stack — specialty sounds take priority where available, with GM as fallback.
Supports USB and Bluetooth MIDI keyboards. The MIDI callback handles Note On/Off, Program Change, Control Change, and Pitch Bend. Live MIDI input works alongside all menu operations.
Route MIDI to the internal FluidSynth engine or to external MIDI devices (USB or Bluetooth). External output uses the MIDO library for port management.
Optional Bluetooth MIDI device scanning and pairing. Discovers advertising devices and connects via bluetoothctl.
The deployment includes 10 soundfonts (~247MB total), selected for variety and stability:
| Soundfont | Size | Character |
|---|---|---|
| General MIDI 64 1.6 | 17M | System default — reliable GM baseline |
| GM GeneralUser GS | 30M | High-quality GM, community standard |
| GM Merlin Elite | 54M | Premium quality, most realistic samples |
| Vocal Chorium Rev B | 28M | Rich choral/vocal ensemble |
| Vocal Acapella GM | 20M | Voice-focused GM hybrid |
| Retro Roland SC88 | 22M | Classic Roland Sound Canvas (90s) |
| Retro Yamaha FB01 | 20M | Classic Yamaha FM synthesis |
| Retro OPL2 FM | 27M | AdLib/Sound Blaster FM nostalgia |
| Synth Korg Triton | 2.8M | Workstation synth, very compact |
| Inst Glass Tones | 26M | Atmospheric/ambient textures |
The Pirate Audio HAT has 4 buttons mapped to GPIO pins:
| Button | GPIO | Function |
|---|---|---|
| A (top) | GPIO5 | Select / Enter |
| B (second) | GPIO6 | Back (one menu level) |
| Up | GPIO16 | Scroll up |
| Down | GPIO24 | Scroll down |
Main Menu
+-- MIDI INPUT Select input device (USB/Bluetooth MIDI keyboards)
+-- MIDI OUTPUT Select output (FluidSynth internal or external MIDI)
+-- SOUND FONT Browse and load .sf2 files from /usr/share/sounds/sf2/
+-- TONE Browse GM presets in current soundfont
| +-- Piano, Chromatic Perc, Organ, Guitar, Bass, Strings,
| | Ensemble, Brass, Reed, Pipe, Synth Lead, Synth Pad,
| | Synth FX, Ethnic, Percussive, Sound FX
| +-- [8 tones per category] --> Select to change sound
+-- BLUETOOTH Toggle Bluetooth scanning (OFF/ON)
The B button navigates back one level: from tones to categories, from categories to main menu. From any other submenu, B resets to main menu.
This project is forked from mrfloydst/midifileplayer. Key changes:
| Area | Original | This Version |
|---|---|---|
| Soundfont loading | Single sfload(path, True) — crashes on specialty fonts missing GM presets |
Dual-layer: GM base + specialty on top. All 16 channels always have valid presets |
| Tone selection | No on-device tone browsing. Required keyboard to send Program Change | Two-level category browser (16 categories x 8 tones) via HAT buttons |
| Soundfont library | 2 basic GM fonts | Curated 10-font collection spanning GM, retro, vocal, synth |
| MIDI file playback | Threaded play_midi_file() — prone to use-after-free crashes |
Removed from FluidSynth output path (external MIDI output still works via MIDO) |
| Logging | No runtime logging | [LOG] statements throughout with unbuffered stdout for real-time log capture |
| Setup | Manual step-by-step instructions | Automated setup.sh script with verification |
| Menu items | MIDI FILE (file playback) | TONE (preset browser) — replaced MIDI FILE |
chmod +x setup.sh
sudo ./setup.sh
sudo rebootSee the detailed steps in setup.sh or refer to the original midifileplayer README for manual installation.
crontab -e
# Add this line:
@reboot sleep 5 && sudo systemctl stop fluidsynth 2>/dev/null; sudo /usr/bin/python3 /home/pi/midifileplayer/midiplayer.py > /home/pi/mlog.txt 2>&1/home/pi/
+-- midifileplayer/ # This repo (cloned here)
+-- midifiles/ # MIDI files for playback (create manually)
+-- sf2 -> /usr/share/sounds/sf2/ # Symlink to soundfont directory
To deploy changes from a development machine to the Pi:
scp midiplayer.py pi@<pi-ip>:/tmp/midiplayer.py
ssh pi@<pi-ip> "sudo cp /tmp/midiplayer.py /home/pi/midifileplayer/midiplayer.py && sudo reboot"