linux.autostatic.com

Linux Audio Babble

Using a Raspberry Pi as a piano

30 comments

Recently I posted about my successful attempt to get LinuxSampler running on the Raspberry Pi. I've taken this a bit further and produced a script that turns the Raspberry Pi into a fully fledged piano. Don't expect miracles, the sample library I used is good quality so the RPi might choke on it every now and then with regard to disk IO. But it's usable if you don't play too many notes at once or make extensive use of a sustain pedal. I've tested the script with a Class 4 SD though so a faster SD card could improve stability.

Edit: finally got around buying a better SD card and the difference is huge! I bought a SanDisk Extreme Class 10 SD card and with this SD card I can run LinuxSampler at lower latencies and I can play more notes at once.

Before you can run the script on your Raspberry Pi you will need to tweak your Raspbian installation so you can do low latency audio. How to achieve this is all described in the Raspberry Pi wiki article I've put up on wiki.linuxaudio.org. After you've set up your RPi you will need to install JACK and LinuxSampler with sudo apt-get install jackd1 linuxsampler. Next step is to get the Salamander Grand Piano sample pack on your RPi:

cd
mkdir LinuxSampler
cd LinuxSampler
wget -c http://download.linuxaudio.org/lau/SalamanderGrandPianoV2\
/SalamanderGrandPianoV2_44.1khz16bit.tar.bz2
wget -c http://dl.dropbox.com/u/16547648/sgp44.1khz_V2toV3.tar.bz2
tar jxvf SalamanderGrandPianoV2/SalamanderGrandPianoV2_44.1khz16bit.tar.bz2
tar jxvf sgp44.1khz_V2toV3.tar.bz2 -C SalamanderGrandPianoV2_44.1khz16bit \
--strip-components=1

Please note that decompressing the tarballs on the RPi could take some time. Now that you've set up the Salamander Grand Piano sample library you can download the script and the LinuxSampler config file:

cd
mkdir bin
wget -c https://raw.github.com/AutoStatic/scripts/rpi/piano -O /home/pi/bin/piano
chmod +x bin/piano
wget -c https://raw.github.com/AutoStatic/configs/rpi/home/pi/LinuxSampler\
/SalamanderGrandPianoV3.lscp -O
/home/pi/LinuxSampler/SalamanderGrandPianoV3.lscp

Almost there. We've installed the necessary software and downloaded the sample library, LinuxSampler config and piano script. Now we need to dot the i’s and cross the t’s because the script assumes some defaults that might be different in your setup. Let's dissect the script:

#!/bin/bash

if ! pidof jackd &> /dev/null
then
  sudo killall ifplugd &> /dev/null
  sudo killall dhclient-bin &> /dev/null
  sudo service ntp stop &> /dev/null
  sudo service triggerhappy stop &> /dev/null
  sudo service ifplugd stop &> /dev/null
  sudo service dbus stop &> /dev/null
  sudo killall console-kit-daemon &> /dev/null
  sudo killall polkitd &> /dev/null
  killall gvfsd &> /dev/null
  killall dbus-daemon &> /dev/null
  killall dbus-launch &> /dev/null
  sudo mount -o remount,size=128M /dev/shm &> /dev/null
  echo -n performance \
| sudo tee /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor &> /dev/null
  if ip addr | grep wlan &> /dev/null
  then
    echo -n "1-1.1:1.0" | sudo tee /sys/bus/usb/drivers/smsc95xx/unbind &> /dev/null
  fi
  jackd -P84 -p128 -t2000 -d alsa -dhw:UA25 -p512 -n2 -r44100 -s -P -Xseq \
&> /dev/null &
fi

This is the first section of the script. An if clause that checks if JACK is already running and if that's not the case the system gets set up for low latency use, a simple check is done if there is an active WiFi adapter and if so the ethernet interface is disabled and then on the last line JACK is invoked. Notice the ALSA name used, hw:UA25, this could be different on your RPi, you can check with aplay -l.

jack_wait -w &> /dev/null

jack_wait is a simple app that does nothing else but checking if JACK is active, the -w option means to wait for JACK to become active.

