MIDI Library

Hey. one question: how can i make arduino read and write MIDI messages directly from USB UART?

it is useless to have a midi library if you can't send and receive midi over USB. I mean it's quite important! for example if i want to control Ableton Live or a virtual instrument on the PC,
or if i want arduino to behave as a synthethiser (a midi SLAVE) and use the PC as a midi MASTER.

i know that 31250 bps, which is the midi baudrate , isn't ok for the RS-232 serial protocol (which is the one working on USB right?)

but if you google Serial to midi converter, it will show you a program written in processing (thus Java) which handles midi over usb. it uses a finite state machine to emulate a 31250 bauderate with an actual 57600 bps. the link is here.Serial_MIDI

can anyone please help about this?
for now i manage to receive midi from serial with the function MIDI.read() of your library (it turns on a led when this happens)
but it doesn't seem to reckognize the TYPE (status byte) as I use MIDI.getType() function

I'm using arduino and MIDI for my thesis project but i'm really stuck at this point.

here's my arduino code for now:

#include <MIDI.h>
#include <stdio.h>//printf
#include <math.h>//pow
//MIDI REVEALER FROM MIDIYOKE 1, CHANNEL 1

#define LED 2
#define LED_PWM 6
#define BUTTON 5
#define BUZ 9

int decay=500;
float midivec[128];
int buttonState = 0;
int a = 440; // tono fondamentale 440 hz...

void setup() {
  pinMode(LED, OUTPUT);
  pinMode(LED_PWM, OUTPUT);
  pinMode(BUTTON, INPUT);
  pinMode(BUZ, OUTPUT);
  MIDI.begin();                  // Launch MIDI with default options (input channel 1)
  // with MIDI_CHANNEL_OMNI input channel is set to all

//p = 69 + 12 × log2 (f/(440 Hz)), dove con p si denota il pitch (0-127) ossia il valore della nota midi.
//--> f = 440*2^((p-69)/12)
  for (int x = 0; x < 128; x++)   //CALCULATE ALL MIDI FREQUENCIES (midi number (pitch) to frequency converter) 
  {
    midivec[x] = a * pow(2, ((x - 69) / 12));
  }

}

void loop() {
  digitalWrite(LED,HIGH);
  if (MIDI.read()) {
    digitalWrite(LED,LOW);
    if (MIDI.getType()==NoteOn)
    {
        playMidiNote(MIDI.getData1(), MIDI.getData2());//pitch, velocity
        analogWrite(LED_PWM,MIDI.getData2());
        delay(500);
    }
    if (MIDI.getType()==NoteOff)
    {
        playMidiNote(MIDI.getData1(), MIDI.getData2());//pitch, velocity
        digitalWrite(LED_PWM,LOW);
        delay(500);
    }                // Suona la frequenza corrispondente alla nota midi 
     delay(500);         
  }
}

//PLAYS A TONE (given the frequency and the intensity (velocity)) ON THE BUZZER
void playTone(int tone, int velocity) { //ho eliminato la durata INT duration
  //for (long i = 0; i < duration * 1000L; i += tone * 2) {
    analogWrite(BUZ, velocity*2); //128*2 = 256 --> PWM a 8 bit
    delayMicroseconds(tone);
    digitalWrite(BUZ, LOW);
    delayMicroseconds(tone);
 // }
}

//PLAYS A MIDI NOTE given the MIDI VALUE (or number, or pitch) and ITS VELOCITY
void playMidiNote(int midi_val, int velocity){
      playTone(midivec[midi_val], velocity);
}

Hello Giacomo,

Yes, you can do that, and you might have nothing much to do, as the classic Arduino has only one serial port, used both for programming and serial communications within your sketch.

The lib uses this serial port, at the MIDI baudrate 31250, to communicate with whatever is plugged on the other side (MIDI devices if you connect RxTx to MIDI DIN plugs, or computer via USB). The RS-232 norm is compliant with a lot of baudrates, including 31250.

This thing you linked, the Serial to MIDI converter, is a software solution for creating virtual MIDI ports in your computer, a bit like MIDI Yoke. But the main (real) MIDI stream ends up in the serial port of your Arduino (on which the library runs). You can combine these software to get a powerful MIDI configuration.

For example, if you want to control Live with a keyboard (thru the Arduino used for filtering), you will need the keyboard to be plugged into the Rx port of the Arduino, and the Tx to go to the computer (through the USB cable or another MIDI cable).

About your code, I don't see any mistake, assuming your tone function works. However, there is a trick about NoteOff: there are two ways of killing a note: sending a NoteOff message OR sending a NoteOn with the same note number and velocity set to 0.

A piece of advice: I see a MIDI note number to frequency converter loop, as this shall not change inside the Arduino, you can calculate it on a computer and use a PROGMEM array (saves RAM and boot time).

