Instructables

Send and Receive MIDI with Arduino

Featured
Picture of Send and Receive MIDI with Arduino
This instructable will show you how to use an Arduino to send and receive a variety of MIDI messages so you can start building your own MIDI controllers and instruments.  First I'll talk a little bit about MIDI protocol, if you're just looking for sample code skip ahead to steps 5-9.

If you know absolutely nothing about MIDI note, velocity, and pitchbend or are confused about what MIDI does and why you would want to use it, check out my What is MIDI? instructable.
 
Remove these adsRemove these ads by Signing Up

Step 1: Bytes and Bits

To understand MIDI communication, you have to understand a little about bytes and bits.  A byte is a packet of data used to store information.  In MIDI protocol, each byte is made up of 8 bits; bits can only equal to 0 or 1.  A sample byte is given below:

11010111

Each 1 or 0 in this byte is a bit.  The leftmost bit is called the most significant bit (or MSB) and the rightmost bit is called the least significant bit (or LSB).

Bytes of the form above are binary numbers because they are expressed using only 1's and 0's.  We can convert this number to base ten as well:

11010111 in binary (base 2) = 215 in decimal (base 10)

If you need help converting numbers from binary to decimal or vice versa check out Wolfram Alpha.  Type in a binary number followed with "from binary to decimal" to get the decimal equivalent.  Wolfram Alpha is also great for converting to and from hexadecimal.

Wikipedia is a good resource for more information about bytes and binary.
Now I did, sorry. I just got in the optocouplers from mouser, and was about to put this all together, and remembered by board in 3.3V. If I supply the optocouplers with 3.3 will I run into any obvious issues?
if you supply the optocouplers with 3.3V, then the max signal coming out of them will be 3.3V. Since you are trying to read with with one of the Arduino's digital pins, I'm concerned it might not be enough to switch it to a "HIGH" state. no harm in trying though.
Hi there

Thanks for the Instructable - the MIDI out section's fantastic, and the tutorial as a whole inspired me to buy an Arduino. Great work!

I've not been able to get MIDI in messages to light an LED though. It's to do with the non-Arduino components, I think: I took a risk and connected the MIDI In directly to my Arduino Nano, and it then works fine - so the issue's not Arduino compatibility. I've tested continuity where I can (resistors, diode) and tried 2 different optocouplers. My optocoupler was Lite-On brand, but I've compared the specs and the pinout/internal circuitry are the same as the device you specify. No oscilloscope here I'm afraid!



amandaghassaei (author)  museumoftechno1 year ago
without an oscilloscope it;s really hard to troubleshoot. I had some trouble getting this to work too, the circuit can be a bit finicky. my only suggestion is tot get the optocoupler I recommended and wire it up exactly as it;s shown int eh schematic. sorry!
spacekit1 year ago
Hi! I am following this step by step. I see msg coming into my arduino and can't see anything going on MAX patch and Ableton Live. I set USB port as my midi input in Ableton Live. Is there anything that I am missing?
amandaghassaei (author)  spacekit1 year ago
this is going to sound dumb, but try changing the order that you open max/ableton and plug in the arduino, also try resetting the arduino (there is a tiny button on the board that causes it to reset). do you see the ardunio in your available inputs?
cezarsp1231 year ago
The code passes to perfection midi signal coming from the drums, but to manipulate this sign, or put a note in it that comes from the keyboard is hard to give. I suppose there must be a code to receive only channel 10, and one for receive only channel 1, separates what you want, and formed the final message with command byte, keyboard note, and velocity of the battery. The problem for me is that there is only one serial port input, and my filter is not working.
amandaghassaei (author)  cezarsp1231 year ago
you can make another serial input with this:
http://arduino.cc/en/Reference/SoftwareSerial
but if your incoming midi is coming in with separate channels, then you can read them both from pin 0. do the following:

byte commandByte;
byte noteByte;
byte velocityByte;

void setup(){

Serial.begin(31250);

cli();//stop interrupts

//set timer2 interrupt every 128us
TCCR2A = 0;// set entire TCCR2A register to 0
TCCR2B = 0;// same for TCCR2B
TCNT2 = 0;//initialize counter value to 0
// set compare match register for 7.8khz increments
OCR2A = 255;// = (16*10^6) / (7812.5*8) - 1 (must be <256)
// turn on CTC mode
TCCR2A |= (1 << WGM21);
// Set CS11 bit for 8 prescaler
TCCR2B |= (1 << CS11);
// enable timer compare interrupt
TIMSK2 |= (1 << OCIE2A);

sei();//allow interrupts

}


