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.

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:


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.

<p>Hello<br><br>I'm trying to do a laser harp using midi. But I always sound ! Could someone help me find the error in the code? Thanks</p>
<p>Hi,<br>I have made a harp like you... send me message to talk...</p>
<p>Hello,</p><p>I'm trying to receive MIDI notes from an Axiom 49 keyboard using your tutorial and exact resistor values, but nothing comes out when i try the middle C (only &quot;-1&quot;).<br><br></p>
<p>Only difference is the baud rate that i tried to set to 19200, 38400, 57600 instead of 31250.</p>
<p>Hello<br><br>I'm trying to do a laser harp using midi. But I always sound ! Could someone help me find the error in the code? Thanks</p>
<p>Hello<br><br>I'm trying to do a laser harp using midi. But I always sound ! Could someone help me find the error in the code? Thanks</p>
<p>Hi im trying to receive midi to control solenoids, so ive it set up exactly as its shown but when i play a file the led wont blink, im using cubase to play the files. Im just wondering if theres some sort of setup im mssing? Thanks</p>
Why do the other tutorials use optocouplers and you don't? Can I use this with a drum machine
I do use an optocoupler to receive MIDI. This will work with anything that sends or receives MIDI.
<p>Ah! Thank you so much for the response, didn't see the last part. Can note on and note off be used as clock signals as well to send to drum machines etc?</p>
Or is it computer only *
<p>Hello Amanda! Thank you for the tutorial!! I have a question about step 10. Everything works great. I can turn the LED on with a midi note. But what if I want to turn it off with the same note? And what if I want to do it permanently but not once. I mean how can I make some kind of switch out of that note? What should I add to the code or how it should be transformed? Thank you! </p>
<p>What software are you using to send the MIDI?</p>
<p>Hi! I use Cubase.</p>
<p>Hello! Im very interested in this tutorial. I want to receive MIDI with the Arduino, but you don't say anything about how to send it from the Computer. Do you know any Software that can send MIDI songs to the Arduino? I'm really having a headache with this point.</p><p>Thanks!</p>
<p>Hi, thank you for this instructable. You 're talking in step 10 about using timers of the arduino if we care about timing. Would it be a good solution to use external interrupt?</p><p>Thanks again.</p>
<p>Hi, great Instructable thank you. Has anyone done anywork on reading USB class compliant devices as these are quite predominant in the market. I was interested in terms of Midi note remapping. I can do this easily in Max but it would be great to have a standalone USB device. Thanks</p>
<p>Hello again! I changed your code a bit to turn one LED on/off with the exact midi notes. Everything works except one thing the led sometimes doesn't want to go off. And besides nothing works without the &quot;delay&quot; in the loop. I'm an arduino beginner. If you please could you say what I did wrong? Thank you! </p><p>byte commandByte;</p><p>byte noteByte;</p><p>byte velocityByte;</p><p>byte noteOn = 10010000;</p><p>void setup(){</p><p> Serial.begin(115200);</p><p> pinMode(12,OUTPUT);</p><p> }</p><p>void checkMIDI(){</p><p> if (Serial.available()){</p><p> commandByte = Serial.read();</p><p> noteByte = Serial.read();</p><p> velocityByte = Serial.read();</p><p> if (commandByte == noteOn){</p><p> if (noteByte == 95 &amp;&amp; velocityByte &gt; 0){</p><p> digitalWrite(12,HIGH);//turn on led</p><p>}</p><p>}</p><p> if (commandByte == noteOn){</p><p> if (noteByte == 93 &amp;&amp; velocityByte &gt; 0){</p><p> digitalWrite(12,LOW);</p><p>} </p><p>}</p><p>}</p><p>} </p><p>void loop()</p><p>{</p><p> checkMIDI();</p><p> delay(1);</p><p>}</p>
<p>Hi, great tutorial! I've been making midi controllers for a while, but just with midi out, now I want to have som feedback from the software. I've made a controllers with a couple encoders and what I want to do is to update the cc value of the encoders when I play in the knobs in the software. any clue on how to do? Thanks!</p>
<p>Thanks for the great 'ible.</p><p><iframe allowfullscreen="" frameborder="0" height="281" src="//www.youtube.com/embed/wUUEu4H2_tE" width="500"></iframe></p><p>Do you know how to do something like this. I basically want to be able to read midi files from the Arduino and connect it to a MIDI device. I'm planning (if this is possible!) to have LEDs which light up when a specific note is played - it could also display the MIDI velocity by changing its brightness with PWM.</p>
<p>Hi there,</p><p>Have a look at this device you can get for 91 euros : the Midilektor.</p><p><a href="http://www.orgautomatech.com/epages/3b85d6ba-28b0-11e2-b53b-000d609a287c.sf/en_GB/?ObjectPath=/Shops/3b85d6ba-28b0-11e2-b53b-000d609a287c/Products/Midilec" rel="nofollow">http://www.orgautomatech.com/epages/3b85d6ba-28b0-...</a></p><p>I've bought is 5 years ago, and , combined with a midi decoder from the same provider, it works perfectly on a street organ .</p><p>Jean-Paul </p>
<p>congratulations for detailed instructable I could make my MIDI OUT and MIDI IN connections thanks to the tutorial, the MIDI OUT connection could first since the MIDI IN messed up enough, first mistake was to connect the MIDI input to the contrary (pin 2 to pin 4 and pin 4 on pin 2), the second was the diode, called the entrance 4 6N139 to inves entry 3, the third and final error was carrying coding in arduino with zero connected pin, gave several errors ... Finally I watched one toturial to set the MIDI OUT on the fruit loops and is now running smoothly ... once again, thank you! I am Brazilian and I'm using google translator, sorry for the grammatical errors ...</p>
<p>The &quot;Receive MIDI Messages&quot; diagram is incorrect, and does not match the picture of the board. The MIDI jack wires should go to the opposite IC pins as shown in the diagram. Took me a while to figure this out.</p>
<div>when I try to use the MIDI Hairless and try to connect with the port of arduino, the error &quot;this application has Requested the Runtime to terminate it in an unusual way&quot; shows how I can fix this?</div>
<p>Hi, I realize this is an old thread, but I am having the same issue. How did you resolve it?</p>
<p>Hi Amanda,</p><p>Great Tutorial. However when it comes to Electronics my knowledge is limited at best. I was wondering whether you would mind further explaining the use of the optocoupler for receiving data... If I could understand WHY we use it the rest will become clearer to me. Many Thanks. Chris</p>
<p>hey, sorry for the late reply. <a target="_blank" href="http://www.midi.org/techspecs/electrispec.phphttps://en.wikipedia.org/wiki/Opto-isolator">Optocouplers</a> isolate circuits from each other by using light to transmit data instead of voltage. This can be useful if two circuits need to communicate with each other and they use different voltages to transmit data signals (eg 5V vs 3.3V logic). In this case it's not a voltage difference, I think the optocoupler is there to protect from current spikes. It is required in the <a target="_blank" href="http://www.midi.org/techspecs/electrispec.phphttps://en.wikipedia.org/wiki/Opto-isolator">specs</a>.</p>
The optocoupler provides electrical insulation between equipments. This avoids several problems that plague audio devices, like ground loops and hum pickup.
<p>Hi Amanda!</p><p>I think your phrase: </p><p>&quot;The last half of the command byte sets the MIDI channel. All the bytes <br>listed above would be in channel 0, command bytes ending in 0001 would <br>be for MIDI channel 1, and so on.&quot;</p><p>is not exact, because in 4 bits values go from 0 to 15. So a byte ending 0001 means 2. </p>
<p>Hi your tutorial is very usefull :-)</p><p>I just have a probleme. I tried you receive and check midi if note = 60 and it work. So i decided to modify it to light up 8 led when i play on my midi keyboard. So i made this programme but it does'nt work. </p><p>/*<br>By Amanda Ghassaei<br>July 2012<br><a href="http://www.instructables.com/id/Send-and-Receive-MIDI-with-Arduino/" rel="nofollow">http://www.instructables.com/id/Send-and-Receive-M...</a><br><br><br>*/<br><br>byte commandByte;<br>byte noteByte;<br>byte velocityByte;<br><br>byte noteOn = 144;<br><br><br>void setup(){<br> <br> Serial.begin(56000);<br> pinMode(13,OUTPUT);<br> pinMode(12,OUTPUT);<br> pinMode(11,OUTPUT);<br> <br> digitalWrite(13,LOW);<br> digitalWrite(12,LOW);<br> digitalWrite(11,LOW);<br> <br>}<br><br>void directblink13(){<br> digitalWrite(13,HIGH);//turn on led<br> delay(1000);<br> digitalWrite(13,LOW);<br> }<br>void directblink12(){<br> digitalWrite(12,HIGH);//turn on led<br> delay(1000);<br> digitalWrite(12,LOW);<br> }<br>void directblink11(){ <br> digitalWrite(11,HIGH);<br> delay(1000);<br> digitalWrite(11,LOW); <br> }<br><br>void checkMIDI(){<br> do{<br> if (Serial.available()){<br> commandByte = Serial.read();//read first byte<br> noteByte = Serial.read();//read next byte<br> velocityByte = Serial.read();//read final byte<br> if (commandByte == noteOn){//if note on message<br> //check if note == 60 and velocity &gt; 0<br> if (noteByte == 60 &amp;&amp; velocityByte &gt; 0){directblink13;}<br> <br> else if(noteByte == 61 &amp;&amp; velocityByte &gt; 0){directblink12;}<br> <br> else if(noteByte == 62 &amp;&amp; velocityByte &gt; 0){ directblink12;}<br> }<br> <br> <br> <br> }<br> <br> }<br> while (Serial.available() &gt; 2);//when at least three bytes available<br>}<br> <br><br>void loop(){<br> checkMIDI();<br> delay(1);<br><br>}</p><p>Thanks :-)</p>
<p>When you're calling your directblink functions, you're forgetting to add ()</p><p>So a call should be: directblink12();</p>
<p>Hey Amanda. I've written some very simple code that receives MIDI and turns on some LEDs via the pwm. I'm receiving the messages via Hairless so no need for the external MIDI wirings.</p><p>For some reason the program will only work when there is a short delay of minimum 4ms after the checkMIDI() function is called. If there is no delay, the LEDs dont light up. The only problem is, this causes some messages to be missed. Any idea why? </p><p>Below is the code:</p><p>byte commandByte;</p><p>byte secondByte;</p><p>byte thirdByte;</p><p>byte noteOn = 144;</p><p>byte noteOff = 128;</p><p>byte pitchBend = 224;</p><p>int pwmVal;</p><p>void setup()</p><p>{</p><p> Serial.begin(9600);</p><p> pinMode(3,OUTPUT);</p><p>}</p><p>void checkMIDI()</p><p>{</p><p> do</p><p> {</p><p> if (Serial.available())</p><p> {</p><p> commandByte = Serial.read();//read command byte</p><p> secondByte = Serial.read();//read next byte (MSB, or Note)</p><p> thirdByte = Serial.read();//read final byte (LSB or velocity)</p><p> if (commandByte == noteOn)</p><p> {</p><p> if (secondByte &gt; 0 &amp;&amp; thirdByte &gt; 0)</p><p> {</p><p> pwmVal = map(thirdByte,0,127,0,255);</p><p> analogWrite(3,pwmVal);//turn on led with velocity value</p><p> }</p><p> }</p><p> else if(commandByte == noteOff)</p><p> {</p><p> analogWrite(3,0);</p><p> }</p><p> }</p><p> }</p><p> while (Serial.available() &gt; 2);//when at least three bytes available</p><p>}</p><p>void loop()</p><p>{</p><p> checkMIDI();</p><p> delay(4);</p><p>}</p>
<p>Sorry, I conducted as your instructable and I found that midiout message can be received normally by hairless software. But it seemed that the midiin.maxpat didn't work as what presented in your video.</p><p>I am trying to figure out this problem. I am assuming that the problem occurs when hairless route message to MAX, but I don't know where goes wrong.</p>
<p>maybe try selecting another midi channel in hairless midi/max. There might be something called From/To MaxMSP</p>
<p>Hi Amanda, thanks for your extensive tutorial! I'm thinking of building a touch capacitative midi keyboard and am trying to figure out how to translate the amount of touch recieved to velocity of note. So &lt; touch &lt; volume. Just wondering if you could help me out. Thanks!</p>
<p>No problem. Read in touch data from an analog pin (number between 0-1023) then scale that number down to a number between 0-127 using the <a target="_blank" href="https://www.arduino.cc/en/reference/map">map</a> function. Then send that out as the velocity. You can start with the variable velocity code I wrote and modify it to use the touch velocity from your sensor.</p>
<p>Hey There!</p><p>I am currently working on this project and everything is working fine so far. Is there a big difference between an 6N138 and an 6N137 Optocoupler? Am I able to build Step10 with an 6N137 Optocoupler too? </p><p>By the way: <strong>Awesome </strong>tutorial!!!</p><p>Greetings from Germany ;)</p>
<p>I'm not sure. If the pin outs are the same and the basic specs (input/output voltage/current, etc) look the same and are withing range for the arduino it's worth it to try. Did you try it already?</p>
<p>Thank you for this great tutorial! I've tried the midi out and works perfectly, I even managed to have arduino play poliphony in my synth. I haven't tried the midi in because I don't have the octocoupler yet but in the meanwhile I've been having a look at the schematics and the photos and there's something I don't understand (I'm a just a beginner in arduino/electronics): in the schematics, the cable with the 220ohm resistor comes out from the octocoupler's pin 2, but in the photos the resistor is soldered to the yellow cable, which in turn comes from pin 3.</p><p>Should I solder the resistor to the yellow or the green cable? To which pins in the octocoupler should the yellow and green cable ba connected?</p><p>Many thanks! :-)</p>
<p>hey, I see where the confusion is coming from, but it's been so long I'm not sure. I would probably go with the schematic, did you find out which pin was correct?</p>
<p>Hi!<br>First of all, thank you for this great instructable!<br>I'm currently using MIDI as input on my Arduino Uno and use Arduino as output translator device. So basically I'm playing notes on Synthesizer, send them to Arduino using MIDI, and then play them using notes library. I'm also displaying notes, velocity and event on LCD, just to se what is going on there. <br>The main problem is that the whole thing is too slow. I don't know if this happens to you, but Arduino sometimes skips or doesn't even receive the note or any MIDI message if it is played too fast. For example, if I play a note and release it emediately, the Arduino receives the first message with velocity&gt;0, but misses the second message with velocity=0. <br>I tried to make it faster by removing notes or LCD library, but it was the same. Maybe the Serial is to slow in Arduino because it is Arduino softare? Any ideas?</p>
<p>Thank you for the elaborate tutorial.</p><p>But you didn't mention how to interface the midi software like garageband when the midi messages were sent out.</p><p>I know that hairless can help messages route to garageband, but I wonder how garageband behave when receiving the Noteon command? </p>
<p>Our project is slightly different, since we do MIDI over USB and then use Hairless and LoopMIDI to interface with Ableton, but if people are interested, the code is available here:</p><p><a href="http://stephane.thunus.org/SAE/arduino.htm" rel="nofollow">http://stephane.thunus.org/SAE/arduino.htm</a></p><p>It is not 100% finished and clean, but it works - sorry, the code is a further version than the video explanations - will be updated when the project is finished.</p>
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.
<p>Hello amanda I was looking at this programs you put in here, very interesting, and thanks for sharing them a lot of things i&acute;ve learn. I have a small question is their for example any free software for arduino that can receive the midi file (for example a midi version of beethovens 5th symphony intro) and just read the notes as they came from the midi file and then to the arduino board keeping the same duration &quot;as the intro of the symphony is&quot;. For example if I want to export each note from the midi and let several leds to play each single note.<br>Thanks a lot again for sharing this. Hope you have a great day</p>
<p>You could use fl studio demo it will let you export into an audio file (mp3, wav, etc...) but not save.</p>
<p>This Code below here from you doesn't work to me.<br>The Serial.read() only put values in commandByte, but not noteByte and velocityByte? I can be sure that commandByte is always bigger than 127 and the other values 0-127 can be noteByte or velocityByte?</p><p>ISR(TIMER2_COMPA_vect) {//checks for incoming midi every 128us<br> do{<br> if (Serial.available()){<br> commandByte = Serial.read();//read first byte<br> noteByte = Serial.read();//read next byte<br> velocityByte = Serial.read();//read final byte<br> }<br> }<br> while (Serial.available() &gt; 2);//when at least three bytes available<br>}</p>
Yes the command byte is always >127 and the note and velocity (or whatever other parameters come after the command are <= 127. This code can be really finicky depending on your setup. Try removing the > 2 in the code able and see if it helps. You might want to add some additional logic to be sure that the command byte is set correctly (check if it is > 127)<br />
<p>First of all, many thanks for this awesome tutorial! It really helped me a lot. </p><p>Unfortunately, I'm having the same problem. Removing &gt;2 doesn't seem to help. With additional logic, I've discovered that noteByte reads 255, no matter wich note I play.The commandByte, noteOn and noteOff are working fine.</p>

About This Instructable




Bio: I'm a grad student at the Center for Bits and Atoms at MIT Media Lab. Before that I worked at Instructables, writing code for ... More »
More by amandaghassaei:OTCA Metapixel - Conway's Game of Life"9 Degrees of Freedom" IMUTwitter Controlled Pet Feeder
Add instructable to: