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):

USB MIDI device

  • A USB MIDI keyboard, guitar, or perhaps something that you have built yourself?

Setup Instructions:

  • Download the latest version of Raspbian Lite from: https://www.raspberrypi.org/downloads/raspbian/
  • Burn the image to a 4GB+ MicroSD card, and follow the excellent instructions for headless SSH configuration at: https://www.tomshardware.com/reviews/raspberry-pi-headless-setup-how-to,6028.html
  • 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