Instructables
loading
loading
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

Picture of 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.
« Previous41-80 of 160Next »
if you want to send midi into a piece of hardware like a synthesizer, you will have to output at 31250, it's possible to send messages at other baud rates and then convert it to a midi signal in your comp, that's probably what's happening
http://spikenzielabs.com/SpikenzieLabs/Serial_MIDI.html
Use this link from Spikenzie Labs, which has a Serial <> MIDI sketch made in processing already set-up. It does have the correct baud rate for me, you just have to know which serial port to use, what device to output TO, and what device to input FROM

I'm thinking can I make my midi cotroller to cotrol any sound generator.

One idea is with PWM

MIDI controller -> Arduino -> PWM output -> analog output

X1L31 year ago
Thanks amanda. Appreciate the help. Really cool project and a brilliant and easy to grasp introduction to midi.
e.ma.niak1 year ago
I'm building my own midi controler, now i know how to handle incoming midi. Great instructable.
amandaghassaei (author)  e.ma.niak1 year ago

awesome!

X1L31 year ago
Hi. I'm just wondering how you'd go about filtering out unwantwd midi controler date. The project I've built with this works fine but any pitch/modwheel data etc freezes / unfreezes it. Is it a case of telling it to read these messages and then do nothing?
amandaghassaei (author)  X1L31 year ago

yes definitely, you should add an if statement that checks to the value of commandByte to see if it's what you want. commandByte = 144 is note on, you can find the rest of the commands here

Team3G1 year ago
The shake to clear feature is genius. Inspiration points++
jhenrique31 year ago
Hello, Amanda! Your projects are awesome :D I don't have an arduino yet, but I'm planning to use two of your instructables (Arduino Audio Output and Send and Receive MIDI with Arduino) and some other projects to modify a toy casio keyboard, so that I can control the arduino with the toy keyboard's keys or another keyboard to play some NES-like music. I would like to know if it is possible to change the pin where the arduino receives MIDI data, because the D0 pin of the arduino is already used in the Arduino Audio Output project, as I plan to do these projects with a single arduino. Thanks in advance.
It is not possible to change the MIDI send/receive pins because MID requires serial data and pin D0 is the serial receive while pin D1 is the serial transmit pin. If you need more than one serial TX/RX pin, I would recommend and Arduino MEGA 2560, which has 4 of each.
amandaghassaei (author)  kipfan231 year ago
actually, you can use software serial to change the Serial outs.
Very clear explanation. Excellent work! Great!
soeren1 year ago
Hi Paulsoulsby

I'm really having issues getting midi input as well. I've tried many different setups and opto couplers, including this exact instructable - without luck.

I tried your code, but you haven't defined NOTE_ON, NOTE_OFF, PITCH_WHEEL and CONTROLLER anywhere. What did you intend to put into these variables, or are they #define instructions that you forgot to include here?

all the best
Søren
amandaghassaei (author)  soeren1 year ago
I updated my code, I made a little typo with serial.available(), I'm curious to see if it works for you now, does it?
amandaghassaei (author)  soeren1 year ago
hey, Paulsoulsby won't get your comment unless you reply to them directly. I'm sorry this MIDI input issue has been causing you trouble, I had some trouble getting my input circuit to work at first too. Do you have an oscilloscope? I found that really helpful in figuring out where the problem was.
pulykamell1 year ago
Doesn't Serial.available() return the number of bytes and not bits in the serial buffer? Could that be the issue for folks here?

I got it to work from the schematic, but I had my yellow and green wires flipped around initially. Once I flipped those and changed around the code, it worked fine. Also, there is an issue with "running status" as some MIDI devices, to save data, will not resend the command byte if the last command is the same. For example, on my keyboard, if I hit G then C quickly, the bytes sent will look like: 144, 55, 70, 60, 70, with the 144 only being sent the first time, so you have to watch out if you're reading in threes. I'll try to post the code I got working later, as I have it currently set to output MIDI data onto an LCD screen (which helps for diagnosing this stuff.)
amandaghassaei (author)  pulykamell1 year ago
good catch, I'll update the code to reflect that
Hi Amanda,

