Lab: MIDI Output using an Arduino

Last edited 31 August 2014 by Tom Igoe

Introduction

This lab covers only the details of MIDI communication on the Arduino module. For a more general introduction to MIDI on a microprocessor, see the the MIDI notes.

MIDI, the Musical Instrument Digital Interface, is a useful protocol for controlling synthesizers, sequencers, and other musical devices. MIDI devices are generally grouped in to two broad classes: controllers (i.e. devices that generate MIDI signals based on human actions) and synthesizers (including samplers, sequencers, and so forth). The latter take MIDI data in and make sound, light, or some other effect.

What You’ll Need to Know

To get the most out of this lab, you should be familiar with the following concepts. You can check how to do so in the links below:

Things You’ll Need

For this lab you will need the following parts:
Solderless breadboard hookup_wire arduino midi_jack
Solderless Breadboard 22-AWG hook-up wire Arduino microcontroller module MIDI Connector
Resistors Resistors fsr switch
10Kohm resistors 220 ohm resistors Force-sensing resistors (or a different form of variable resistor) Switch

Prepare the breadboard

Connect power and ground on the breadboard to power and ground from the microcontroller. On the Arduino module, use the 5V and any of the ground connections:

LabMidiOut_bb
Made with Fritzing

Connect the sensors

Connect an analog sensor to analog pins 0 like you did in the analog lab. Connect a switch to digital pin 10 like you did in the digital lab.

LabMidiOut_sensors_schem  LabMidiOut_sensors_bb

Build the MIDI Circuit

Add the MIDI out jack and a 220-ohm resistor like so:

LabMidiOut_schem LabMidiOut_bb_components

This circuit doesn’t actually match the MIDI specification, but it works with all the MIDI devices we’ve tried it with. This circuit includes an analog and a digital sensor to allow for physical interactivity, but those aren’t necessary to send MIDI data.

Play Notes

Once you’re connected, sending MIDI is just a matter of sending the appropriate bytes. The bytes have to be sent as binary values, but you can format them in your code as decimal or hexadecimal values. The example below uses hexadecimal format for any fixed values, and a variable for changing values. All values are sent serially as raw binary values, using the BYTE modifier to Serial.print() (Many MIDI tables give the command values in hex, so this was done in hex for the sake of convenience):

#include <SoftwareSerial.h>

 // Variables:
  byte note = 0;            // The MIDI note value to be played

 //software serial
 SoftwareSerial midiSerial(2, 3); // digital pins that we'll use for soft serial RX & TX

  void setup() {
    //  Set MIDI baud rate:
    Serial.begin(9600);
      midiSerial.begin(31250);

  }

  void loop() {
    // play notes from F#-0 (30) to F#-5 (90):
    for (note = 30; note < 90; note ++) {
      //Note on channel 1 (0x90), some note value (note), middle velocity (0x45):
      noteOn(0x90, note, 0x45);
      delay(100);
      //Note on channel 1 (0x90), some note value (note), silent velocity (0x00):
      noteOn(0x90, note, 0x00);
      delay(100);
    }
  }

  //  plays a MIDI note.  Doesn't check to see that
  //  cmd is greater than 127, or that data values are  less than 127:
  void noteOn(byte cmd, byte data1, byte data2) {
    midiSerial.write(cmd);
    midiSerial.write(data1);
    midiSerial.write(data2);

     //prints the values in the serial monitor so we can see what note we're playing
    Serial.print("cmd: ");
     Serial.print(cmd);
       Serial.print(", data1: ");
   Serial.print(data1);
      Serial.print(", data2: ");
    Serial.println(data2);

  }

Allow a Person to Play Notes

The previous example will just play notes, no interactivity. The example below uses an analog input to set the pitch, and a digital input (a switch) to start and stop the note:

 #include <SoftwareSerial.h>

 const int switchPin = 10;  // The switch is on Arduino pin 10
 const int LEDpin = 13;     //  Indicator LED

  // Variables:
  byte note = 0;              // The MIDI note value to be played
  int AnalogValue = 0;        // value from the analog input
  int lastNotePlayed = 0;     // note turned on when you press the switch
  int lastSwitchState = 0;    // state of the switch during previous time through the main loop
  int currentSwitchState = 0;

 //software serial
 SoftwareSerial midiSerial(2, 3); // digital pins that we'll use for soft serial RX & TX

  void setup() {
    //  set the states of the I/O pins:
    pinMode(switchPin, INPUT);
    pinMode(LEDpin, OUTPUT);
    //  Set MIDI baud rate:
   Serial.begin(9600);
    blink(3);

     midiSerial.begin(31250);

  }

  void loop() {
    //  My potentiometer gave a range from 0 to 1023:
    AnalogValue = analogRead(0);
    //  convert to a range from 0 to 127:
    note = AnalogValue/8;
    currentSwitchState = digitalRead(switchPin);
    // Check to see that the switch is pressed:
    if (currentSwitchState == 1) {
      //  check to see that the switch wasn't pressed last time
      //  through the main loop:
      if (lastSwitchState == 0) {
        // set the note value based on the analog value, plus a couple octaves:
        // note = note + 60;
        // start a note playing:
        noteOn(0x90, note, 0x40);
        // save the note we played, so we can turn it off:
        lastNotePlayed = note;
        digitalWrite(LEDpin, HIGH);
      }
    }
    else {   // if the switch is not pressed:
      //  but the switch was pressed last time through the main loop:
      if (lastSwitchState == 1) {
        //  stop the last note played:
        noteOn(0x90, lastNotePlayed, 0x00);
        digitalWrite(LEDpin, LOW);
      }
    }

    //  save the state of the switch for next time
    //  through the main loop:
    lastSwitchState = currentSwitchState;
  }

  //  plays a MIDI note.  Doesn't check to see that
  //  cmd is greater than 127, or that data values are  less than 127:
  void noteOn(byte cmd, byte data1, byte  data2) {
    midiSerial.write(cmd);
   midiSerial.write(data1);
    midiSerial.write(data2);

   //prints the values in the serial monitor so we can see what note we're playing
    Serial.print("cmd: ");
     Serial.print(cmd);
       Serial.print(", data1: ");
   Serial.print(data1);
      Serial.print(", data2: ");
    Serial.println(data2);
  }

  // Blinks an LED 3 times
  void blink(int howManyTimes) {
    int i;
    for (i=0; i< howManyTimes; i++) {
      digitalWrite(LEDpin, HIGH);
      delay(100);
      digitalWrite(LEDpin, LOW);
      delay(100);
    }
  }

Make an Instrument

This is a suggestion for the Media Controller assignment. You can do any project you wish as long as it demonstrates your mastery of the lab exercises and good physical interaction. This is just one suggestion.

Now that you’ve got the basics, make a musical instrument. Consider a few things in designing yor instrument:

  • Do you want to play discrete notes (like a piano), or sliding pitches (like a theremin)? How do you program to achieve these effects?
  • Do you want to control the tempo and duration of a note?
  • Do you want the same physical action to set both the pitch and the velocity (volume) of a note?
  • Do you want to be able to play more than one note at a time (e.g. chords)?

All of these questions, and many more, will affect what sensors you use, how you read them, and how you design both the physical interface and the software.