if ! pidof linuxsampler &> /dev/null
then
  linuxsampler --instruments-db-location $HOME/LinuxSampler/instruments.db \
&> /dev/null &
  sleep 5
netcat -q 3 localhost 8888 \
< $HOME/LinuxSampler/SalamanderGrandPianoV3.lscp &> /dev/null &
fi

This stanza checks if LinuxSampler is running, if not LinuxSampler is started and 5 seconds later the config file is pushed to the LinuxSampler backend with the help of netcat.

while [ "$STATUS" != "100" ]
do
  STATUS=$(echo "GET CHANNEL INFO 0" | netcat -q 3 localhost 8888 \
| grep INSTRUMENT_STATUS | cut -d " " -f 2 | tr -d '\r\n')
done

A simple while loop that checks the load status of LinuxSampler. When the load status has reached 100% the script will move on.

jack_connect LinuxSampler:0 system:playback_1 &> /dev/null
jack_connect LinuxSampler:1 system:playback_2 &> /dev/null
#jack_connect alsa_pcm:MPK-mini/midi_capture_1 LinuxSampler:midi_in_0 &> /dev/null
jack_connect alsa_pcm:USB-Keystation-61es/midi_capture_1 LinuxSampler:midi_in_0 \
&> /dev/null

This part sets up the necessary JACK connections. The portnames of the MIDI devices can be different on your system, you can look them up with jack_lsp which will list all available JACK ports.

jack_midiseq Sequencer 176400 0 69 20000 22050 57 20000 44100 64 20000 66150 67 20000 &
sleep 4
jack_connect Sequencer:out LinuxSampler:midi_in_0
sleep 3.5
jack_disconnect Sequencer:out LinuxSampler:midi_in_0
killall jack_midiseq

This is the notification part of the script that will play four notes. It's based on jack_midiseq, another JACK example tool that does nothing more but looping a sequence of notes. It's an undocumented utility so I'll explain how it is invoked:

jack_midiseq

<command> <JACK port name> <loop length> <start value> <MIDI note value> <length value>

Example:
jack_midiseq Sequencer 176400 0 69 20000 22050 57 20000 44100 64 20000 66150 67 20000

JACK port name: Sequencer
Loop length: 4 seconds at 44.1 KHz (176400/44100)
Start value of first note: 0
MIDI note value of first note: 69 (A4)
Length value: 20000 samples, so that's almost half a second
Start value of second note: 22050 (so half a second after the first note)
MIDI note value of second note: 57 (A3)
Length value: 20000 samples
Start value of third note: 44100 (so a second after the first note)
MIDI note value of second note: 64 (E4)
Length value: 20000 samples
Start value of third note: 66150 (so one second and a half after the first note)
MIDI note value of second note: 67 (G4)
Length value: 20000 samples

Now the script is finished, the last line calls exit with a status value of 0 which means the script was run successfully.

exit 0

After making the script executable with chmod +x ~/bin/piano and running it you can start playing piano with your Raspberry Pi! Again, bear in mind that the RPi is not made for this specific purpose so it could happen that audio starts to stutter every now and then, especially when you play busy parts or play more than 4 notes at once.


Using a Raspberry Pi as a piano: quick demo

Written by Jeremy

Sunday 20 October 2013 om 19:54

