How to Make a MIDI Controller with an Arduino

As a musician who has amassed a collection of musical instruments and noise boxes, the humble Arduino is the perfect tool to create a custom MIDI controller. Whilst the Raspberry Pi may have taken the crown for Internet of Things (IoT) projects, a simple Arduino Uno (what are the different types of Arduino?) has more than enough power for this project.

First time using an Arduino? No worries, we’ve got a complete Arduino beginner’s guide to read through before you tackle this project. 

Arduino-Midi-Controller-Breadboard

What is MIDI?

MIDI stands for Musical Instrument Digital Interface. It outlines a standard way for musical devices to communicate with each other. If you own an electronic keyboard you probably have a MIDI interface. Whilst there are a few technical details involved in the implementation of MIDI, it’s important to remember that MIDI is not audio! MIDI data is a simple set of instructions (one instruction is called a “message”) that another device may implement to make different sounds or control parameters.

MIDI supports 16 channels. This means that each cable can support 16 different devices communicating independently with each other. Devices are connected using a 5-pin DIN cable. DIN stands for “German Institute for Standardization”, and is simply a cable with five pins inside the connector. USB is often used in place of 5-pin DIN, or a USB-MIDI interface can be used.

MIDI-Cable-Male

Control Change and Program Change

There are two main types of MIDI message: Control Change, and Program Change.

Control Change (CC) messages contain a controller number and a value between 0 and 127. CC messages are often used to change settings such as volume or pitch. Devices that accept MIDI should come with a manual explaining what channels and messages are setup by default, and how to change them (known as MIDI mapping).

Program Change (PC) messages are simpler than CC messages. PC messages consist of a single number, and are used to change the preset or patch on a device. PC messages are sometimes known as “Patch Change”. Similar to CC messages, manufacturers should provide a document outlining what presets are changed by a particular message.

What You Will Need

  • Arduino
  • 5-pin DIN female socket
  • 2 x 220 ohm resistors
  • 2 x 10k ohm resistors
  • 2 x momentary switches
  • Hook-up wires
  • Breadboard
  • MIDI cable
  • MIDI device or USB interface

Build Plan

This project will be quite simple. You can of course add more buttons or hardware to suit your needs. Almost any Arduino will be suitable — only three pins are needed for this example. This project consists of two buttons to control the program, a MIDI port to send the data, and a device to receive the messages. This circuit has been built on a breadboard here, however it is possible to transfer it to a project box and soldered connectors for a robust solution.

Circuit Assembly

Arduino-Midi-Controller-Circuit

MIDI Connection

MIDI-Pinout

Wire up your MIDI socket as follows:

  • MIDI pin 5 to Arduino Transmit (TX) 1 via a 220 ohm resistor
  • MIDI pin 4 to Arduino +5V via a 220 ohm resistor
  • MIDI pin 2 to Arduino ground

Button Connection

The buttons work by changing the resistance the Arduino “sees”. The Arduino pin goes through the switch straight to ground (LOW) via a 10k ohm resistor (a “pull down” resistor, ensuring the value stays low). When the button is pressed, the value seen by the circuit changes to +5v without a resistor (HIGH). The Arduino can detect this change using the digitalRead(pin) command. Connect the buttons to pins 6 and 7 on the Arduino digital input/output (I/O). Connect both buttons:

  • Left side of button to +5V
  • Right side of button to Arduino Ground via a 10k ohm resistor
  • Right side of button to Arduino pin (6 or 7)

MIDI Testing

Now that all the hardware is finished, it’s time to test it. You will need a USB-MIDI interface (many audio interfaces can do this) and a MIDI cable. The MIDI port wired up on the breadboard is sending data, so it is the output. Your computer is receiving the data, therefore it is the input. This project uses the excellent Arduino MIDI Library v4.2 by Forty Seven Effects. Once you have installed the Library, you can include it in your code by going to Sketch > Include Library > MIDI.

You’ll also need a program to monitor the incoming MIDI data:

  • MIDI Monitor for OS X
  • MIDI-OX for Windows
  • KMidimon for Linux

Connect the Arduino to your computer and upload the following test code (don’t forget to select the correct board and port from the Tools > Board and Tools > Port menus).

#include <midi.h>  #include <midi_defs.h>  #include <midi_message.h>  #include <midi_namespace.h>  #include <midi_settings.h>    MIDI_CREATE_INSTANCE(HardwareSerial,Serial, midiOut); // create a MIDI object called midiOut    void setup() {    Serial.begin(31250); // setup serial for MIDI  }    void loop() {    midiOut.sendControlChange(56,127,1); // send a MIDI CC -- 56 = note, 127 = velocity, 1 = channel    delay(1000);  // wait 1 second    midiOut.sendProgramChange(12,1); // send a MIDI PC -- 12 = value, 1 = channel    delay(1000);  // wait 1 second  }

