The definitive MIDI controller

What is RPC?

The Raspberry Pi Controller is intended to be a stand-alone MIDI sequencer workstation, made with open-source software and DIY electronic components. It is built around a Raspberry Pi board delivering a solid user interface. The I/O connections are served by an Arduino feeding directly to four MIDI inputs and outputs, guaranteeing accurate timing.

The name pays homage to the venerable Akai MPC series, but this is going to be a whole new kind of beast.

If this project is of interest to you, or if you would be interested in having your own little RPC (DIY, kit or pre-built, doesn’t matter) please drop me an email, tell me what you want to see me accomplish, and I will add you to the news email list. You’ll be the first to hear of updates, and I will be aware if someone actually wants one! No spam.

The protosynth

The DSP synthesizer project has taken most of my attention lately, with the RPC making steady progress on the background. The unique synthesis algorithms of the synth will make it a beast of a companion for the RPC.

Recent posts

It’s alive!

The box for the protosynth is finally complete. See the previous posts for details. The paint is still not entirely finished and could use some final touch-up, but it’s good enough for now. First pics!

Sumutor-1 ready to rok

Sumutor-1 ready to rok

All the hardware is in there and, most importantly, it all seems to work. All knobs and buttons register, leds light, and although there is no real gui, you can tap on the mock buttons and they register. Headphone output works, but I’m not sure yet if the voltage levels are right or if it’s clipping. All the parts of the synth work just as before.

The picture is taken at such an angle that the display looks empty. No, it works just fine. The led segment displays will get covered later, I still have to find some nice red film to put on top of them.

Sumutor-1 with its fleshy belly open

Sumutor-1 with its fleshy belly open

All the internals are in place. In the cover: thumbstick, big buttons and the headphone amplifier on the left, with the main UI panel and the touch TFT screen with its SD card slot taking the rest of the space. On the bottom: the synth on the left has grown itself an opamp attachment and a couple of admittedly ugly connectors, the USB+MIDI interface in the middle, and power supply board and the power connector and switch on the right. Oops, I forgot to remove the jtag cables for the photo shoot.

I’ll take some fancier shots and soundclips later (see the previous posts though!). There’s still much to do on the software side.

KL26ZxxxVFM4 pinout

The KL26Z feels overall like a very nice MCU; the collection of features and the pin mapping that it provides works very well for me. The chip does USB natively, it has three serial ports, two SPI, two I2C, I2S, plenty of ADCs and a DAC… the evaluation board is a scam, but can be converted into a cheap debugger with USBDM. And Erich Styger has made some really impressive work writing Processor Expert modules that also work with this chip. And the chip itself is tiny. I think I’ve found my new favorite microcontroller.

The datasheet and manuals are a mess. So I combined the pin layout, spread over three pages, on a single printable page. Click the picture below for a print-size version.

KL26ZxxxVFM4 Cheatsheet

On USB latency

Every so often someone mentions the dreaded USB latency. MIDI is MIDI, and USB is USB, do we need to mix both, and can that work reliably?

So let’s say we want to provide a Raspberry Pi with some USB MIDI connectivity, and run a software synth to produce sound. Since you would need some kind of a MIDI-to-USB conversion box in between, that must inherently produce some kind of sluggishness. Right?

Even worse, let’s run a sequencer on the Raspberry Pi, so that it must receive MIDI notes and knob twists played on a keyboard, and as a response send them to some other synthesizer to produce sound. That must be twice as bad, as the MIDI notes go once through the USB conversion to the Pi, and a second time back.

USB MIDI latency diagram

So how bad is that then? We can measure it!

The Arduino works fine as a simple MIDI device. Its serial ports can be easily configured for the 31250 bps bitrate needed by MIDI, and you only need a few extra components for interfacing with other MIDI devices. It’s not too difficult to program the Arduino to first send some MIDI commands to the Pi, and then make it wait for a reply, and at the same time measure the time that transaction takes to finish.

MIDI latency measurement setup

It’s an Arduino Mega 2560 under the Ethernet shield there! This is a good moment to reuse those MIDI boards from before… Here is the schematic of the MIDI interface electronics. Click for a larger picture.

MIDI UART schematic

Use only 4N28 optocouplers or similar with this circuit! 6N138 and PC-900 require a different schematic.

The MIDI0_RXD and MIDI0_TXD wires can be directly connected to the Arduino. The separate driver IC (74AC04 hex inverter suggested here) is not absolutely necessary, so those parts of the schematic are faded out. VCC for this schematic is 3.3V, and for 5V from a standard Arduino you only need to replace the two 56 ohm resistors with 220 ohm instead. If you look carefully, you can see the resistor values in the picture below.

The interface is very simple, and the MIDI interface boards I made earlier look empty with just the mandatory components populated… I soldered wires from the Arduino UART directly to the bottom of the board, on the pins of the through-hole components.


The program for the Arduino goes something like this. I left the timer functions out, get the whole source file instead!

bool measuring = false;

