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:

MIDI_CREATE_DEFAULT_INSTANCE();

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:

MIDI_CREATE_INSTANCE(Type, SerialPort, Name);
MIDI_CREATE_CUSTOM_INSTANCE(Type, SerialPort, Name, Settings);

Where:

  • 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:

struct MySettings : public midi::DefaultSettings{
    static const bool UseRunningStatus = false;
    static const bool HandleNullVelocityNoteOnAsNoteOff = true;
    static const bool Use1ByteParsing = true;
    static const long BaudRate = 31250;
    static const unsigned SysExMaxSize = 128;
};

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:

// Default Instance
MIDI_CREATE_DEFAULT_INSTANCE();

// Hardware Serial
MIDI_CREATE_INSTANCE(HardwareSerial, Serial, MIDI2);

// Hardware Serial, Custom Baud
struct CustomBaud : public midi::DefaultSettings{
    static const long BaudRate = 115200; // Baud rate for hairless
};
MIDI_CREATE_CUSTOM_INSTANCE(HardwareSerial, Serial, MIDI3, CustomBaud);

// Software Serial
#include <SoftwareSerial.h>
SoftwareSerial mySerial(10, 11); // RX, TX
MIDI_CREATE_INSTANCE(SoftwareSerial, mySerial, MIDI4);

// Dual Instance (Arduino Mega)
MIDI_CREATE_INSTANCE(HardwareSerial, Serial, MIDI5);
MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, MIDI6);

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:

setHandleNoteOff(void (*fptr)(byte channel, byte note, byte velocity));
setHandleNoteOn(void (*fptr)(byte channel, byte note, byte velocity));
setHandleAfterTouchPoly(void (*fptr)(byte channel, byte note, byte pressure));
setHandleControlChange(void (*fptr)(byte channel, byte number, byte value));
setHandleProgramChange(void (*fptr)(byte channel, byte number));
setHandleAfterTouchChannel(void (*fptr)(byte channel, byte pressure));
setHandlePitchBend(void (*fptr)(byte channel, int bend));
setHandleSystemExclusive(void (*fptr)(byte * array, unsigned size));
setHandleTimeCodeQuarterFrame(void (*fptr)(byte data));
setHandleSongPosition(void (*fptr)(unsigned beats));
setHandleSongSelect(void (*fptr)(byte songnumber));
setHandleTuneRequest(void (*fptr)(void));
setHandleClock(void (*fptr)(void));
setHandleStart(void (*fptr)(void));
setHandleContinue(void (*fptr)(void));
setHandleStop(void (*fptr)(void));
setHandleActiveSensing(void (*fptr)(void));
setHandleSystemReset(void (*fptr)(void));

You configure these in the setup function, like so:

// "MIDI" is the name of our MIDI instance

void setup(){
  MIDI.setHandleNoteOn(noteOn);
  MIDI.setHandleNoteOff(noteOff);
  MIDI.begin(MIDI_CHANNEL_OMNI);
}

void noteOn(byte channel, byte note, byte velocity){  
}

void noteOff(byte channel, byte note, byte velocity){
}

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.

void loop(){
  MIDI.read(); // Check for MIDI messages every loop
}

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:

struct CustomBaud : public midi::DefaultSettings{
    static const long BaudRate = 115200;
};
MIDI_CREATE_CUSTOM_INSTANCE(HardwareSerial, Serial, MIDI, CustomBaud);

Adding Handlers

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

void setup(){
  MIDI.setHandleNoteOn(handleNoteOn);
  MIDI.setHandleNoteOff(handleNoteOff);
  MIDI.setHandleControlChange(handleControlChange);
  MIDI.begin(MIDI_CHANNEL_OMNI);
}

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.

const uint8_t minNote = 40;
const uint8_t maxNote = minNote + NumLEDs;

void handleNoteOn(byte channel, byte note, byte velocity){
  if(note < minNote || note > maxNote){
    return;
  }

  ledON(note - minNote);
  show();
}

void handleNoteOff(byte channel, byte note, byte velocity){
  if(note < minNote || note > maxNote){
    return;
  }

  ledOFF(note - minNote);
  show();
}

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.

const uint8_t
 redCC = 21,
 greenCC = 22,
 blueCC = 23;

uint8_t
 rVal = 255,
 gVal = 255,
 bVal = 255;