30 comments

  1. Thanks for the detailed walk through. I feel like I am really close to having this work but something seems to be failing with the output from jack. Do I need to set the output in linuxsampler somehow?

    I am trying to use the onboard 1/8th inch output.. Is this the trouble perhaps? I recently found a thread where you had been discussing issues with this. Thanks!

    c0wfunk

    c0wfunk

    09-11-’13 04:33

  1. Isn’t
    cat file | netcat …
    a bit redundant here? That’s equivalent to
    netcat …. < file

    RalfD

    RalfD

    09-11-’13 21:32

  1. @c0wfunk: you don’t need to set the output in LinuxSampler. You do need to make the necessary JACK connection from LinuxSampler to your audio out. And you can use the onboard audio with JACK, I just didn’t have a lot of luck getting it to work at lower latencies.

    Jeremy

    Jeremy

    10-11-’13 20:47

  1. @RalfD: good catch. UUOC. I’ll modify it in the script.

    Jeremy

    Jeremy

    10-11-’13 20:51

  1. Thanks for the response. Your efforts on this topic have been invaluable!!

    When you say: “You do need to make the necessary JACK connection from LinuxSampler to your audio out”

    Are you referring to this line of the script?
    jack_connect LinuxSampler:0 system:playback_1

    Or somewhere else I need to do this? Do I need to define system:playback_1 somehow?

    My goal is to connect a midi keyboard for the highest quality piano / organ / Rhodes / clav sounds I can find for a general rock n roll tonebank to use. With what you’ve seen am I dreaming or is this feasible?

    I may end up adding a new DAC to the system but I want to get it running simply first.

    I also have a tascam us-122l but I was unsure whether to try it because I had a lot of issues with it under windows vista (probably my problem right there). I’ll give it a shot this week

    c0wfunk

    c0wfunk

    11-11-’13 03:46

  1. I’m starting to wonder if I need jack at all After I read your statement on another thread:
    ASIO is a driver stack (like ALSA) and JACK is a sound daemon that allows multiple clients to output sound and MIDI simultaneously. JACK is more similar to a tool like ReWire.”

    In this case it seems I could just run linuxsampler with alsa?

    c0wfunk

    c0wfunk

    11-11-’13 03:55

  1. Hello c0wfunk,

    “Are you referring to this line of the script?
    jack_connect LinuxSampler:0 system:playback_1”

    Yes, the jack_connect command is used to set up the connections. But the port names for the onboard audio should be the same. Are you sure JACK is running and is using the onboard audio?

    “My goal is to connect a midi keyboard for the highest quality piano / organ / Rhodes / clav sounds I can find for a general rock n roll tonebank to use. With what you’ve seen am I dreaming or is this feasible?”

    I think it is. But not with the onboard audio. It can’t handle low-latency audio and its output is 11-bit audio. But there are some exciting developments going on, there are some people working on external audio boards that you can attach to the RPi. Hopefully these solutions allow low-latency high quality audio.

    Afaik the Tascam us-122l does not work on ARM based boards because of the firmware loader not working properly.

    And yes, you can run LinuxSampler directly with ALSA since it will be the only application locking the soundcard. Haven’t tried this myself with LinuxSampler but I did try with Hydrogen. Somehow I manage to achieve lower latencies when using JACK, especially when running JACK in ALSA softmode. This mode ignores ALSA buffer under/overruns (xruns) and JACK just simply chugs along handling audio without any glitches. When using ALSA directly those xruns will be audible.

    Jeremy

    Jeremy

    (URL)

    12-11-’13 20:53

  1. This is great info. I unfortunately found too that others are having issues with the tascam box. The thing is junk and was given to me by a friend replacing an maudio version of mine he had stolen on him.. Oh well, I’ll have to find another output. Thanks again I’ll have time to play with this some more later this week.

    c0wfunk

    c0wfunk

    13-11-’13 03:13

  1. This is starting to make me crazy! You asked “Are you sure JACK is running and is using the onboard audio?”

    Yeah, I’ve definitely been able to get Jack to run.. I’ve been going line by line through your piano script and also the lscp script to see where things are going bad. The command I’ve been able to get the most stable run from jack is this:

    jackd -P85 -p16 -t2000 -d alsa -d hw:2 -P -p 1024 -r 44100

    The -d “hw:2” I stumbled upon in a thread somewhere – my aplay -l output is “card 2: ALSA [bcm2835 ALSA], device 0: bcm2835 ALSA [bcm2835 ALSA]”

    I tried various iterations of specifying the bcm2835 but the hw:2 string is the only one I could get to work. So Jack runs, and I can get LinuxSampler to run and return OK for all of the lines of the lcsp script. When I run qjackctl, I see my connections, I’m able to connect my midi ports up, and everything seems OK. When I monitor the midi coming into linuxsampler, I see note on / off signals coming from the keyboard, so I know everything is good there. But I just don’t get any audio!

    I am able to play a wav file with aplay (filename) so I know I have good connections.

    I’ve started messing with adding jsample to see if I can get that to work and I may try some other midi software when I get a chance tomorrow. I’m at the end of my time today, but if you have any thoughts on what I may be missing, I’d love to hear! It has to be something simple I’m overlooking!

    c0wfunk

    c0wfunk

    15-11-’13 02:25

  1. Hello c0wfunk, try hw:ALSA as the ALSA soundcard name, this way ALSA will always pick that soundcard to use. It’s weird you don’t get any audio. Did you check the levels with alsamixer? And did you connect the JACK MIDI port of LinuxSampler to the MIDI port of your MIDI device? That’s what I used -Xseq for.

    Jeremy

    Jeremy

    (URL)

    15-11-’13 17:23

  1. Yeah – so weird. I did an update/upgrade on my packages and flashed the firmware today to make sure I wasn’t missing something new. I think my next move is going to be to reinstall Raspian and start from scratch with the latest version. I read somewhere that jack is now included in the Raspian install (?) and I installed a version so perhaps something has gone awry. I haven’t spent meaningful time in Linux since the early days of Red Hat (~1998 or so) so I’m really not sure how all of this works together. After spinning in circles, I think I’m ready for a blank slate.

    I have jsampler running now and today I walked through each line of the lcsp file again.. There is one thing I had to change from your file:

    The line “SET AUDIO_OUTPUT_CHANNEL_PARAMETER 0 0 JACK_BINDINGS=NONE” gives me this error:
    ERR:0:Jack: Cannot connect port ‘LinuxSampler:0’ to port ‘PCM:0’

    I am able to get the command to work with this value:
    SET AUDIO_OUTPUT_CHANNEL_PARAMETER 0 0 JACK_BINDINGS=‘system:playback_1’

    Perhaps this is causing something I don’t understand?

    So after I ran all of the commands, including loading the sample pack manually, I’ve got Fantasia up and my 2 midi devices are there as well as the jack audio device. The SalamanderGrandPiano is loaded, and when I press a key on my oxygen8, the fantasia keys light up. But still, no audio! I am expecting crackly, crappy audio, but so far, I get only silence. So very bizarre.

    I loaded alsamixer and made sure the level is all the way up. Your hw:ALSA trick worked as well, thanks. I went ahead and added the -Xseq to my jackd launch command. MIDI in is definitely working. The sample is loaded, the device seems to be there, but ..just..no..sound. I’m going to go leap off a building, thanks for your help! ;)

    c0wfunk

    c0wfunk

    15-11-’13 19:21

  1. Ya know – it’s not silence. I my headphones in the last time I ran through the script I noticed that when Jack launches there is a quiet but audible click as the driver is activated. Then when I reboot the pi, I hear it click off. So it seems jack is connecting to the alsa driver. I still feel like the disconnect is within the LinuxSampler setup. Can you think of another good application to use to test the jack driver output?

    c0wfunk

    c0wfunk

    15-11-’13 19:57

  1. You can try reinstalling but it probably won’t solve your issue. You could test the JACK output with aqualung for instance, a simple mediaplayer that has good JACK support. I wouldn’t be surprised if ALSA is continously having issues with buffering to the soundcard. I’ll have to test it myself, hopefully I get to it it this weekend. Great to know that Fantasia works! Is it usable?

    Jeremy

    Jeremy

    (URL)

    15-11-’13 20:31

  1. (sorry for spamming your page, hopefully more comments will get you more traffic :)
    One more piece to the puzzle..

    When I use
    jack_connect alsa_pcm:USB-Oxygen-8-v2/midi_capture_1 LinuxSampler:midi_in_0
    to connect my keyboard (similar to what you use above, just different hardware) this connection does not make the little keyboard in jsample to light up when the keys are pressed.

    When I use
    jack_connect alsa_pcm:USB-Oxygen-8-v2/midi_capture_1 alsa_pcm:LinuxSampler/midi_playback_1

    this makes the external keyboard trigger jsample’s keyboard.

    For both of these QjackCtl shows a connection made on the midi tab. I can also get the external keys to trigger the jsample keys by manually making a connection on the ALSA tab in QjackCtl between 20:USB Oxygen 8 v2 0:USB Oxygen 8 v2 MIDI 1 and 129:LinuxSampler 0:Port 0 . I haven’t figure out the syntax for making this connection via jack_connect commands.

    Either way though, I get no sound. Also I’m not sure why, but I can’t trigger the jsample keys with a mouse click, only from my ext keyboard when connected in one of the two ways above.

    So after a lot of circles, I still intuitively feel like the issue lies in a simple disconnect between linuxsampler and the jack outputs for some reason. Which has me looking at the CREATE AUDIO_OUTPUT_DEVICE JACK and following SET AUDIO_OUTPUT_CHANNEL_PARAMETER NAME & JACK_BINDINGS settings lines in the lscp script

    c0wfunk

    c0wfunk

    15-11-’13 20:41

  1. Fantasia “works” in that it loads my linuxsampler settings but it is super slow and pegs the CPU to 100% whenever trying to do anything. I was able to use it to setup but it was basically click – wait 10 seconds – click kind of work.

    I’ve read that the slow performance could be in the way I installed my java runtimes so I need to look at that as well. Right now, no it’s really not usable, except for as confirmation that my linuxsampler settings are being processed as expected.

    c0wfunk

    c0wfunk

    15-11-’13 20:43

  1. ‘You could test the JACK output with aqualung for instance’

    This installed and played a wav. It says Output: Jack @44100 Hz

    I’m looking at getting the Behringer UCG-102 for an easy 1/4” output.. Have you gotten yours working with this piano script?

    c0wfunk

    c0wfunk

    15-11-’13 20:52

  1. Fired up my RPi and I’m now running the script with the onboard soundcard. I can just hear the buffering issues. When I try a synth like amsynth there’s sound coming out but it sounds heavily distorted. So definitely a buffering issue.
    With the UCG-102 the script works well, just tested it.

    Jeremy

    Jeremy

    (URL)

    15-11-’13 21:15

  1. Ah, success with the onboard sound and using ALSA directly. Try this .lscp file:

    # Exported by: JSampler - a java front-end for LinuxSampler
    # Version: 0.9
    # Date: Sun Sep 22 22:10:55 CEST 2013

    RESET

    SET VOLUME 1.0

    CREATE MIDI_INPUT_DEVICE ALSA NAME='LinuxSampler'
    SET MIDI_INPUT_PORT_PARAMETER 0 0 NAME='Port 0'
    SET MIDI_INPUT_PORT_PARAMETER 0 0 ALSA_SEQ_BINDINGS=NONE

    CREATE AUDIO_OUTPUT_DEVICE ALSA ACTIVE=true CHANNELS=2 SAMPLERATE=44100 CARD='ALSA,0' FRAGMENTS=2 FRAGMENTSIZE=1024
    SET AUDIO_OUTPUT_CHANNEL_PARAMETER 0 0 NAME='Channel 0'
    SET AUDIO_OUTPUT_CHANNEL_PARAMETER 0 1 NAME='Channel 1'

    REMOVE MIDI_INSTRUMENT_MAP ALL

    ADD CHANNEL
    SET CHANNEL MIDI_INPUT_DEVICE 0 0
    SET CHANNEL MIDI_INPUT_PORT 0 0
    SET CHANNEL MIDI_INPUT_CHANNEL 0 0
    LOAD ENGINE SFZ 0
    SET CHANNEL VOLUME 0 1.0
    SET CHANNEL MIDI_INSTRUMENT_MAP 0 NONE
    SET CHANNEL AUDIO_OUTPUT_DEVICE 0 0
    LOAD INSTRUMENT NON_MODAL '/home/pi/LinuxSampler/SalamanderGrandPianoV2_44.1khz16bit/SalamanderGrandPianoV3.sfz' 0 0

    Sound quality is abysmal though but at least there is something coming out. You can connect your MIDI keyboard with the aconnect command. First check the client ID’s with aconnect -i -o and then connect with aconnect ID-of-MIDI-device ID-of-LinuxSampler

    Jeremy

    Jeremy

    (URL)

    15-11-’13 21:44

  1. Thanks for this .. we were at the last hour of a 24hour hackathon at work where i was working on this project and I switched gears and got Carla to work. My jack driver was playing my piano tones in less than a half an hour using Carla, albeit broken up and crappy sounding. I’ll try your new script this weekend. Thanks much for helping me work through this!

    c0wfunk

    c0wfunk

    16-11-’13 00:07

  1. You’re welcome! With Carla it’s possible too but I’m not surprised it sounds crappy. Running a GUI on the RPi consumes so much resources that loading the samples and sending them out via JACK just doesn’t happen in a timely fashion.

    Jeremy

    Jeremy

    (URL)

    16-11-’13 16:06

  1. Hi Jeremy,
    Fantastic post, thank you!
    Could you tell us the approximative number of simultaneous notes your RPi config can handle? Are you able to play piano tunes without restriction?

    julien

    julien

    18-11-’13 23:32

  1. Hello Julien, I think the polyphony is 5 or 6 notes at once. It’s less though when you use sustain. And you can play tunes without restriction but if it gets a bit too busy the audio will become choppy. The sound will recover eventually but it’s audible that something went wrong.

    Jeremy

    Jeremy

    (URL)

    19-11-’13 20:20

  1. Received my RPi yesterday; I’ll try to follow your steps this WE!
    Do you think using an external USB audio interface (i have fasttrack pro collecting dust in a drawer) instead of the internal audio chip would allow to increase the polyphony?

    Julien

    Julien

    22-11-’13 17:45

  1. Hi,
    I was able to run your script after some minor tweaks; saved me so much time, thank you man!
    It sounds really nice and there was no noticeable latency using my fast track pro usb soundcard.
    I tried to increase the polyphony using a high-speed sdcard (45Mo/s), a smaller piano sample (150Mo sf2 soundfount) and copying it to a ramdisk, but the gain was modest and couldn’t get past 7 simultaneous notes.
    So it’s a fun experiment and my daughter can now play the keyboard, but I can’t really use it to play a real piano song.

    Julien

    Julien

    25-11-’13 09:19

  1. Thanks for this article !

    Why does “sudo apt-get install linuxsampler” bring me this error :
    “E: Package ‘linuxsampler’ has no installation candidate”
    on my fresh-installed Raspbian ?

    About polyphony, what are the possible improvements in a near future in your opinion ?

    jo

    jo

    25-01-’14 14:27

  1. Hey , thanks for this great writeup and the repository..

    Just a note, i’m using the latest raspbian image (w. 3.12.22+ kernel) and when running the scripts that you have provided, Jackd1 will fail with a fatal error, because the kernel is no longer reporting a speed in the /proc/cpuinfo and jack doesn’t like that… I haven’t tried to see if Jack2 has this fixed in the current repositories.

    Alwyn

    Alwyn

    18-07-’14 12:56

  1. What’s more, those lines :
    while [ "$STATUS" != "100" ] do STATUS=$(echo "GET CHANNEL INFO 0" | netcat -q 3 localhost 8888 | grep INSTRUMENT_STATUS | cut -d " " -f 2 | tr -d '\r\n') echo "$STATUS" done
    Make the script wait forever – “$STATUS” containing a blank string.

    Benguch

    Benguch

    10-09-’14 12:04

  1. Sorry, problem with my first message : I have the same problem as Alwyn. Jack1 seems to have been fixed in the latest offical release (https://github.com/jackaudio/jack1), but compiling leads to a lot of errors.

    Thanks a lot anyway for that article, this is exactly what I was looking for.

    Benguch

    Benguch

    10-09-’14 12:07

  1. Hi Benguch, I’m really behind on all the current RPi developments and I don’t think I have any time looking into the issues you mention in a foreseeable future :( But once I do I’ll update the repository and this blog post.

    Jeremy

    Jeremy

    (URL)

    10-09-’14 12:31

  1. Thanks for your answer.
    Eventually the latest Jack2 from github compiles and works well, even with headless RPi, and lines above works well too now (I don’t why it’s related but anyway…).
    Anyway I have no sound (works with aplay), and my USB Keyboard as no item in jack_lsp… I’ll try to make it work.
    See you !

    Benguch

    Benguch

    12-09-’14 13:35

Leave a comment

(optional field)
(optional field)
Remember personal info?
Small print: All html tags except <b> and <i> will be removed from your comment. You can make links by just typing the url or mail-address.