void setup() {
  // initialize UARTs
  // Arduino serial monitor
  // MIDI in/out

void loop() {
  if (!measuring) {
    // not measuring yet, go!
    measuring = true;
    // start sending a MIDI CLOCK byte
    char c = 0xF8;
  else {
    if (timer_overflow()) {
      // no reply before timer overflowed
      measuring = false;

void printTime(long time)
  // convert timer count to 0.1 milliseconds
  time = time * 10000 / timer_ticks_per_sec;
  Serial.print(time / 10);
  Serial.print(time % 10);

void serialEvent1() {
  // if measurement was started, finish and report time
  if (measuring) {
    long endtime = timer_count();
    measuring = false;
  // flush all input
  while (Serial1.available()) {;

In short, the program tries to send one-byte MIDI clock commands through the MIDI out, waits for a reply, and prints the time in milliseconds from starting of the output to the end of the reception of the reply. It doesn’t care about whether it gets the correct data back… You’re welcome to add that part yourself for practice. :-)

First test should always be to connect the latency tester to itself in loopback, with a single MIDI cable, from output to input. This way I measured about 0.4 milliseconds round-trip time, sometimes 0.3. The MIDI bitrate is 31250 bits per second, and a single transmitted byte includes one start bit and one stop bit, 10 bits total. A single MIDI output port can therefore transmit 31250/10 = 3125 bytes per second, or 1/3125 = 0.0032 seconds = 3.2 milliseconds per byte. Hey, that matches what we measured, the program always sends just one byte at a time! Looking good. And unplugging the cable gives the message “timeout” as expected.

The Edirol MIDI interface I used here has a OUT/THRU switch for each of its inputs, allowing direct output of whatever it received on the input. With the switch engaged, I also measured 0.4 ms round-trip time. So the switch probably just connects the input port directly electrically to the output port.

Now it gets more interesting. With the USB MIDI interface plugged in and configured for both input and output, I start JACK on the Pi, using just the internal audio device since I don’t really care about the audio side for this experiment. Then in Patchage I just hooked the MIDI input directly to the MIDI output, in a loopback configuration. The MIDI commands from the Arduino will be received by the Linux software, the Jack2 daemon specifically, and sent back out as quickly as possible.


The result: 1.4 ms round-trip time! Since it takes 0.32 ms to transmit a byte, and that must happen in order (first in, then out) the overhead of the data passing through USB drivers, the Linux kernel, and the userspace software is 1.4 – 2*0.32 = 0.76 milliseconds. Not bad! An ideal hardware sequencer could only react 0.76 milliseconds faster than the Pi. There is some variance in the results, sometimes it takes 2.0 to 2.3 ms to get a reply. Maybe it would be a good idea to add some kind of average measurement to the program.

The software running on the Pi would of course have to process the input it receives, and prepare the output, but an optimized program should not add much overhead on top of these measurements. For reference, I got the same 1.4 ms minimum latency with the exact same setup on my much more powerful desktop Linux PC, but overall the measured time varied much more, often peaking around 5 ms probably due to Firefox and other programs running on the background.

But any Ethernet traffic or disk I/O immediately degrades the performance on the Raspberry Pi. Connecting to the Pi remotely with SSH and running some simple “ls” and “cd” commands immediately causes the round-trip times to jump up to 10 ms. That’s bad! A real-time kernel might help with the disk I/O, that could be worth investigating further. This page on the Linux-Sound wiki gives another clue: the Ethernet controller is connected to the CPU core over USB. Any Ethernet traffic may steal some bandwidth from all other USB communication. In the end it’s probably easier to just disable all unnecessary peripherals, as instructed on the Linux-Sound wiki.

Still the result is very reassuring: if the Pi is able to respond to MIDI in less than 2 milliseconds, it should be perfectly capable of using standard USB MIDI devices while running some sequencer software.

Next time I’ll measure the round-trip time of the RPC for comparison…

Audio analyzer enclosure design

This was where I really started the project. It’s also the most fun part. :-)

The front panel: what you see is what you interact with

The first sketch of the front panel already gave a good idea of what I had thought the analyzer should do.

THD analyzer front panel, first sketch

The audio XLR and TRS connectors for plugging in the device-under-test would be on the front-left, since those need to be easily accessible. There also has to be an “auto” button to measure everything in one go. (What exactly should that do, you ask? Details… to be decided later on. ;-)

The box will get an IP address, so some menus are for sure necessary to at least read the status and perhaps configure the Ethernet link. One button for that.

Most of the controls will be for the signal generator, as it will be hugely convenient to be able to dial in a specific setting and then debug the device receiving the signal. The analyzer is synchronized with the generator and is therefore quite automatic. The signal generator’s output is most likely going to be just a sine wave, so level and a frequency controls are in order, and sufficient. A frequency dial alone can be inconvenient for scrolling a long way, so two buttons next to it for going up and down whole octaves at a time will make it more accessible.

The signal generator’s output level setting should be straight-forward: decibels relative to some reference level. It just happens that there are a few different ways to define the reference level. There are at least two different yet common scales used for defining signal levels, the dBu standard and the dBV standard. dBu is used in “professional” gear, where signal levels are overall hotter to make use of the extra dynamic range afforded by it, and also because such devices have higher voltage power rails and therefore more headroom to work with. dBV on the other hand is used for cheaper devices that may even be battery-powered. The whole business of such reference level smells a bit old-fashioned, but since these are still commonly used, it should be possible to switch between them. I also found a handy web tool for converting signel levels from one scale to another.

It could also be very handy to be able to set a different custom level as the reference and measure everything relative to that; even better if you could use the current input level as measured by the analyzer as the reference, and it should only take a single button press to do it. Some way to quickly skip through common preset levels is also needed, for the same reasons as the frequency control needs buttons, and that gives the third button for the level controls.

On the right-hand of the panel is a rocker power switch on the bottom, and a wide-levered output enable switch in the same style as on the constant current loads I built earlier (and now I realized that I forgot to write a post about those.)

At this point I still had an empty spot on the panel, and could only think of spending the space for two less critical switches: a balanced/unbalanced I/O button and a bandwidth limit control. The idea with the bandwidth limit switch was to force the analyzer to use the lower 48 kHz sampling rate, with higher dynamic range and improved THD. To measure the distortion of >5 kHz signals it would still be necessary to enable the 96 kHz or 192 kHz sampling rates, but it could be useful to disable such automatic reconfigurations.

The balanced/unbalanced switch takes care of the level adjustments needed with the two different interconnects: simply grounding or muting one side of a balanced cable would reduce the signal level by half, causing a significant measurement error! This can be automatically compensated for by switching the analyzer to unbalanced mode.

At this stage I was sure enough of the practicality of the project, that I designed the PCBs and ordered and built them. I will write more about those in later posts. After verifying the general concept in hardware, it was time to decide on the final design.

Making it tangible

Again I went for Protocase to manufacture the enclosure, just because of the simplicity of their own cad design tool and the handy templates. With a little bit of good advice from Sebastian (check out his site for some really cool art!) I hacked together a more realistic design. The most important tip I got from Sebastian was: keep it simple. Even very simplified designs look awesome when they’re made into tangible objects. Typography should be simple but elegant (heh, maybe that’s still not my cup of tea) and emphasis should be on legibility and usability. So I kept it minimal.

THD analyzer 3D model

Colors are hard; somehow I have no intuition of which colors or tones work well together, but I knew the LCD screen would be blue, and inverse colors often work well together. But should it be orange, or should it be yellow, light or dark, saturated or not… choices, choices!

This is also where the projects gets expensive – it’s much cheaper to make your own boxes out of wood or plexiglas, but these enclosures are really high quality and have a seriously professional feel! Even better, they’re very low-effort if your wallet can take the hit.

But when the postman arrives, it’s like Christmas all over again ;-)

Analyzer delivery!

That is definitely not the end of the process, but since you read it all the way here, have a treat. I really like it how the whole design turned out!

Final THD analyzer

I think I spent weeks just selecting the right components for the front panel. Connectors were easy, I’m used to Neutrik jacks. Likewise the LCD display is a common part, it pays off to keep a good supply of those, and the prices are very acceptable when buying in bulk.

I must have pored over tens of shops just looking for knobs. It was so difficult to find good ones that we even considered making our own molds with Stijn. I don’t think I’m quite ready for that yet, but it would definitely be an option for larger production runs. Those that I used on the Protosynth I found first at Conrad, and later in different sizes at Das Musikding. The bigger sizes felt just right for this project. I covered them thoroughly with Plasti Dip, also to improve the plasticy feel of the plain knobs. The rubber paint gives them a very nice grip. The encoders are not both the same; I envisioned that the level knob would also be used to make a selection in the menus, so it should have a good stepped feel. After trying a bunch of different ones, I decided to go for Alps. The frequency dial is a smooth encoder from TT Electronics, and it requires medium force to turn, so that precise frequency adjustment is easy.

The buttons are Marquardt 6450-series from Mouser. I think Clavia also uses them in their synthesizers. The leds next to them are just 0603 SMD leds placed directly on the PCB behind the front panel, but I found out that Toby has a good selection of light pipes in practical sizes, and got a bunch of those. The light pipes carry the light so that it looks like the light is emitted from them, and they are also flush with the panel. This way the front panel PCB can be inserted in place very quickly without having to worry about the placement or spacers of the LEDs. The light pipes are short enough to stay in place by just pushing them through the panel.

On the back of the enclosure there’s just an Ethernet jack, USB jack (I still don’t know what to use it for – USB audio? In mono? Not very useful…) and a power jack. I also added a MIDI jack but it’s also an option for later use.

Inside the THD analyzer enclosure

The insides of the enclosure are spiked with standoffs for attaching the PCBs. Sadly here Protocase made a small mistake and left out two standoffs on the front panel. I had to replace them with screws and spacers. Pity for the screws are now visible on the outside… I also still have to find some black self tapping screws for the XLR connectors.

The rubber feet keep the box steady on the desk when buttons are pressed, and even when the small but sturdy power switch is operated. The box is made of just two parts, the base and the cover, and the base is very thick and heavy; it’s 2.3 mm thick steel! The box is too heavy to lug around, but it feels very robust and reliable, which is definitely a plus.