Wednesday, November 16, 2016

Electric Piano Part 2: Raspberry Pi SF2 Synth

This is a continuation of a previous post on re-building the electronics for an old, broken electric piano keyboard. After getting the keyboard working as a MIDI device, I decided to add in a Raspberry Pi to act as a synthesiser to actually generate out different instrument sounds based on the MIDI data from a Teensy which is used to read the keyboard state.

I found some good instructions here for running Fluidsynth, an open-source, command-line based synth on the Pi that uses Soundfont sf2 files. The great thing about soundfont is that I can download and pick and choose form thousands of different instruments for free in the internets, which will make for a more interesting playing experience than the simple square waves that I can generate on the Teensy. After install Fluidsynth, I connected up the MIDI/USB connection from the Teensy into a Raspberry Pi 2 model B, and ran: "fluidsynth -a alsa /usr/share/sounds/sf2/FluidR3_GM.sf2". I then put Fluidsynth into the back ground using cmd-z and ran: "aconnect 20:0 128:0" to route the MIDI input from the Teensy (client 20, port 0) to Fluidsynth (client 128, port 0 on my machine). I could now hear a standard piano instrument when playing the piano, but the sound is fairly delayed through the HDMI audio (a latency of maybe 250 ms by my guess). Tried changing audio output to headphones using "amixer cset numid=3 1", and the delay is slightly less noticeable, but the sound quality is dreadful.

A bit of digging around on the internets regarding Raspberry Pi audio quality, and I came across this, an experimental firmware update for improved headphone jack audio quality, using a different DAC interface. I ran "sudo rpi_update" (I ran it on Oct 12th) and went and added two lines to my /boot/config.txt file: "audio_pwm_mode=2" and "dtparam=audio=on", rebooted and re-tested audio. The quality improvement is very noticeable; at least through my headphones, the quality of sound is now acceptable.

I turned my attention to trying to get amplified audio out of my setup. I connected up a class D audio amp I had left over from a previous project to the 3.5mm audio jack on the RPi, powered it using the 5V out from the RPi GPIO and connected it up to a 4 ohm 2.5W speaker that was inside the original piano keyboard. After configuring the RPi audio volume to 80% using "amixer cset numid=1 -- 80%" I was getting a reasonable sound coming out when playing. I ramped up the volume to 100% on the gain pot on the amplifier and played again: now quite loud and a little bit distorted. When I power cycled the RPi I was getting a fairly loud popping sound coming from the speaker, and also when the RPi booted up again. When I had the volume up to max I was getting a little lightning bolt brown out warning coming up on my screen too ... I decided to tune the volume down to a slightly more modest level of 80% again. Didn't notice the brown out issues again. I added a pot to the signal line coming out of the RPi and into the amplifier for volume control.

I did a bit of configuring in my /etc/rc.local file on the Pi to start everything up automatically:

amixer cset numid=3 1
amixer cset numid=1 -- 80%
fluidsynth -s -i -a alsa -z 256 -c 6 -f fs_config.txt /usr/share/sounds/sf2/FluidR3_GM.sf2
sleep 10
aconnect 20:0 128:0

The -c and -z flags are for controlling audio buffer sizes and number of buffers in fluidsynth/alsa: setting these I'm able to find an acceptable middle ground between low latency and infrequency of audio stuttering: I still sometimes get a little bit of stutter on instruments with complex, long lasting waveforms, but the latency is now at an acceptable level (I haven't figured out yet how to measure it precisely, but I mean from a playing/responsive feel perspective). I also setup a configuration file for Fluidsynth so I can automatically set the instruments for different channels (fs_config.txt).

Next thing I'm going to do is add some more controls onto the Teensy and then package the whole thing up in a new custom designed case. Stay tuned!