The definitive MIDI controller | This is not rocket science

Side projects

So you think you need Bluetooth audio…

You know the feeling, there’s this little project itching in the back of your mind, and as you procrastinate upon it, you realize just one part is missing.

It needs Bluetooth. The audio kind. It should play music from your phone. But you really don’t want to delve into antenna design and protocols just now… And it should sound good. Like, really good. How to go about that?

For me, the answer was in my pocket! I had been using one of these TaoTronics audio dongles for a while and the sound quality is great. So maybe I could just figure out which chip it is using, get one, and embed one into my project?

It’s a very simple device though. You press the “play” button for a second or two, the power comes on. You long press the play button again and it powers off. There’s a volume control, a microphone, and the play button… USB charging, and a battery… No need to make it complicated.

I don’t want to do this the hard way. I don’t want to deal with another complex IC and crazy datasheets.

How about I just use the dongle itself, without any modifications? It does everything I need. I could just take the sound out of it with a cable, the way it’s supposed to be used. But I don’t want a separate dongle, really. And I don’t want to keep on charging the battery constantly. Maybe I could hide it, just put one of those directly into my project! The size is right…

But I don’t need a battery at all. I’m going to have a proper power supply. And I can do better than whatever headphone amp is in that thing. I don’t need the buttons either, if it’s always on.

Time to crack it open and see what’s inside! (After ordering a second one for continued personal use – these are lovely devices.)

Long story short, after a little bit of probing, I could figure out how the battery and power button are wired. When power comes on, the dongle starts blinking two leds. I could “press” the power button with a transistor, and probe those leds to detect when the chip is alive to let go of the “button”. It did not take much time at all to write a piece of code on an NXP KL02z to control the dongle. A simple state machine would do.

It turns out that the chip in there has a rather neat, high quality differential audio output. It was AC-coupled to the internal headphone amp, so I replaced that with my own preamp circuit+antialiasing filter (just in case.)

It’s a bit of a crude hack. I removed the battery and power it with a regulator with roughly the right voltage. The board is literally just soldered on. OK, the audio DC bypass caps are a bit exaggerated perhaps, but it adds to the sound.

But it does the trick, and it does it marvellously!

Mellotron on the Raspberry Pi

Mellotron is one of those curious instruments that are impossibly difficult and expensive to own, but so deceptively simple and expressive that when you get to play one, you can’t let go of it. So of course I want one.

Note: you will need an audio interface that works with Jack. This will define how playable your new instrument will be! You will also need a MIDI interface, such as the USBmidi2, but any Linux-compatible audio interface will do.


Step 0: Acquire the necessary parts

The purpose of this post is to demo the USBmidi2. So I have one of those for connecting a MIDI keyboard. It will let you plug in a laptop also.

For the audio I used an old Terratec audio interface that I was familiar with. You can use any audio interface that you can get Jack to work with. The Raspberry Pi’s internal headphone jack will also “work”, kind of, but it requires so long buffer sizes that it’s unusable.

The Mellotron sample bank is available on the LinuxSampler instrument page.

Step 1: Configure Jack

Sorry, this part I will not explain here in detail. I used jackd2 and qjackctl. I was able get a latency of 2.9 ms at 44.1khz (according to qjackctl)!

You have to make sure that your Pi is configured to output audio at the minimum possible latency with minimum glitches, before you continue.

For testing Jack, I simply played some mp3s with mplayer -ao jack [song.mp3]

Step 2: Acquire LinuxSampler sources

LinuxSampler is available in the official SVN repository. See the LinuxSampler download page for details.

I had to install a few dependencies first (I already had a g++ installed):

sudo apt-get install subversion bison flex libtool automake autoconf intltool libsqlite3-dev patch

Then download the sources:

mkdir linuxsampler-src
cd linuxsampler-src
svn co libsf2
svn co libgig
svn co liblscp
svn co linuxsampler

Step 3: Build the support libraries

Build libsf2, libgig, and liblscp in that order.

To build each, run these commands:

automake --add-missing
./configure --prefix=/usr
make -j4
sudo make install

Some of them may require some variation or some commands were unnecessary; I will make better notes if I have to do this from scratch. Make sure the make and make install steps finish completely before continuing to the next.

Step 4: Patch LinuxSampler sources for the Raspberry Pi

LinuxSampler does not support the ARM CPU of the Raspberry Pi out of the box. Luckily someone has already fixed this, and the necessary patches are available here. You need both the RTMath.cpp patch, and also the attached atomic.h.diff patch. Or you can just grab them from my site.