void handleControlChange(byte channel, byte number, byte value){
  switch(number){
    case redCC:
      rVal = map(value, 0, 127, 0, 255);
      redraw();
      break;
    case greenCC:
      gVal = map(value, 0, 127, 0, 255);
      redraw();
      break;
    case blueCC:
      bVal = map(value, 0, 127, 0, 255);
      redraw();
      break;
  }
}

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.

// Build the LED strip
#ifdef ADAFRUIT_NEOPIXEL_H
  Adafruit_NeoPixel strip = Adafruit_NeoPixel(NumLEDs, Pin, NEO_GRBW + NEO_KHZ800);
#elif FASTLED_VERSION
  CRGB leds[NumLEDs];
#endif

boolean ledState[NumLEDs];

void ledON(uint8_t index){
  ledState[index] = 1;
  setLED(index, rVal, gVal, bVal);
}

void ledOFF(uint8_t index){
  ledState[index] = 0;
  setLED(index, 0, 0, 0);
}

void setLED(uint8_t index, uint8_t r, uint8_t g, uint8_t b){
  #ifdef ADAFRUIT_NEOPIXEL_H
    strip.setPixelColor(index, r, g, b);
  #elif FASTLED_VERSION
    leds[index].r = r;
    leds[index].g = g;
    leds[index].b = b;
  #endif
}

void redraw(){
  for(int i = 0; i<NumLEDs; i++){
    if(ledState[i] == 1){
      ledON(i);
    }
  }
  show();
}

void show(){
  #ifdef ADAFRUIT_NEOPIXEL_H
    strip.show();
  #elif FASTLED_VERSION
    FastLED.show();
  #endif
}

Result

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.

/*
 * Basic MIDI Visualizer
 * by David Madison © 2017
 * www.partsnotincluded.com
 * 
 * This is a basic MIDI visualizer using addressable LEDs, to demonstrate how
 * Arduino's MIDI library works. Playing a note turns an LED on, stopping a note
 * turns the LED off. Continuous controllers 21, 22, and 23 adjust the RGB color.  
 * 
 */

#include <FastLED.h>
//#include <Adafruit_NeoPixel.h> // Uncomment if you're using RGBW LEDs

// ---- User Settings --------------------------
#define DATAPIN 6
#define NUMLEDS 60
#define BRIGHTNESS 255
#define BAUDRATE 115200 // For Hairless
#define NOTESTART 40
// ----------------------------------------

// Continuous Controller Numbers
static const uint8_t
  redCC   = 21,
  greenCC = 22,
  blueCC  = 23;

// Settings
static const uint8_t
  Pin = DATAPIN,
  NumLEDs = NUMLEDS,
  minNote = NOTESTART,
  maxNote = minNote + NumLEDs,
  maxBright = BRIGHTNESS;

// LED Color Values
uint8_t
  rVal = 255,
  gVal = 255,
  bVal = 255;

// Build the LED strip
#ifdef ADAFRUIT_NEOPIXEL_H
  Adafruit_NeoPixel strip = Adafruit_NeoPixel(NumLEDs, Pin, NEO_GRBW + NEO_KHZ800);
#elif FASTLED_VERSION
  CRGB leds[NumLEDs];
#endif

boolean ledState[NumLEDs];

// Create the MIDI Instance
#include <MIDI.h>
struct CustomBaud : public midi::DefaultSettings{
    static const long BaudRate = BAUDRATE;
};
MIDI_CREATE_CUSTOM_INSTANCE(HardwareSerial, Serial, MIDI, CustomBaud);

void setup(){
  #ifdef ADAFRUIT_NEOPIXEL_H
    strip.setBrightness(maxBright);
    strip.begin();
    strip.show();
  #elif FASTLED_VERSION
    FastLED.addLeds<WS2812B, Pin, GRB>(leds, NumLEDs);
    FastLED.setBrightness(maxBright);
    FastLED.show();  
  #endif
  
  MIDI.setHandleNoteOn(handleNoteOn);
  MIDI.setHandleNoteOff(handleNoteOff);
  MIDI.setHandleControlChange(handleControlChange);
  MIDI.begin(MIDI_CHANNEL_OMNI);
}

void loop(){
  MIDI.read(); // Check for MIDI messages every loop
}

void handleNoteOn(byte channel, byte note, byte velocity){
  // Check if note is in range
  if(note < minNote || note > maxNote){
    return;
  }
  
  ledON(note - minNote);
  show();
}

void handleNoteOff(byte channel, byte note, byte velocity){
  // Check if note is in range
  if(note < minNote || note > maxNote){
    return;
  }

  ledOFF(note - minNote);
  show();
}

