Arduino and MIDI in

Level: 
Tools: 

Arduino circuit photo.

In this second installment of our Arduino tutorial series, we will learn to use the Arduino micro-controller as a tool to control electronics by reading MIDI, in this case turning on the Arduino's built in LED when it receives MIDI note on messages. If you haven't already read our first Arduino tutorial on MIDI out, we suggest you at least give it a quick glance.

The hardware of this tutorial is inspired by the Send and Receive MIDI with Arduino tutorial.

Building the MIDI in interface

You will need the following components to build the MIDI in interface:

  • 1 x Arduino UNO R3 (or similar)
  • 1 x breadboard
  • 1 x MIDI DIN contact
  • 3 x 220 Ohm resistor
  • 1 x 1N4148 diode
  • 1 x 10kOhm resistor
  • 1 x 6N138 optocoupler
  • and some wires

These components can be bought at your local electronics store or on Ebay. You will also need a MIDI keyboard/controller and a computer running the Arduino IDE.

The reason why we can't interface our MIDI gear with the Arduino directly is that the two electronic circuits (the Arduino and the MIDI gear) have to be electronically isolated from each other. This is done by the opto-coupler, shown as a black IC with 8 legs in the middle of the breadboard below. (If you are interested in what the opto-coupler does, check out the datasheet, but in short it contains an LED and a photo detector, transferring the signal as light before turning it into electricity again.)

You put the components together like this:

Arduino Midi In Schema

or you can follow the circuit design by Amanda Ghassaei (although she uses D0 while we use D2 as the Arduino input pin, and a 470 Ohm resistor whle we use 2 x 220 Ohm resistors in series):

Arduino graphic schema

You can test the interface with the following code, which turns on the built in LED on the Arduino for every MIDI Note On message it receives:

// midi_in_test.ino
// version 2015-06-01
// Arduino MIDI tutorial
// by Staffan Melin
// http://libremusicproduction.com/

// libraries

#include <SoftwareSerial.h>

// We will use the SoftwareSerial library instead of the Serial library, as this will let us control which pins our MIDI interface is connected to.
SoftwareSerial mySerial(2, 3); // RX, TX

// constants

const byte midiNoteOn = 144;

const int midiSendDelay = 100; // give MIDI-device a short time to "digest" MIDI messages

#define PIN_LED 13

#define MIDI_NOTE_ON 144

byte midiByte;
byte midiChannel;
byte midiCommand;

void setup() {
    // setup SoftSerial for MIDI control
    mySerial.begin(31250);
    delay(midiSendDelay);

    pinMode(PIN_LED, OUTPUT);
}

void loop () {

    // Is there any MIDI waiting to be read?

    if (mySerial.available() > 0) {

        // read MIDI byte

        midiByte = mySerial.read();
    
        // remove channel info
        midiChannel = midiByte & B00001111;
        midiCommand = midiByte & B11110000;

        // if it is a MIDI note on commannd, blink the LED    
        if (midiCommand == MIDI_NOTE_ON)
        {
            digitalWrite(PIN_LED, HIGH);
            delay(100);
            digitalWrite(PIN_LED, LOW);
        }
    } // mySerial.available()

} // loop

A state machine

We would like to have some more control over the input and when to trigger the LED. We would like to take some action only when we receive a MIDI Note On message for a specific note on a specific channel.

A nice way to handle several incoming bytes in a row is to use the state machine model. This works by letting the program exist in several different states, depending on what kind of MIDI data it has already received. For our program it is:

State diagram.

We can do that with the following code which only turns on the LED when the user presses middle C on a controller on MIDI channel 1 (called 0 on some devices):

// midi_in_state.ino
// version 2015-06-01
// Arduino MIDI tutorial
// by Staffan Melin
// http://libremusicproduction.com/

// libraries

#include <SoftwareSerial.h>

// We will use the SoftwareSerial library instead of the Serial library, as this will let us control which pins our MIDI interface is connected to.
SoftwareSerial mySerial(2, 3); // RX, TX

// constants

#define PIN_LED 13