Apply the patches:

cd src/common/
patch < ~/RTMath.cpp.diff patch -p2 < ~/atomic.h.diff cd ../..

Step 5: Build LinuxSampler

There are a few programs in linuxsampler/scripts/ that you have to run first, before LinuxSampler is ready to compile. I ran them all on order:

cd scripts

Those perl scripts required XML::Parser to run, but I think that installing ‘intltool’ adds the necessary dependencies. If not, make sure to see “Installing packages system-wide” before going on installing all the Perl libraries with cpan.

Step 6: Build LinuxSampler

This will take some time if you do it on the Pi, and it will require several hundred megabytes of disk space.

The same commands work as before, but configure required some help:

automake --add-missing

CFLAGS="-I/usr/include/sf2 -I/usr/include/libgig" CPPFLAGS="-I/usr/include/sf2 -I/usr/include/libgig" ./configure --prefix=/usr

make -j4
sudo make install

You should now be able to run ‘linuxsampler’ in a shell on the Pi.

Step 7, optional: Install qsampler on a PC

LinuxSampler allows the GUI to run remotely. You can build qsampler to run on a more powerful computer, and connect to the Pi with it. The sources are in the same subversion repository.

Step 8: Install the sample bank and configure LinuxSampler

Extract the TaijiguyGigaTron.tar.bz2 from the LinuxSampler instrument page on the Pi. If you use qsampler remotely, the .gig file must be at the exact same path on both the Pi and your remote controller host.

I ran out of disk space at this point. Running “make clean” in the linuxsampler source tree will make you some room. I was able to fit everything on a 4 GB disk by removing a bunch of unnecessary locales from /usr/share/locale. My Raspbian also came with a rather large General Midi sound bank in /usr/share/, see if you can find it! (OK, I’m assuming it was General Midi, I deleted it before listening to it.)

Now you have to create a LSCP (LinuxSampler Control Protocol) script that initializes your hardware and loads the Mellotron sample bank. I did it like this:

  • Start linuxsampler on Pi
  • Start qsampler on PC
  • In qsampler:
    • Disable local server
    • Connect to “raspberrypi”
    • Add ports for your audio and MIDI hardware
    • Add a channel with TaijiguyGigaTron_switched.gig
    • Make sure the green “led” in qsampler blinks when you play notes – if not, check your MIDI connections!
    • Make sure sound comes out when the green “led” blinks – if not, check your audio connectiosn!
    • Save settings to LSCP file, I called mine “TaijiguyGigaTron.lscp”

Then copy the LSCP file to your Pi. My example LSCP file is available for download here, but I’m sure that you will have to modify it to work with your choice of hardware.

Step 9: Set up LinuxSampler to start without remote control

There’s a nice trick to load the LSCP file from the previous step on the Pi.

First run LinuxSampler in one shell on the Pi:


When it says “initialization completed”, send the LSCP file to it in a second shell:

cat TaijiguyGigaTron.lscp | netcat localhost 8888

If you didn’t change anything else since Step 7, you should now be able to play notes with the Mellotron patch.

Step 10: Wrapping it up in a script

To prepare for starting everything in one go, I wrote a simple script that kicks off Jack and LinuxSampler. OK, it’s dirty with those sleeps and all, but works pretty well for a quick hack.

I have this in /home/pi/, you have to replace the jackd command line with whatever your hardware needs:

daemon -e "DISPLAY=:0.0" -- /usr/bin/jackd -P10 -dalsa -dhw:USB2448 -r44100 -p64 -n2 -Xseq -P
sleep 1
daemon -- linuxsampler
sleep 1
cat /home/pi/TaijiguyGigaTron.lscp | netcat localhost 8888

Debugging it is easy; you can add the -f parameter to daemon to run the programs in a terminal. That allows you to directly see the jack error messages. And when you get each step to run properly, just update the parameters in the script and continue with the next.

Step 11: Running Jack and LinuxSampler on startup

I found it easiest to add my script to the LXDE autostart scripts. I had two directories in /etc/xdg/lxsession/, and I’m not sure why, so I added it in both:

sudo nano /etc/xdg/lxsession/LXDE/autostart
# add on new line at end of file: /home/pi/

sudo nano /etc/xdg/lxsession/LXDE-pi/autostart
# add on new line at end of file: /home/pi/

Save everything, test it a few times, reboot, and you’re ready to rok!