void handleControlChange(byte channel, byte number, byte value){
  switch(number){
    case redCC:
      rVal = map(value, 0, 127, 0, 255);
      redraw();
      break;
    case greenCC:
      gVal = map(value, 0, 127, 0, 255);
      redraw();
      break;
    case blueCC:
      bVal = map(value, 0, 127, 0, 255);
      redraw();
      break;
  }
}

void ledON(uint8_t index){
  ledState[index] = 1;
  setLED(index, rVal, gVal, bVal);
}

void ledOFF(uint8_t index){
  ledState[index] = 0;
  setLED(index, 0, 0, 0);
}

void setLED(uint8_t index, uint8_t r, uint8_t g, uint8_t b){
  #ifdef ADAFRUIT_NEOPIXEL_H
    strip.setPixelColor(index, r, g, b);
  #elif FASTLED_VERSION
    leds[index].r = r;
    leds[index].g = g;
    leds[index].b = b;
  #endif
}

void redraw(){
  for(int i = 0; i<NumLEDs; i++){
    if(ledState[i] == 1){
      ledON(i);
    }
  }
  show();
}

void show(){
  #ifdef ADAFRUIT_NEOPIXEL_H
    strip.show();
  #elif FASTLED_VERSION
    FastLED.show();
  #endif
}

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.

Conclusion

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!


44 Comments

José Manuel González · January 14, 2018 at 8:05 am

Really cool stuff man!!!

Pwr · October 29, 2018 at 9:02 pm

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!

pwr · November 4, 2018 at 10:13 am

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.

    Dave · November 4, 2018 at 2:32 pm

    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.

      pwr · November 14, 2018 at 11:14 pm

      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!

        Dave · November 14, 2018 at 11:33 pm

        Awesome! Glad to hear you got it working.

danhli · November 12, 2018 at 1:35 pm

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.

    Dave · November 12, 2018 at 6:26 pm

    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.

Chip McClelland · March 19, 2019 at 10:02 pm

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?

    Dave · March 19, 2019 at 10:05 pm

    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.

Gould Lin · April 26, 2019 at 1:47 am

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 ?

    Dave · April 26, 2019 at 2:57 am

    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.:

    void handleNoteOn(byte channel, byte note, byte velocity) {
     if(velocity <= 63) {
     // red color stuff
     }
     else if(velocity> 63) {
     // green color stuff
     }
    }

      Gould Lin · April 26, 2019 at 5:02 am

      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)?

        Dave · April 26, 2019 at 5:11 am

        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.

          Gould Lin · April 26, 2019 at 5:33 am

          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)

          Dave · April 26, 2019 at 5:57 am

          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!

          Gould Lin · April 26, 2019 at 6:20 am

          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?

          Dave · April 26, 2019 at 9:16 am

          With Arduino you can use the “random” function (reference) with a range of 0 to 1. Then use the result of that to decide which color to set.

Gould Lin · May 22, 2019 at 2:33 am

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?

    Dave · May 22, 2019 at 4:44 pm

    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).

Juan Baq · May 30, 2019 at 10:40 am

Hey,
how can I recieve data from diferent MIDI channels??

    Dave · May 30, 2019 at 10:56 am

    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.

      Juan Baq · June 8, 2019 at 5:03 pm

      Thanks Dave,

      Is there a chance to control de dimmer of a LED by receiving a midi Control Change message ?

        Dave · June 8, 2019 at 9:09 pm

        Absolutely, you’d control it just like anything else.

Andy · October 19, 2019 at 12:11 am

Hi Dave. I’ve just stumbled on your article and it was very informative. I do have one question. In principle could I use an existing midi file stored on an sd card in place of real time midi messages. Would the output from the sd card be the same as a midi instrument played live and would the connection to the arduino, that is, the midi input side be the same.

    Dave · October 19, 2019 at 12:45 am

    In principle, yes. If you’re playing the MIDI file on a PC or a Raspberry Pi or through some other device interfacing with the Arduino over USB or through the serial input then nothing changes – it would behave exactly as if it was receiving live data.

    If you wanted to use an SD card attached to the same Arduino then you likely wouldn’t use the built-in MIDI library at all, and would write the code based off of how the data is being read off of the SD card.

Connor · June 7, 2020 at 3:54 pm

Hey Dave, thanks so much for posting this! It was super helpful. I’m using the foundations laid out in this article to control my Arduino patches using an external midi controller that has 16 faders (control channels).