If you have a chip with more than one Serial UART (like the Mega or the Sanguino), you can change the Serial port used for MIDI communications in MIDI.cpp, line 16. USB (programming) Serial UART number is 0).

@DARRELL:

You need to know which kind of message to send for your mixing table to recognise a Start command, it should be written in its manual (MIDI Implementation or something like that).

Have you tried to receive MIDI messages from the PC to the arduino via USB?

on the MidiToSerial converter FAQ it sais to set the baud rate to 57600 (not 31250 which is the MIDI standard) but then it gives even 31250 as an option, anyway, when i set it up with midi yoke, and ableton live sending midi to midi yoke, and then to Arduino, it dosn't work at all.

in practice, if i want to send a midi message over the serial, what i need to do is to send a status byte, and 2 data bytes, right?
do i have to send even start and stop bits or the UART chip handles that?

as you said the code looks fine. the PlayTone function works but i can't detect the midi, as i use MIDI.getType() when i send a noteOn or noteOff midi message it doesn't get it.

thanks for your quick reply

ps: are you sure that FTDI UART chip (FT232RL) operates at 31250 bps?

http://www.megadrum.info/forums/viewtopic.php?f=6&t=94

here it looks like it gives problems. i don't know, does anyone have a working MIDI-USB device (controller or synth) interfaced to the PC?

Ok solved sending midi over usb at 57600 bps.
i think the midi baudrate doesn't ivolve usb communication.
or at least that way is simplier.

just change the #define MIDI_BAUD line in MIDI.h and set it to 57600 (or other rs-232 baud rates) instead of 31250 if you want to send and receive MIDI via USB

As another user of the MIDI Library wanted to use directly the USB cable to be able to remotely control a software (such as Ableton Live, Cubase..), it seems to be time to sum things up.

  • The Arduino uses the UART for serial communications. As MIDI is a serial protocol, the library uses the Serial class in the Arduino core to send and receive messages.

  • For those whom board has more than one UART (Arduino Mega, Sanguino), you can select the one the library uses by changing
    #define UART Serial
    to
    #define UART Serial1
    or any Serial port number you want.

  • If you have a USB connector on your board, or if you are using a FTDI Cable, such as this one:

There is a chip between the UART and the USB cable that translates the logic levels and acts as a converter from Serial (UART) from/to USB, called the FT232-RL. It communicates with the USB driver in your Operating System, on your computer.

  • If you want to send MIDI over the USB cable to a computer, you will need 2 things:
  • As the FT232-RL declares itself as a "Communication Port", you will need to fool your OS to make it look like a MIDI device. Two ways to do that, reprogram the FT232-RL to make it answer like a MIDI device, or use a specific driver on the computer, that will capture data from the USB/Serial thing and create a virtual MIDI port you can use in a software.
  • Either way you choose, you will need to change the transmisson speed from 31250 (Classic MIDI) to 57600 (USB), so that your driver on the computer can sync with the messages you are sending.

Hello, I'm new here, and i was using Tom Scarff's older midi stuff for the arduino, but just found this, my project is to put in a simple logic switch into my amp, I have already programmed the arduino to read a 3 button momentary footswitch which it does flawlessly, but now i'm adding a reading midi function (In and Out), and want to use the midi.h library, and i have a couple of questions, firstly, the midi input pin is 0, RX, and send (or through) is 1, TX, is that correct?

secondly, would you be able to look over my code see if it makes sense?

#include <MIDI.h>
/*this version, remove 2N7000 and jump connections so arduino puts out a LOW signal to enable the channel (ground
x88 transistors) and HIGH to dissable
This build has been confirmed to work with the footswitch, as for MIDI functionality, still working on that one as of june 5th, 2010
June 6th 2010 - Midi communication is done through UART ports, RX and TX pins 0, and 1.

EN
Revision 05.06.10.001
Channel Switching Interface for X88 clone
Footswitch function working
*/

#define CH1 2 //Clean channel output pin
#define CH2 3 // Crunch channel output pin
#define CH3 4 // Lead channel output pin
#define Controller_Status 8 // pin that checks if rotary switch is on FS position
#define FSCH1 9 // Pin reading clean footswitch button
#define FSCH2 10 //Pin reading crunch footswitch button
#define FSCH3 11 // Pin reading lead footswitch button

byte switches[3] = {
  FSCH1, FSCH2, FSCH3 }; // this initializes the footswitch pins

byte switchState[3] = {
  HIGH, HIGH, HIGH }; // initializes footswitch pins to high to test of ground
  
void setup() {
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT); //sets switching pins as output
  pinMode(8, INPUT);
  pinMode(9, INPUT);
  pinMode(10, INPUT);
  pinMode(11, INPUT); // Sets reading pins to read
  digitalWrite(8, HIGH);
  digitalWrite(9, HIGH);
  digitalWrite(10, HIGH);
  digitalWrite(11, HIGH); // Sets reading pins to High
  MIDI.begin();
  MIDI.turnThruOn();
  int count;
}

