I’ve been messing around with MIDI for my musical floppy drive project, and it was surprisingly difficult to find detailed information on how to get started with Arduino’s MIDI library. So in this post I’m going to show you, in detail, how to use this library to control anything on an Arduino using MIDI.

What is MIDI?

MIDI, an acronym for Musical Instrument Digital Interface, is a protocol and interface standard designed to allow musical instruments and computers to connect and communicate with each-other. It’s widely used in the music world, for everything from digital audio workstations (DAWs) to musical keyboards. See the Wikipedia article for more information on the standard.

How do you use it?

The two most basic MIDI messages are “note on” and “note off” messages, that either start or stop a musical note. These messages have three parts:

  1. Channel: A channel between 1 – 16 that the note is played on. You can think of these as “tracks” for different instruments. Notes can be on any channel, although channel 10 is usually reserved for percussion.
  2. Note: The note being played, from 0 – 127 where 60 is middle C. Each increment is a semitone.
  3. Velocity: The speed at which the note is played, from 0 – 127. Think of it as the difference between hitting a piano key very quickly (high velocity) vs slowly pressing it until it plays the note (low velocity).

There are also a number of other messages, such as pitch bends and continuous controllers, that give you more control over how the instrument plays music (or, in this case, anything!).

So why is this useful with Arduinos?

The obvious reason is that you might be trying to make a musical instrument of some sort – a keyboard, a synthesizer, or something completely unique. But because you can use MIDI to control practically anything, there are some other reasons that may not be so obvious.

Timing Control

MIDI is designed for music, which means it is fundamentally intertwined with time. This means you can build a MIDI track on your computer and use it to control exactly when events will happen on a microcontroller without worrying about tedious (and much more permanent) delay timing.

You can also link many devices together with MIDI, and keep them all in sync with each-other while performing tasks.

MIDI Controllers

These days you can buy all sorts of MIDI controllers, from large digital keyboards to control boards and sample pads. These devices provide you with a whole host of polished physical controls for your devices that can be remapped, interlinked, and activated remotely.

Universal Support

If you need a remote control protocol for anything, MIDI might be a tempting candidate because it is so widely supported. Anything that uses an on/off switch or a potentiometer can be set up for MIDI control with just a few lines of code.

Instead of designing your own custom protocol, it may be easier just to adapt MIDI for your needs.

Getting Started

To do this you’ll need an Arduino of some sort – it doesn’t need to be a model with native USB support (e.g. Leonardo, Pro Micro), although it certainly doesn’t hurt.

The first thing you’ll need to do is to download the Arduino MIDI library by FortySevenEffects, which you can find here. You can also download it in the Arduino IDE by going to the library manager and searching for “MIDI”. Download the ZIP file and extract the contents into your Arduino ‘libraries’ folder.

Note: You don’t need to use the Arduino MIDI library to work with MIDI Messages, although it certainly does make things easier. If you’re writing your own MIDI code, I highly recommend this tutorial on the protocol.

Creating the MIDI Instance

Before we can do anything with MIDI, we need to create a MIDI instance so the Arduino knows where and how to get its MIDI data.

This can be as easy as this one line of code:

This will build the typical MIDI instance usually used on your Arduino board. If you want to customize the parameters, you have a two options:


  • Type is either “HardwareSerial” or “SoftwareSerial” depending on the port type.
  • SerialPort is the name of the serial port from the Arduino’s Serial class
  • Name is the name of the MIDI port you’re creating. This can be anything you’d like.
  • Settings is a custom struct from the MIDI library that contains the settings for a few custom parameters including baud rate.

To change the “settings”, you need to create your own struct:

Any values you put in this struct will overwrite the defaults. If you omit any, the struct will use the default values from the library.

Here are a few instance examples:

For more information on instance creation, look at the source files for the MIDI definitions and MIDI settings in the library’s repository.

Adding Handler Functions

Once your instance is created, the next step is to link some handler functions. The MIDI library works by calling a function pointer when it finds a matching MIDI packet. Here is a list of the available handlers:

You configure these in the setup function, like so:

You can name these functions whatever you’d like, although keeping descriptive names will make your code more readable. The library automatically populates the function parameters with the data it receives for each respective message.

At the end of the setup function you also need to call begin() before the library will start reading the incoming MIDI messages. begin() takes one parameter, which is the MIDI channel to listen to. You can use MIDI_CHANNEL_OMNI to listen to all channels at once. If you don’t provide a parameter it listens to channel 1 only.

Read MIDI Messages