Referring to step 9. I understand that digital pin 0 (RX0) must be disconnected when uploading program to Arduino via USB cable.

After uploading the program to arduino, pin 0 (RX0) will be reconnected to receive input from MIDI jack. Can I also reconnect the USB cable to power the arduino? Or do I have to power the arduino using external power source such as battery pack?

Thanks and regards,
electronicrookie
I think you can keep the usb plugged in w/o a problem, have you tried?
kylehlogan2 years ago
I'm really interested in doing something that requires the tempo from another device via MIDI In but I didn't see anything pertaining to tempo in the article. I know you can send tempo map information via MIDI, but how would you do it via Arduino?
amandaghassaei (author)  kylehlogan2 years ago
you might want to incorporate this into your setup:
http://en.wikipedia.org/wiki/MIDI_beat_clock
scroll down to the "system real-time messages" in this table:
http://www.midi.org/techspecs/midimessages.php
you just need to check to see what type of messages you are receiving with the midi in, if they are equal to 11111000, then you know it is a timing clock message and you can have this modulate the timing of your midi out. does that make sense?
I'm planning on making a real proper midi controller for ableton soon. Its going to be an arcade style controller, I've never built something like this besides a ghetto "sequencer" for ableton i made which is based on a keyboard encoder. Any tips for me?
amandaghassaei (author)  mastermakoko2 years ago
breadboard everything first, and if you're feeling ambitious, multiplexing your buttons will allow you to connect more stuff to the arduino.
paulsoulsby2 years ago
Hi,
Thanks for this instructable.  It's been really handy.  I had problems with the MIDI input, with some MIDI devices.  I discovered that this was to do with MIDI active sensing.  Here's my code for reading the MIDI port that takes into account for MIDI active sensing.

byte incomingByte=0;
byte notebyte=0;
byte velocitybyte=0;
byte statusbuffer=0;
boolean arp_triggernext=false;
boolean firstbyte;
void MIDI_Poll(){
  if (Serial.available() > 0) {
    do {
      // read the incoming byte:
      incomingByte = Serial.read();
      if (incomingByte>247) {
        // this is where MIDI clock stuff is done
        switch (incomingByte){
        }
      }
      else if (incomingByte>240) {
        statusbuffer = 0;
        //sysex stuff done here
      }
      else if (incomingByte>127) {
        statusbuffer = incomingByte;
        firstbyte = true;
        notebyte = 0;
        velocitybyte = 0;
      }
      else if (statusbuffer!=0) {
        if (firstbyte == true) {
          // must be first byte
          notebyte = incomingByte;
          firstbyte = false;
        }
        else {
          // so must be second byte then
          velocitybyte = incomingByte;
          //process the message here
          if (statusbuffer == NOTE_ON && velocitybyte != 0) {
            //MIDI note on subroutine
          }
          else if (statusbuffer == NOTE_OFF || (statusbuffer == NOTE_ON && velocitybyte == 0)) {
            //MIDI note off subroutine
          }
          else if (statusbuffer == PITCH_WHEEL){
             //pitch bend wheel
          }
          else if (statusbuffer == CONTROLLER){
            if (notebyte==1) {
              //MIDI_modwheel_level = velocitybyte;
            }
          }
          //now clear them for next note
          notebyte = 0;
          velocitybyte = 0;
          firstbyte = true;        
        }
      }
    } while (Serial.available() > 0);
  }
}
amandaghassaei (author)  paulsoulsby2 years ago
that's really interesting! thanks for sharing.
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)  museumoftechno2 years 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!
spacekit2 years 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)  spacekit2 years 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?
cezarsp1232 years 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)  cezarsp1232 years 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)  amandaghassaei2 years 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)  cezarsp1232 years 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!
enomys732 years 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)  enomys732 years 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.
amandaghassaei (author)  canada13records2 years ago
did you read step 9?
« Previous41-80 of 160Next »