8.2 MIDI spec / MIDI port
Next use the following spec and image to wire up a midi jack so we can send our MIDI serial data from the Arduino to a MIDI interface using a MIDI cable:

Thanks to ITP Physical Computing for the MIDI OUT schematic.

And finally copy, save, compile and upload the following code to your Arduino:
/*
* 7.1 Midi OUT controller
* roguescience.org
*
* digital pin 11 (OUTPUT/PWM) --> LED
* digital pin 2 (INPUT) <-- button
* analog pin 0 <-- pot
* tx1 <-- pin 5 (5 PIN DIN aka MIDI jack)
*
* Send a MIDI note when the button is pressed and sends MIDI
* CC data when a potentiometer is turned.
*/
int ledPin = 11; //choose the pin for the LED - needs to be (3,5,6,9,10, or 11)
int buttonPin = 2; //choose the input pin for a pushbutton
int potPin = 0; //choose the input pin for a potentometer
int buttonVal = 0; //variable for reading the button status
int buttonState = 0; //variable to hold the buttons current state
int bounceCheck = 0; //variable for debouncing
int potVal = 0; //variable for reading potentiometer value
int mappedPotVal = 0; //variable for holding remapped pot value
int prevPotVal = 0; //variable for storing our prev pot value
int THRESHOLD = 2; //threshold amount
void setup() {
pinMode(ledPin, OUTPUT); //declare LED as output
pinMode(buttonPin, INPUT); //declare pushbutton as input
Serial.begin(31250); //MIDI communicates at 31250 baud
}
void loop(){
buttonVal = digitalRead(buttonPin); //read input value from button
delay(10); //wait 10ms
bounceCheck = digitalRead(buttonPin); //check again
if(buttonVal == bounceCheck){ //if val is the same then not a bounce
if (buttonVal == HIGH && buttonState == 1) { //check if the input is HIGH
digitalWrite(ledPin, LOW); //turn LED OFF
midiOUT(0x90, 60, 0); //Note ON (CH 1), middle C, zero velocity turns note off
buttonState = 0;
}
if(buttonVal == LOW && buttonState == 0){
digitalWrite(ledPin, HIGH); //turn LED ON
midiOUT(0x90, 60, 127); //Note ON (CH 1), middle C, velocity 127
buttonState = 1;
}
}
potVal = analogRead(potPin); //read input from potentiometer
mappedPotVal = map(potVal, 0, 1023, 0, 127); //map value to 0-127
if(abs(mappedPotVal - prevPotVal) >= THRESHOLD){
midiOUT(0xB0, 7, mappedPotVal); //Control Change (Ch 1), Controller 7 - default control for volume.
digitalWrite(ledPin, HIGH);
prevPotVal = mappedPotVal;
}
else{
digitalWrite(ledPin, LOW);
}
}
void midiOUT(char command, char value1, char value2) {
Serial.print(command, BYTE);
Serial.print(value1, BYTE);
Serial.print(value2, BYTE);
}
To test this out we will hook it up to a MIDI interface connected to my computer and see if it can communicate with Garage Band.
Hi Justin,
Great series on building a MIDI controller with Arduino. There’s a bug in your code on this page. MIDI CC messages have a range of 0-127, so your call to the map function should be:
mappedPotVal = map(potVal, 0, 1023, 0, 127); //map value to 0-127
…instead of 0-255.
Also, though not 100% a bug, the datatype passed to your midiOUT() function should be byte, not char. While debugging the map() bug I added to midiOUT():
Serial.print(command, HEX);
Serial.print(command, DEC);
If command is a char and 0xB0 is pased in, 0xFFFFFFB0 is printed for the HEX and -80 for DEC, but if command is a byte, all is correct. I’m guessing that when BYTE is passed to Serial.print() the upper bits are masked. Since the data always has a range of byte, it just makes sense to keep everything a byte and not have any data conversion.
Jeff
Thanks Jeff! I’ve corrected the code. I think you are probably right about the unnecessary conversion - I’ll look into it.
cheers,
Justin
In the setup do you have to
pinMode(potPin, INPUT);
For the pot?
Hi Ben - the ANALOG pins on the Arduino are INPUT ONLY so the pin mode does not have to be specified. ANALOG OUTPUT is emulated using pulse width modulation (PWM) on a DIGITAL pin (which does need to be set to OUTPUT) - see section 4.1 for details i.e. http://roguescience.org/wordpress/?page_id=13
cheers,
Justin
Ah, I missed that page completely, thanks for the explanation, I appreciate it.