This code will send a CC message, wait 1 second, send a PC message then wait 1 second indefinitely. If everything is working correctly you should see a message appear in your MIDI monitor.

If nothing happens, don’t panic! Try troubleshooting:

  • Ensure all the connections are correct
  • Check the MIDI port is wired correctly – there should be 2 spare pins on the outside edges
  • Double-check the circuit is correct
  • Verify the circuit is connected to a USB-MIDI interface with a MIDI cable
  • Check your MIDI cable is connected to the input on your USB-MIDI interface
  • Make sure the Arduino has power
  • Install the correct driver for your USB-MIDI interface

If you are still having problems it might be worth checking your breadboard. Cheap boards can sometimes be very inconsistent and low-quality — it happened to me whilst working on this project.

Button Testing

Now it’s time to test the buttons are working correctly. Upload the following test code. MIDI does not need to be connected to test this part.

const int buttonOne = 6; // assign button pin to variable  const int buttonTwo = 7; // assign button pin to variable    void setup() {    Serial.begin(9600); // setup serial for text    pinMode(buttonOne,INPUT); // setup button as input    pinMode(buttonTwo,INPUT); // setup button as input  }    void loop() {        if(digitalRead(buttonOne) == HIGH) { // check button state      delay(10); // software de-bounce      if(digitalRead(buttonOne) == HIGH) { // check button state again        Serial.println("Button One Works!"); // log result        delay(250);       }    }        if(digitalRead(buttonTwo) == HIGH) { // check button state      delay(10); // software de-bounce      if(digitalRead(buttonTwo) == HIGH) { // check button state again        Serial.println("Button Two Works!"); // log result        delay(250);      }    }      }  

Run this code (but keep the USB cable connected) and open the Serial Monitor (Top Right > Serial Monitor). When you press a button you should see “Button One Works!” or “Button Two Works!” depending on the button you pressed.

There is one important note to take-away from this example – the software de-bounce. This is a simple 10 millisecond (ms) delay between checking the button and then checking the button again. This increases the accuracy of the button press and helps prevent noise triggering the Arduino. You do not have to do this, although it is recommended.

Creating the Controller

Now that everything is wired and working, it’s time to assemble the full controller.

This example will send a different CC message for each button that is pressed. I’m using this to control Ableton Live 9.6 on OS X. The code is similar to both the testing samples above.

#include <MIDI.h>  #include <midi_Defs.h>  #include <midi_Message.h>  #include <midi_Namespace.h>  #include <midi_Settings.h>    const int buttonOne = 6; // assign button pin to variable  const int buttonTwo = 7; // assign button pin to variable    MIDI_CREATE_INSTANCE(HardwareSerial,Serial, midiOut); // create a MIDI object called midiOut    void setup() {    pinMode(buttonOne,INPUT); // setup button as input    pinMode(buttonTwo,INPUT); // setup button as input    Serial.begin(31250); // setup MIDI output  }    void loop() {    if(digitalRead(buttonOne) == HIGH) { // check button state      delay(10); // software de-bounce      if(digitalRead(buttonOne) == HIGH) { // check button state again        midiOut.sendControlChange(56,127,1); // send a MIDI CC -- 56 = note, 127 = velocity, 1 = channel        delay(250);       }    }       if(digitalRead(buttonTwo) == HIGH) { // check button state      delay(10); // software de-bounce      if(digitalRead(buttonTwo) == HIGH) { // check button state again        midiOut.sendControlChange(42,127,1); // send a MIDI CC -- 42 = note, 127 = velocity, 1 = channel        delay(250);      }    }  }  

Note — you will not be able to use Serial.println() with MIDI output.
If you wanted to send a PC message instead of a CC simply replace:

midiOut.sendControlChange(42,127,1);

With:

midiOut.sendProgramChange(value, channel);  

In Action

Below is a demonstration as a controller for Ableton Live (Best DJ software for every budget). The top right shows the audio meters, and the top middle shows the incoming midi messages (via MIDI Monitor on OS X).

Have you Made a MIDI Controller?

There are a lot of practical uses for a custom MIDI controller. You could build a vast foot-controlled unit, or a sleek studio controller. Have you made a custom MIDI controller? Let me know in the comments, I’d love to see them!

Image Credit: Keith Gentry via Shutterstock.com

Leave a Reply

Your email address will not be published. Required fields are marked *