// MIDI commands
#define MIDI_NOTE_ON 144
#define MIDI_NOTE_OFF 128

// filter MIDI events on channel and note number
const int filterChannel = 0; // MIDI channel 1
const int filterNote = 60; // middle C

// states
#define STATE_NONE 0
#define STATE_NOTE_ON 1
#define STATE_NOTE 2
int state;

// keep action (LED) going for actionDuration milliseconds
bool actionOn;
unsigned long actionTime;
unsigned long actionDuration = 100;

// received MIDI data
byte midiByte;
byte midiChannel;
byte midiCommand;
byte midiNote;
byte midiVelocity;

void setup() {

    mySerial.begin(31250);
    delay(100);

    pinMode(PIN_LED, OUTPUT);
    
    state = STATE_NONE;
    actionOn = false;    
}

void loop () {

    // Is there any MIDI waiting to be read?

    if (mySerial.available() > 0) {

        // read MIDI byte

        midiByte = mySerial.read();

        switch (state) {

        case STATE_NONE:
        
            // remove channel info
            midiChannel = midiByte & B00001111;
            midiCommand = midiByte & B11110000;

            if (midiChannel == filterChannel)
            {
                if (midiCommand == MIDI_NOTE_ON)
                {
                    state = STATE_NOTE_ON;
                }
            }
            break;

        case STATE_NOTE_ON:
            midiNote = midiByte;
            state = STATE_NOTE;
            break;
            
        case STATE_NOTE:
            midiVelocity = midiByte;
            state = STATE_NONE;
            
            if (midiNote == filterNote && midiVelocity > 0)
            {
                digitalWrite(PIN_LED, HIGH);
                actionTime = millis();
                actionOn = true;
            }
            
            break;
            
        } // switch

    } // mySerial.available()

    // turn action off after predetermined time

    if (actionOn)
    {
        if ((millis() - actionTime) > actionDuration)
        {
            actionOn = false;
            digitalWrite(PIN_LED, LOW);
        }
    }    

} // loop

Resources and files

by Staffan Melin

 

 

Comments

To build a touch sensitive MIDI device with 128 inputs have a look at https://blog.georgmill.de/2015/07/22/touchduinoxtended/

Thanks for the head up, Georg! I have added it to the Arduino page as well as written a News piece about it.

Thanks. Development is in alpha stage. But in some days the Arduino source library to get the chip running easily will become available (gpl).

The XL version of the touch sensitive Midi piano incl. Midi controller on https://blog.georgmill.de/2015/07/30/touchduino-xl/

Damn, aiming for king of the controllers? :) Actually, very interesting to see you using I2C for expanding the inputs. This could be used in a lot of (music) projects. I have added it to the Arduino Tool entry. Great work!

Maybe the king of touch fruit midi keyboards :-) The website was updated with a new video showing how to get values from 0-127 from each of the digital inputs of the MCP23017. Enjoy and don't laugh too loud, please. It's not usable for a real touch sensitive midi keyboard controller but maybe interesting for the industry or medicine.

I think it's cool. Now I understand -- the MCP sends data via the serial pins of the Arduino, right? Maybe you'd like to write a tutorial for LMP sometime?

It is not the MCP that sends the data to the serial line. It is the sketch, especially the Serial.print(...) lines that do this. For generating midi it is just as easy as using Serial.print messages in the sketch that contain midi notes or messages. The good news is that you don't need water any longer. We modified the sketch. Now it is possible to use all 64 paper clips with the touch of your (dry) fingers to produce sound. You can download it from here-> https://blog.georgmill.de/2015/07/30/touchduino-xl/ Scroll to the bottom of the page (where the comments start) and search for "Download the modified version directly from here." To answer your question concerning the tutorial: Yes. Please contact me for details.

Hi, this project doesn't work for me. Are you sure this work? Yoy have a mistake in the pic before the schematic, see the diode position. Regards

All correct, sorry for the inconvenience ;)

Is that diode on the breadboard diagram not still wrong? It's connected to nothing.

It should be between pins 2 and 3.

Thank you for the correction, you are of course right! Tutorial graphics updated!