ISR(TIMER2_COMPA_vect) {//checks for incoming midi every 128us
do{
if (Serial.available()){
commandByte = Serial.read();//read first byte
noteByte = Serial.read();//read next byte
velocityByte = Serial.read();//read final byte
MIDImessage(commandByte,noteByte,velocityByte);
}
}
while (Serial.available() > 24);//when three bytes available
}

//send MIDI message
void MIDImessage(int command, int data1, int data2) {
Serial.write(command);//send command byte
Serial.write(data1);//send data byte #1
Serial.write(data2);//send data byte #2
}

void loop(){
//do whatever here
}

does that work? are your keys and drums coming into the arduino on separate channels?
amandaghassaei (author)  amandaghassaei1 year ago
oops, I just reread your original post, I think this is what you need:

byte commandByte;
byte noteByte;
byte velocityByte;

byte newCommandByte = 0;
byte newNoteByte = 0;
byte newVelocityByte = 0;

boolean newote = false;

void setup(){

Serial.begin(31250);

cli();//stop interrupts

//set timer2 interrupt every 128us
TCCR2A = 0;// set entire TCCR2A register to 0
TCCR2B = 0;// same for TCCR2B
TCNT2 = 0;//initialize counter value to 0
// set compare match register for 7.8khz increments
OCR2A = 255;// = (16*10^6) / (7812.5*8) - 1 (must be <256)
// turn on CTC mode
TCCR2A |= (1 << WGM21);
// Set CS11 bit for 8 prescaler
TCCR2B |= (1 << CS11);
// enable timer compare interrupt
TIMSK2 |= (1 << OCIE2A);

sei();//allow interrupts

}


ISR(TIMER2_COMPA_vect) {//checks for incoming midi every 128us
do{
if (Serial.available()){
commandByte = Serial.read();//read first byte
channel = commandByte&B00001111;//last four bits of commandByte
if (channel ==10){//midi channel of your drums
newCommandByte = commandByte &B11110000;//change newCommandByte to commandByte with midi channel 0
noteByte = Serial.read();//read next byte, this gets thrown away
newVelocityByte = Serial.read();//read final byte and set to newVelocityByte
newNote = true;//let's us know there is a new note to send out
} else {//midi channel of your keys
newNoteByte = Serial.read();//read next byte and set newNoteByte
velocityByte = Serial.read();//read final byte, this gets thrown away
}
if (newNote){//
newNote = false;
//send out combined midi on channel 0
MIDImessage(newCommandByte,newNoteByte,newVelocityByte);
}
}
}
while (Serial.available() > 24);//when three bytes available
}

//send MIDI message
void MIDImessage(int command, int data1, int data2) {
Serial.write(command);//send command byte
Serial.write(data1);//send data byte #1
Serial.write(data2);//send data byte #2
}

void loop(){
//do whatever here
}
I do not understand my work wrong but it works, and that you went above does not work. Something is missing in void loop?

byte commandByte;
byte noteByte;
byte velocityByte;
byte noteByte1;
byte noteOn = 144;

//light up led at pin 13 when receiving noteON message with note = 60

void setup(){
Serial.begin(31250);
// pinMode(13,OUTPUT);
//digitalWrite(13,LOW);
}

void checkMIDI(){
do{
if (Serial.available()){
commandByte = Serial.read();//read first byte

noteByte = Serial.read();//read next byte

velocityByte = Serial.read();//read final byte

//if (commandByte == noteOn){//if note on message
//check if note == 60 and velocity > 0
//if (noteByte == 60 && velocityByte > 0){
//digitalWrite(13,HIGH);//turn on led
//}
//}
}
}
while (Serial.available() > 24);//when three bytes available
}


void loop(){
if (Serial.available()){
checkMIDI();

MIDImessage(commandByte, noteByte, velocityByte);
}

}
void MIDImessage(int commandByte, int noteByte, int velocityByte) {
Serial.write(commandByte);//send note on or note off command
Serial.write(noteByte);//send pitch data
Serial.write(velocityByte);//send velocity data

}
amandaghassaei (author)  cezarsp1231 year ago
are you receiving two different midi channels? if you play both instruments, plug int he arduino to your computer, turn on the serial monitor and add
println (commandByte);
to the loop(), can you copy what gets printed and post it?
I thank you very much for responding, I'll test tomorrow and then reply. A big hug!
enomys731 year ago
Hi, I am new with MIDI and Arduino, but I can't understand how to connect my keyboard contacts( matrix) with Arduino Inputs.... I'd like to put MIDI interface into my homemade synth... thanks so much...
amandaghassaei (author)  enomys731 year ago
do you have a pic you can post?
So, now how do you receive MIDI on the Arduino. I am writing a synth for the DUE and have lots of knowledge with wave table synthesis in super collider but not much with serial communication or programming with data types other than control or audio. I am having issues receiving MIDI and detecting which bytes are which without commas or some other carriage return to differentiate each byte from the last.
did you read step 9?
It's hard to manipulate the bytes?
cezarsp1231 year ago
I read step 9, it works well to receive 1 channel 1 channel and send, but how do I separate each midi message (channel 10, channel 1) handle this message, and send a final message? Working with bytes is hard!
cezarsp1231 year ago
the esqueme
esquema midi bateria.jpg
cezarsp1231 year ago
that the scheme did
cezarsp1231 year ago
/*Receive MIDI and check if note = 60
By Amanda Ghassaei
July 2012
http://www.instructables.com/id/Send-and-Receive-MIDI-with-Arduino/

* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.

*/