I’m able to successfully read the midi data from the 16 faders, but there is a pretty substantial latency when I move a fader up and down quickly or move multiple faders at once. It looks like individual messages come in very quickly, but as moving a faders sends a CC message for every value between 0-127, it looks like a ‘queue’ forms in the serial port and it takes a second or more for the arduino to ‘catch up’ with all of the messages.

Do you know of any strategies to: receive messages more quickly / avoid that ‘queue’ of cc messages. I was thinking that I could ‘ignore’ some of the messages, but I don’t know how to do that if midi.read() collects everything in every loop.

    Dave · June 7, 2020 at 7:25 pm

    Hi Connor. The Arduino is more than capable of reading the MIDI messages faster than they can arrive even if the serial bus is fully saturated. The ‘x’ factor, and what can introduce delays, is what you’re doing with the data once it arrives.

      Connor · June 8, 2020 at 2:00 pm

      Thanks, Dave. That’s encouraging 🙂 My sketch is pretty simple already (read midi cc messages, map them, Serial.print them), but I’ll start to break it down and do some experiments. .

        Dave · June 8, 2020 at 3:21 pm

        It’s likely the Serial.print statements that are getting you in trouble. Before anything else, try to up your baud rate (115200 or higher) and cut down the amount of text you’re sending through.

          Connor · June 9, 2020 at 12:31 am

          I removed most of what I was printing and am now seeing almost no latency 🙂 Thanks again!

          Dave · June 9, 2020 at 1:22 am

          Awesome! Glad you were able to get it sorted ?

Jaguar · June 21, 2020 at 1:09 pm

Can i do this way by melodica ..and can i make button to move between Octaves??

Willy · July 1, 2020 at 6:48 am

Great tutorial. Is there any reason to think that I can’t use Arduino to convert CC# to PC? All I want to do it send a CC# and have it changed to the same number but as a PC. There are devices that can to it, but can it be done with Arduino?

    Dave · July 1, 2020 at 7:42 am

    Absolutely. Just read the CC message and send a corresponding program change message out.

mmryspace · August 4, 2020 at 1:35 pm

Hi Dave,
Your tutorial has been super helpful – thank you!
I am new to Arduino and building electronic circuits and have a small MIDI project I am undertaking with an Arduino UNO.
I have built a basic MIDI input and Output circuit on a breadboard and I am using the Arduino MIDI library.

Tested using the example callback sketch provided in the repository and it works fine with an input from a step sequencer and a VST soft synth.

What I would like to know is if I can use the FortySevenEffects MIDI library to achieve some of the functionality that the Mutable Instruments MIDI Pal (https://github.com/pichenettes/midipal) offers?

Specifically: a BPM Counter, Note Display of a specific step, i.e. MIDI monitor. I thought these might be a good place to start as a beginner.

    Dave · August 4, 2020 at 3:01 pm

    Hi there!

    So long as the data is passing through the board you can add just about any feature of other MIDI devices. I would recommend looking at that source to find the feature you want and the data it’s referencing, then search for the corresponding handler function in the library.

mmryspace · August 4, 2020 at 3:57 pm

Ok, great! That is what I was thinking could be possible. I will dig in the source there and see if I can have a go. Much appreciated!

Nicolas · January 16, 2021 at 8:19 pm

Thank you dear Dave. May you tell to us about the delta time and how to code it ?

    Dave · January 17, 2021 at 9:02 am

    Hi Nicolas. Although it looks like the Arduino library supports MIDI timecode, I have no experience with it myself.

Michael · April 18, 2022 at 7:35 pm

Hi Dave,

Great article!!!

I would like to have the color of leds change based on the note played. When a note is played, all leds will be the same color. for example, if a C4 is played, leds will turn red; if c#4 is played, leds will turn blue; and if a D4 is played, leds will turn green. I think it involves 3 different for loops, but im not sure how to do it. Thanks!

    Dave · April 19, 2022 at 4:10 am

    Hi Michael. Within the `handleNoteOn()` function you would parse the incoming note and set the color value. Then you would have to iterate through the LEDs to change the colors. In my demo code I did that using a secondary `boolean` array that tracked whether the LEDs were on or not. I hope that helps.

François · January 8, 2023 at 4:04 pm

Hi Dave, author of the Arduino MIDI Library here, thanks for this article, it’s a great showcase of what can be done with the library!

    Dave · January 9, 2023 at 6:22 pm

    Hi François! Great work on the library and thank you for the kind words, I really appreciate it.

Leave a Reply

Avatar placeholder

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.

Would you like to know more?