void loop(){
  
int count;
  digitalWrite(2, HIGH);
  digitalWrite(3, HIGH);
  digitalWrite(4, HIGH); // sets switching pins to high, effectively turning all channels off when amp turns off on FS position
  
  while((digitalRead(8)== LOW)){ //program runs while rotary switch is on FS position

  for(count = 0; count < 3; count++){ 
    if((digitalRead(switches[count]) ==00 ) &&(switchState[count] == HIGH)) { // reads through FS pins to see if any are momentarily ground
      switch( count) {
            case 0: 
            digitalWrite(2, HIGH);
            digitalWrite(3, HIGH);
            digitalWrite(4, HIGH);
            digitalWrite(2, LOW);
            digitalWrite(9, HIGH);
            digitalWrite(8,HIGH); // for clean pin, turns off all channels, then turns clean on, resets reading pins
            break;
            case 1: 
            digitalWrite(2, HIGH);
            digitalWrite(3, HIGH);
            digitalWrite(4, HIGH);
            digitalWrite(3, LOW);
            digitalWrite(10, HIGH);
            digitalWrite(8,HIGH); // crunch case
            break;
            case 2: 
            digitalWrite(2, HIGH);
            digitalWrite(3, HIGH);
            digitalWrite(4, HIGH);
            digitalWrite(4, LOW);
            digitalWrite(11, HIGH);
            digitalWrite(8,HIGH); //lead case
            break;
      }
    }
    }
    // MIDI function goes here 
    MIDI.read();
    if(MIDI.getType() == PC ){ // Reads if MIDI is PC message, responds to PC 1, 2, 3
      switch(MIDI.getData1()){
            case 1: 
            digitalWrite(2, HIGH);
            digitalWrite(3, HIGH);
            digitalWrite(4, HIGH);
            digitalWrite(2, LOW);
            digitalWrite(9, HIGH);
            digitalWrite(8,HIGH); // for clean pin, turns off all channels, then turns clean on, resets reading pins
            break;
            case 2: 
            digitalWrite(2, HIGH);
            digitalWrite(3, HIGH);
            digitalWrite(4, HIGH);
            digitalWrite(3, LOW);
            digitalWrite(10, HIGH);
            digitalWrite(8,HIGH); // crunch case
            break;
            case 3: 
            digitalWrite(2, HIGH);
            digitalWrite(3, HIGH);
            digitalWrite(4, HIGH);
            digitalWrite(4, LOW);
            digitalWrite(11, HIGH);
            digitalWrite(8,HIGH); //lead case
            break;
      }
    }
if(MIDI.getType() == CC ){   // Reads if MIDI is CC message, responds to 1, 2, 3
      switch(MIDI.getData1()){
            case 1: 
            digitalWrite(2, HIGH);
            digitalWrite(3, HIGH);
            digitalWrite(4, HIGH);
            digitalWrite(2, LOW);
            digitalWrite(9, HIGH);
            digitalWrite(8,HIGH); // for clean pin, turns off all channels, then turns clean on, resets reading pins
            break;
            case 2: 
            digitalWrite(2, HIGH);
            digitalWrite(3, HIGH);
            digitalWrite(4, HIGH);
            digitalWrite(3, LOW);
            digitalWrite(10, HIGH);
            digitalWrite(8,HIGH); // crunch case
            break;
            case 3: 
            digitalWrite(2, HIGH);
            digitalWrite(3, HIGH);
            digitalWrite(4, HIGH);
            digitalWrite(4, LOW);
            digitalWrite(11, HIGH);
            digitalWrite(8,HIGH); //lead case
            break;
      }
    }
  } // end of program
  digitalWrite(8, HIGH);
  digitalWrite(2, HIGH);
  digitalWrite(3, HIGH);
  digitalWrite(4, HIGH); // resets all pins
 }

For the pins, you're right, RX is Midi In and TX is Midi out.

The aim of the MIDI.read() method is to be called a lot of times, very fast in a loop, so you won't miss any incoming message. In that loop , you can also check your footswitches states,

A few code tricks you could use:

  • You defined names for your pins, but did not use these defines in digitalWrites
  • I don't think it is necessary to write all the outputs for each case, most of the pins should already be in the right state.
  • You say your program will end after exiting the while loop, but as the Arduino's loop function is.. a loop, it will be called again (and mess up with your digitalWrites outside the while that will be called endlessly).

Remember: keep your loop fast, that's the key to a responsive device!

Good idea for a MIDI project though!