byte commandByte;
byte noteByte;
byte velocityByte;
byte noteByte1;
byte noteOn = 144;


void setup(){
Serial.begin(31250);

}

void checkMIDI(){
do{
if (Serial.available()){
commandByte = Serial.read();//read first byte

noteByte = Serial.read();//read next byte

velocityByte = Serial.read();//read final byte


}
}
while (Serial.available() > 24);//when three bytes available
}


void loop(){
if (Serial.available()){
checkMIDI();
if (commandByte == noteOn){
noteByte1=noteByte;
}

MIDImessage(commandByte, noteByte1, velocityByte);
}

}
void MIDImessage(int commandByte, int noteByte1, int velocityByte) {
Serial.write(commandByte);//send note on or note off command
Serial.write(noteByte1);//send pitch data
Serial.write(velocityByte);//send velocity data

}
cezarsp1231 year ago
/*Receive MIDI and check if note = 60
By Amanda Ghassaei
July 2012
http://www.instructables.com/id/Send-and-Receive-MIDI-with-Arduino/

* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.

*/

byte commandByte;
byte noteByte;
byte velocityByte;
byte noteByte1;
byte noteOn = 144;

//light up led at pin 13 when receiving noteON message with note = 60

void setup(){
Serial.begin(31250);
// pinMode(13,OUTPUT);
//digitalWrite(13,LOW);
}

void checkMIDI(){
do{
if (Serial.available()){
commandByte = Serial.read();//read first byte

noteByte = Serial.read();//read next byte

velocityByte = Serial.read();//read final byte

//if (commandByte == noteOn){//if note on message
//check if note == 60 and velocity > 0
//if (noteByte == 60 && velocityByte > 0){
//digitalWrite(13,HIGH);//turn on led
//}
//}
}
}
while (Serial.available() > 24);//when three bytes available
}


void loop(){
if (Serial.available()){
checkMIDI();
if (commandByte == noteOn){
noteByte1=noteByte;
}

//delay(250);
//digitalWrite(13,LOW);//turn led off
MIDImessage(commandByte, noteByte1, velocityByte);
}

}
void MIDImessage(int commandByte, int noteByte, int velocityByte) {
Serial.write(commandByte);//send note on or note off command
Serial.write(noteByte);//send pitch data
Serial.write(velocityByte);//send velocity data

}