The last and crucial step is to make sure you’re calling the library’s read function to parse any incoming MIDI data. Incoming data will be handled by the respective handler functions, but if you don’t call read the library won’t receive any data to process.

Write Your Code!

With the instance created and the handlers in place, now you can write your code to be controlled by MIDI!

A Demonstration: MIDI Visualizer

To demonstrate, I’m going to write the code for a basic MIDI visualizer that uses my favorite WS2812B addressable LEDs. The goal is to have LEDs on the strip correspond to different notes on the keyboard so they light up when a key is pressed, and turn off when the key is released.

To make it slightly more interesting, we can map some continuous controllers to change the colors on the fly.

Custom Instance

This visualizer is going to use an Arduino Uno, which doesn’t have native USB support. To get around this I’m going to use the Hairless MIDI to Serial Bridge to convert the MIDI messages into generic serial messages. You can see this post for more information.

For Hairless we’re going to change the Arduino’s baud rate from 31250 to 115200, which requires a custom MIDI instance:

Adding Handlers

This visualizer makes use of three MIDI messages: note on, note off, and continuous controller:

The “note on” and “note off” functions will mirror each-other: we’re going to check if the note is in the range we can play, set the LED color, and then refresh the LED strip.

To control this visualizer I’m going to use a Novation Launchkey Mk II, which is a class compliant MIDI controller and has 8 rotary potentiometers that act as continuous controllers. These potentiometers are mapped to MIDI controller numbers 21 through 28, respectively.

I’m going to use the first three potentiometers to adjust the LED color channels: red, green, and blue. The code uses a switch() statement to check if the received control number matches one of the three color controls. If it does, the value from the controller is remapped from the MIDI range of 0 – 127 to the 8-bit range 0 – 255, and then the LEDs are updated.

LED Functions

Since I did my testing with an RGBW strip, I’ve written the code to work with both the Adalight NeoPixel and FastLED libraries. To keep the code clean, the specific library functions are encapsulated in their own helper functions.

I’m also using a boolean array to keep track of whether an LED is on or not for the redrawing function. This could be made more efficient, but for this example there’s plenty of memory available on the microcontroller.


Voilà! With just a few lines of code and the Arduino’s MIDI library, I built a basic MIDI visualizer with colors you can tweak via MIDI continuous controllers. Cool, huh?

Here is the full sketch, if you’d like to replicate this yourself. You can also find it on Github.

Note that WS2812B LEDs are a poor choice for this because you’ll lose data during the LED latching, which can cause LEDs to be “stuck” on until they receive a MIDI off packet. But they’re one of the most common addressable LED types, and I still had plenty left over from the ambilight project.


This post is meant to be a primer – there is much more to MIDI and the Arduino’s MIDI library that I didn’t have time to touch on, notably how to send data back over MIDI. But hopefully you learned how to get started with the library and how to use MIDI data in your code.

For my example I used some addressable LEDs, but this can truly be used to control absolutely anything – servo motors, relays, speakers, serial messages… the list goes on and on. If you can control it with an Arduino and receive serial data, you can control it with MIDI.

