Raspberry Pi
MIDI Synthesizer Engine
Instructions for configuring a Raspberry Pi 3B or 4 as a portable, headless, ultra-low latency MIDI synthesizer using the FluidSynth synthesizer.
Shopping list:
Raspberry Pi 3B/3B+ (lower power requirement when using a battery bank):
(Discontinued, but still widely available)
OR
Raspberry Pi 4 (2GB+ allows for larger SoundFont options):
USB sound card (required for low latency):
Devices that I have personally tested as working flawlessly, though I'm sure most others also work well:
Pyle PAD20MXU (recommended for EQ adjustment): https://www.amazon.com/dp/B009GU4UHY/
Sabrent AU-MMSA (much cheaper): https://www.amazon.com/dp/B00IRVQ0F8/
USB MIDI device
A USB MIDI keyboard, guitar, or perhaps something that you have built yourself?
Setup Instructions:
Download the latest version of Raspberry Pi OS Lite from: https://www.raspberrypi.org/software/operating-systems/
Burn the image to a 4GB+ MicroSD card using Balena Etcher (or other image writer of choice): https://www.balena.io/etcher/
Mount the FAT32 "boot" partition on the card on your computer.
Create an empty file on the root of the drive named "ssh" with no file extension to enable the SSH server.
Create a new text file in the root of the drive named "wpa_supplicant.conf" and save the text below customized to your locale and wireless network:
country=US
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
network={
scan_ssid=1
ssid="your_wifi_ssid"
psk="your_wifi_password"
}
Boot the Pi. When connected to the network, it should respond at address: raspberrypi.local
Launch PuTTY (or your SSH client of choice) and connect/log-in as username "pi" with password "raspberry".
Run sudo apt update && sudo apt upgrade to upgrade all installed software to current versions.
Run sudo raspi-config, change the default password, configure the device for your locale, and enable console autologin in the boot options.
Run sudo apt install alsa-utils fluidsynth screen to install the required synthesizer packages.
Run cd ~/ && wget https://raw.githubusercontent.com/KOOPInstruments/raspi-synth/master/synth.sh && chmod +x ~/synth.sh to download the headless raspi-synth script, and mark it for execution.
Run nano ~/.bashrc, add the line /home/pi/synth.sh to the end of the file, and press Ctrl-o Ctrl-x to save and quit nano. This will tell the Pi to launch the script automatically on login (which also means launch on boot due to console autologin enabled earlier).
Run cat /proc/asound/cards to get a list of connected sound devices, and take note of the unique sound device name string on the same line as the device number, example in bold: 2 [CODEC ]: USB-Audio - USB AUDIO CODEC.
Run nano ~/synth.sh and edit the line beginning with audioDevice=$ to insert your unique sound device name between the double-quotes in the 'grep' statement. Press Ctrl-o Ctrl-x to save and quit nano.
Run alsamixer press F6 to select your sound card, set the master volume to a reasonable level, and press Esc to exit.
Run sudo reboot and test out your new synthesizer!
Using Different SoundFonts:
Download your General MIDI SoundFont (.SF2) file to the /home/pi/ folder, run nano ~/synth.sh and change the end of the line beginning with screen -dmS FluidSynth0 to modify the path for your SoundFont file name and location, for example: /home/pi/Timbres\ Of\ Heaven\ GM_GS_XG_SFX\ V\ 3.4\ Final.sf2
RasPi-Synth Script:
## Raspberry Pi 4 FluidSynth MIDI Sound Engine
## 2019 - KOOP Instruments (koopinstruments@gmail.com)
# Remount the file system read/write to allow modifications
sudo mount -o remount,rw /
# Update the clock
sudo ntpd -q -g
echo "Starting synth script in 5 seconds (press Ctrl-c to cancel)..."
sleep 1
echo "4..."
sleep 1
echo "3..."
sleep 1
echo "2..."
sleep 1
echo "1..."
sleep 1
# If the script was not cancelled, remount the file system readonly
sudo mount -o remount,r /
## Optional power saving (uncomment if desired):
# sudo ifconfig wlan0 down # Disable the Wi-Fi adapter
sudo tvservice --off # Disable HDMI video output
echo "Killing any existing fluidsynth processes..."
sudo killall -s SIGKILL fluidsynth &>/dev/null
# Run the rest of the script on a loop in case a new sound card is connected, the FluidSynth server crashes, or a new MIDI instrument is connected
while [[ 1 -eq 1 ]]; do
# Run 'cat /proc/asound/cards' to get a list of audio devices, and modify the grep statement below with a unique identifying string
# Examples:
# audioDevice=$(cat /proc/asound/cards | grep "bcm2835_alsa" | awk -F" " '{ print $1 }') # Raspberry Pi on-board audio (high latency - only use if no other options)
# audioDevice=$(cat /proc/asound/cards | grep "USB-Audio - USB Audio Device" | awk -F" " '{ print $1 }') # Sabrent USB sound card
# audioDevice=$(cat /proc/asound/cards | grep "USB-Audio - Logitech" | awk -F" " '{ print $1 }') # Logitech USB sound card
audioDevice=$(cat /proc/asound/cards | grep "USB-Audio - USB AUDIO" | awk -F" " '{ print $1 }') # Peavy USB mixer sound card
if pgrep -x "fluidsynth" > /dev/null
then
sleep 1
else
echo "Starting fluidsynth server..."
# Blink both lights to let the user know that the synth is starting
sudo echo 1 | sudo tee /sys/class/leds/led0/brightness &>/dev/null
sudo echo 1 | sudo tee /sys/class/leds/led1/brightness &>/dev/null
sudo echo 0 | sudo tee /sys/class/leds/led0/brightness &>/dev/null
sudo echo 0 | sudo tee /sys/class/leds/led1/brightness &>/dev/null
sudo echo 1 | sudo tee /sys/class/leds/led0/brightness &>/dev/null
sudo echo 1 | sudo tee /sys/class/leds/led1/brightness &>/dev/null
sudo echo 0 | sudo tee /sys/class/leds/led0/brightness &>/dev/null
sudo echo 0 | sudo tee /sys/class/leds/led1/brightness &>/dev/null
sudo echo 1 | sudo tee /sys/class/leds/led0/brightness &>/dev/null
sudo echo 1 | sudo tee /sys/class/leds/led1/brightness &>/dev/null
sudo echo 0 | sudo tee /sys/class/leds/led0/brightness &>/dev/null
sudo echo 0 | sudo tee /sys/class/leds/led1/brightness &>/dev/null
# Start the FluidSynth server in a new screen session to allow reattaching for troubleshooting purposes
screen -dmS FluidSynth0 bash -c "sudo nice -n -20 fluidsynth -i -s -g 0.6 -a alsa -o audio.alsa.device=hw:$audioDevice -c 1 -z 1 -o synth.cpu-cores=4 -o synth.polyphony=128 /usr/share/sounds/sf2/FluidR3_GM.sf2"
sleep 5
fi
# Scrape the ALSA port number of the FluidSynth Server
fsClientNum=$(aconnect -l | grep "FLUID Synth" | awk -F" " '{ print $2 -0 }')
# Enable one light to let the user know that device discovery is running
echo 1 | sudo tee /sys/class/leds/led1/brightness &>/dev/null
myCounter=1
while [[ $myCounter -lt $fsClientNum ]]; do
aconnect $myCounter:0 $fsClientNum:0 2>/dev/null
let myCounter=myCounter+1
done
echo 0 | sudo tee /sys/class/leds/led1/brightness &>/dev/null
sleep 1
done