Thanks! Just wanted to make sure I got my coding right, under my program, the arduino should automatically send the midi thru with the MIDI.turnThruOn(), right? Also, if I leave the () empty that means all messages will be sent via channel 1? (and to change it I just place a number in the brackets?

Finally, in my program the arduino will check incoming PC and CC messages to see if it's 1,2,3 out of 127 and act correspondingly?

Thank you!

Actually, just by calling MIDI.begin(), you activate the Thru functionnality, there is no need to call turnThruOn later.

Every incoming message will be forwarded to the MIDI output, as is, without any modification. That means a message coming on channel N will be forwarded to channel N on MIDI out.

There are filters available for selecting which messages to forward:
MIDI_FILTER_OFF will turn thru off (nothing will be forwarded)
MIDI_FILTER_FULL will forward everything
MIDI_FILTER_CANAL will forward only messages that have the same channel as the input channel (default is 1) - You can see this one as a filter that forwards only messages intended to be received by the device running the library.
MIDI_FILTER_ANTICANAL is the exact opposite of the previous one, it will forward only messages that are not to be handled by the device (more useful imho).

These filters are configured using MIDI.setFilter, and the input channel using MIDI.setInputChannel.

Anyway, if you want to remap incoming messages to another channel, you might want to turn thru off (or on an appropriate filter mode) and implement your own remapping protocol (read -> get data -> send on another channel)

Hi,

I'm quite new to the arduino world,and i apologize already if i say something that doesn't make sense.

I'm trying to build a Mini sequencer with the arduino and i need to receive the master midi from the PC with Midi. (the sequencer will control different stuff in sequence with the IO port (not Midi note)

I get prob to use Midi library to get the midi clock.
the MIDI.getType() only know few "type" and not a midi clock.
I've searched where you defined theses type but didn't really find .. because you define them in midi.h like this :

#define NoteOff 0
/*! Message type Note On /
#define NoteOn 1
/
! Message type AfterTouch Poly */
#define ATPoly 2

but what i didn't understand is that noteOff is normally
0x80 Note-off
and after touch is :
0xA0 Aftertouch

That's why i didn't understant where the hex code of midi command are written ..

i've a little code that is working with midi clock and the hex code are defined :
byte midi_start = 0xfa;
byte midi_stop = 0xfc;
byte midi_clock = 0xf8;
byte midi_continue = 0xfb;

i know that my question seems to be stupid but i really don't understand how you make the relation between the data Command serial data and the type ..
Many thanks in advance. .

Nico

Hi,

So far, System messages like SysEx, RealTime clock and other kinds are not fully implemented in the library, only SysEx are recognized. Clock messages is a feature I have to add to the ToDo list for the version 3.

About the types, maybe an enum would have been better than several defines, but the reason for these values is that they do not hold any channel information:

0x90 is a NoteOn on channel 1, but if you decompose it in binary, you get 1001 0000, with the high nibble corresponding to the type of message (x001 = 1 = NoteOn) and the low corresponding to the channel.

Actually, the value 0x90 is recomposed by the library when sending a message, when you pass both the channel and the type as arguments.
On the other side, when receiving a message, 0x90 is parsed as a NoteOn message, and the channel is extracted so you can read one information at a time.

I will try to add Clock features when I have some time.

Hi,

Thanks for your reply.
Thanks for the explanation, it make sense.
I've looked into you library to find a way to add the midi clock but seems to be quite complicated.

Adding the midi clock support would be a great feature to sync to other midi devices.

Waiting for the new version :slight_smile:

Many thanks for your help and for your awesome library..
(i tried also the midiunio library but get only errors and it is difficult to use because of lack of documentation. )

Many thanks and regards,

Nicolas

Franky!

Thank you very much for the help! the library is amazing, I uploaded the program the other day and ran with with midi in and out, and today i threw the amp into my rig and looped the midi with a controller and an FX unit, and it works flawlessly!!! Thank you!!!!! :slight_smile:

Hi.
I may sound totally stupid, but I probably am - with coding in any way. It is just my first week dealing with Arduino and C.
So I think I need to use this library. But where I put this?

After downloading the library, unzip it to the libraries folder (arduino-00xx/hardware/libraries), then reboot the Arduino IDE or compile your sketch, it will compile the library.

I can not find any arduino/hardware/libraries on my mac OS X.

On Mac OS, it is hidden in the Arduino application:

Right-click on Arduino.app, "Show package content", then put the library folder in "Contents/Resources/Java/hardware/libraries"

Ah, yes java! thanks!
Actually ....Java/libraries

Hum no, ..Java/libraries is the libraries folder for the Java application (hosting the Arduino IDE). The MIDI library is an AVR library, so you need to put it in hardware/libraries, with the others (SoftwareSerial, EEPROM...)

Wow, its been 2 months already.
The most easy to use libraries is to put them into Sketch Folder/Libraries. You may need to create these folders where you want them to be(Documents).