cezarsp1231 year ago
Hi Amanda
I did 2 circuits with 2 - 6N138, one gets the midi drums, the other receives midi keyboard according to the Tx, however I can not manipulate the bytes, the sound gets all mixed up, I can not put the note on the keyboard of my message Midi end. MidiMessage (Status, note, velocity)
The battery comes on channel 10, channel 1 on the keyboard. I can not make the arduino identify one another, and finally put the note on my keyboard, the final message (Status, note keyboard, drums velocity)
Please help me with this code. Thank you.
amandaghassaei (author)  cezarsp1231 year ago
can you post your code?
cezarsp1231 year ago
Hi Amanda, is based on step 9 I decided to build this circuit (I'm hoping to get the 6N138 optocoupler to begin testing, I have the remaining components). This circuit would have two inputs and one output as you suggested. I need to get the first and third byte of my son, and it adds just the second byte of my keyboard and send output. As you build the code?
cezarsp1231 year ago
My son has a battery electronic yamaha dtx 500 with midi output. and I have a keyboard psr s 910 with midi input and output.
amandaghassaei (author)  cezarsp1231 year ago
I think you should set up two midi inputs on an arduino, set the second one up (or both of them) using the software serial library (http://arduino.cc/en/Reference/SoftwareSerial). then you can listen to both channels at the same time. you can keep the interrupt the same as step 9, just add another loop in there that listens to the second midi input. do you know how to proceed from there?
cezarsp1231 year ago
http://www.instructables.com/files/deriv/F8J/VPI5/HCJO5NRH/F8JVPI5HCJO5NRH.THUMB.jpgng--2
Hi Amanda
Congratulations on the publication of their work. I'm sure they inspire many people.
I play with my son ten years. He plays drums and I play electronic keyboard. I would like to put a third person in this group and it would be a bassist, but he would own the arduino. lol
Through midi cable, because the battery of my son's electronics.
My idea is as follows. when he touched the kick drum, the bass on my keyboard touch, but he would play the same note I'm playing. For example, my hand would be on the C note, my son would play 123 ... 123, bass keyboard touch C, C, C. .. C, C, C. If I touched the note G, the arduino would do the same thing, he would catch the rhythm of the drum of my son, and put the note in the middle of the sun from midi message.
I think the code of arduino should have a variable which would take note of my keyboard, and replace the bass drum note from my son (because the bass drum is always the same note, if I'm not mistaken is C2 or C3)
I looked at many sketches of arduinos midi, but there are so many bits and Bytes I got a little lost. I am a layman on the subject, but with your help I believe I can. And you can take this idea and create something through their creativity. Thank you.
Baixista virtual.pngBaixista virtual.pngBaixista virtual.pngBaixista virtual.png
amandaghassaei (author)  cezarsp1231 year ago
sounds great, so is it a MIDI drum or a regular drum that your son is using?
rad3d1 year ago
I'm using the Sparkfun MIDI Shield with this code and not getting MIDI input to work. MIDI out works fine, but not MIDI in. Pretty sure all my connections are good on the shield. Is there anything about the code in step 9 that should not work with this shield? Looks like it uses the same components.

I'm new to all of this so I'm not quite sure what I can check on MIDI In for continuity. I've noticed that testing Pin4 on my MIDI Out against the TX send tests fine, but none of the Pins on the MIDI in test against the RX pin. Not sure how the optocoupler affects basic continuity testing though.
amandaghassaei (author)  rad3d1 year ago
hi, sorry for the late reply, have you figured it out?
Mr_Teeth1 year ago
Brilliant Instructable, very inspiring!
jdevs1 year ago
Unfortunately, I do not at this time. Is there another way to debug?
amandaghassaei (author)  jdevs1 year ago
Yes, unfortunately. Recheck all the connections, check for continuity, if it still doesn't work then you'll have to use an oscilloscope.
jdevs1 year ago
First off, thank you for a wonderful MIDI-Arduino instructable. I have been working with the receive circuit set up as instructed (I've triple checked it) using my Arduino Duemilanove, UNO and sending MIDI messages with Reaper (PC).

I've been trying to get the MIDI note 60 (middle C) code working but no matter what I've tried, the circuit doesn't seem to receive a MIDI signal.

A couple of things I've tried for debugging:
- Changing the code to accept ANY MIDI message (removed noteByte == 60 && velocityByte > 0), no success.
- Tested digitalWrite(13,HIGH) in the main loop to test LED output, which worked.
amandaghassaei (author)  jdevs1 year ago
do you have an oscilloscope?
spacekit1 year ago
yes, it works fine with other MIDI cable in both ableton and max. When I connect USB-MIDI cable directly from my keyborad to ableton, it shows the name in ableton but MIDI message is not coming in. I think USB MIDI cable might not work in Windows 7. I will keep trying. Thank you:)
spacekit1 year ago
Hi again~

I am having a problem in sending MIDI message out Arduino to Live.
I see TX light flashing on Arduino and see USB2.0-MIDI port in Live.
When I open Max for Live in Live I receive the following messages.

midi_mme: error 7 opening midi input device USB2.0-MIDI
midi_mme: error 7 opening output device USB2.0-MIDI
midi_mme: error 7 opening output device MIDIOUT2 (USB2.0-MIDI)

Do you have any clue why there is an error message like this in Max?

Thank you in advance!
____________________________________________________
Arduino Uno
USB MIDI Cable Interface Adapter by Konix (HK) Technology Co.
Windows 7
Ableton Live 8
Max 5.1.9





amandaghassaei (author)  spacekit1 year ago
hi, have you connected other midi devices to max for live and have they worked? what happens if you try to send the midi directly into ableton?
11Point1 year ago
Hey first thank you for your amazing instructables. I wanto to ask a question.
I'm doing the same project to receive midi message with arduino, the things is that I send the midi message through an xbee connected to a midi jack that send midi message through my laptop, and the 2 xbee receive the midi message and send it to the lilypad arduino. So in that case the optocupler has to be connected between the lilypad arduino and the 2nd xbee or between the jack midi and the 1xbee, thqt send the signals??

thanks ;)
Pro

Get More Out of Instructables

Already have an Account?

close

PDF Downloads
As a Pro member, you will gain access to download any Instructable in the PDF format. You also have the ability to customize your PDF download.

Upgrade to Pro today!