If this tutorial helped you to build something controlled with MIDI, I’d love to see what you’ve come up with!


  1. Pretty cool! Could you please use something like ttymidi instead of hairless? I can’t even get hairless to open on linux, and therefore I’m missing the somewhat relatively crucial step of connecting midi to serial! Thanks!

  2. hey dude I’m really not sure this code works anymore… have you tested it recently? I thought plugging in the code with the appropriate libraries would work however nothing happens.. baud rate is the same on hairless and on code.

    1. The Arduino MIDI library hasn’t published a new version since I wrote this post, so I have no reason to think the code doesn’t work. I just tested some simple code with a buzzer and the LED visualizer sketch above and they both work fine.

      Here are some troubleshooting steps:

      If you’re using Hairless make sure you’re using a nominal custom baud rate (e.g. 115200) in the code. Some Arduino USB -> Serial bridges (e.g. the CH340G) have issues with non-standard rates (like 31250) and will cause transfer errors. And double-check that the Hairless serial format is correct (8 data, no parity bit, 1 stop bit). That’s the default if you didn’t change it, but it’s good for peace of mind.

      Past that, you have to have your “MIDI In” and “Serial Port’ dropdowns selected to the correct ports and the “Serial <> MIDI Bridge” checkbox checked. Make sure to enable the bridge after you connect the board, otherwise it may not enumerate properly.

      On the Arduino itself, you can start by simplifying the code. Turn on an LED in the “note on” callback regardless of the arguments, then see if you can get it to switch on via MIDI. If you can’t get that, try using a logic analyzer on the RX pin to see if it’s receiving properly formatted data. If you don’t have a logic analyzer, you could use an LED on the RX line and watch if it blinks.

      1. Hi Dave, thank you so much. Those are great troubleshooting tips! I’d been racking my head about getting this to work, going through so many different forums and examples… trying it on Linux is trickier than I though. I got it to work on a mac finally by disconnecting/reconnecting the usb cord while hairless was still on, then reselecting the usb serial. Sounds kinda dumb but I didn’t think to try that as I’d switched between computers, closed out of hairless and opened it again, changed the serial config.. something might have been stuck. Super cool and comprehensive example code btw, you rock!

  3. Hi, thank you for your tutorial, it’s very helpful and I finally I can get my strip working with my piano now. As you mention, the WS2812B is not a good choice and I do have the problem that you point out above. Do we have any way to fix this or we have to replace the strip ? since this is the only one that I have right now. If we have to replace the strip, can you recommend which one is better for this project ? Thank you very much.

    1. Replacing the strip is the simplest option. A non-blocking chipset like APA102 is usually my recommendation.

      For a more advanced solution, you could also switch to a microcontroller like a Teensy that doesn’t disable interrupts when using WS2812Bs, or use a dedicated microcontroller to deal with the LEDs and pass MIDI values to it using some sort of software flow control.

  4. Dave,

    Thank you for writing this article, it is excellent. I have been using this library and have found it very useful in interfacing with MIDI devices. One area I am stuck however. Some of the instruments I want to connect to use continuous controller messages instead of System Exclusives. I don’t think the library has a handler for this – any advice on how to capture and act on these messages?

    1. It absolutely does. Use the setHandleControlChange(void (*fptr)(byte channel, byte number, byte value)) function to set the callback for CC messages. The visualizer example in the post uses continuous controller inputs to adjust the LED color.

  5. Hi Dave,

    Very thank you for this tutorial, now I can make everything work well, but I have a new question, is it possible to use midi velocity to control the LEDs color ?

    Like if I set velocity (1-63) as red (255, 0, 0) and velocity (64-127) as green (0, 255, 0), what should I write in my code ?

    Gould Lin
    1. Definitely possible (the title is “control anything” after-all!).

      You can see that the “note on” and “note off” callback functions include velocity as one of the arguments, then just write a pair of ‘if’ statements to assign the color. E.g.:

      1. Very thank you for your reply, Dave,

        I can now make my LEDs work correctly, but sorry for my meet a new question, if I press a note (or a chord) over than 63, it will make correspond LEDs with green, but if I continue press this note(or those note) then press the other note (or an chord) under than 63 simultaneously, all note include the green notes are all will change to red, what code should I add to prevent the LEDs don’t influence by other midi input until I re-input another new input (in the same pitch)?

        Gould Lin
        1. Are you trying to modify my sample code in the post? The code I wrote wasn’t designed for having the LEDs be separate colors. It uses a boolean array to track whether an LED is “on” and then sets it to the assigned color. You’d have to rewrite the code to check against the LED color array instead of the boolean array. If you don’t care about modifying the colors on the fly it would be simpler to remove the rewrite functions all-together and just write the LED array directly.

          1. Thank you Dave,

            I just modify the code I found on the Internet, not from this post, so the boolean array can’t control LEDs light in different color, right? how to create the LED array with arduino (sorry I am just a newbie with arduino)? Can I send my sample code to you and help me find out if this is possible? (I use ws2812b strip and esp8266 with my controller)

            Gould Lin
          2. Sorry, I can’t help with that. I’d recommend looking at some tutorials for working with WS2812B LEDs and the FastLED library. Otherwise all of the information you need for the MIDI side of things should be in this post.

            Good luck!

          3. Thank you again Dave,

            I will keep trying, can you give me a advice about my project? I just want to press the key and the correspond LED will light in red or green (I want it just random), is any function can make to achieve this?

            Gould Lin
  6. Hi Dave, sorry to bother you again, can I use your code by change the hardware with an esp8266 board and a usb host shield? I just want to connect my digital piano usb output to the usb shield and connect RT, TX pin to the esp8266, does it will work?

    Gould Lin
    1. My code wasn’t written for using a USB host shield. You could probably figure out a way to re-use it, but you’ll have to translate the function calls between the USB library and the serial MIDI one (mostly just wrapping the function pointers into callbacks).

    1. You set which MIDI channels to listen to with the MIDI.begin() function, called in setup() (I typically just leave it as MIDI_CHANNEL_OMNI which will listen to everything). Then whenever you receive MIDI data the channel is passed as one of the arguments to the callback function.


Leave a Reply

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.