Florian Heer

Java

MIDI

MIDI support in Java exists since 1.5. It's main purpose for me is that I don't have to take care of any hardware interaction.It directly supports all simple commands such as playing a note or sending (and receiving) a controller value, but when it comes to SysEx messages, the support is naturally rather limited.

How to find the MIDI-device you want and how to use it

To open a MIDI device you need a javax.sound.midi.MidiDevice.Info object. This contains the information on a device. With it you can ask the system to give access to the device itself. I'll explain later how you get the correct devInfo object:
javax.sound.midi.MidiDevice midiOut = MidiSystem.getMidiDevice(devInfo);
In order to use it, it needs to be opened. And since we want to avoid unnecessary problems, check first, if it is already open:
if (!midiOut.isOpen()) midiOut.open();
Now you have an open MIDI-device, but you need to get either a Receiver or a Transmitter to use it. The first step to test if everything worked is to send data, so we need a Receiver - the object receives data from our program:
javax.sound.midi.Receiver midiRcvr = midiOut.getReceiver();
You're almost there. Everything that is passed to the receiver needs to be a javax.sound.midi.MidiMessage. There are three subclasses (MetaMessage, ShortMessage and SysexMessage) of which ShortMessage is the one to use for notes and controllers. To send a note to your MIDI equipment, construct a ShortMessage that switches a note on:
javax.sound.midi.ShortMessage msg = new ShortMessage();
msg.setMessage (ShortMessage.NOTE_ON, 0, 60, 80);
The parameters for a note-on message are channel, note-value and velocity. Channel ranges from 0-15, whereas 0 is MIDI channel 1, note- and velocity-values are between 0 and 127 (highest value of a signed byte).
We will now send the message, wait 2 seconds and turn the note off again:
midiRcvr.send(msg, -1);
try {
	Thread.wait(2000);
}
catch (InterruptedException ex) {}
msg.setMessage (ShortMessage.NOTE_OFF, 0, 60, 80);
midiRcvr.send(msg, -1);
... and that's how you send notes to a MIDI device. But where do you get the javax.sound.midi.MidiDevice.Info object?
You can ask the system to give you the list of all devices that are known:
javax.sound.midi.MidiDevice.Info[] infos = MidiSystem.getMidiDeviceInfo();
Let's print them for an overview:
for(Info currInfo : infos) {
	System.out.println(currInfo.getName());
}
I have an Edirol UA-25 which registers as two devices, one for the input and one for the output port, so my listing looks like this:
Gervill
EDIROL UA-25
Microsoft MIDI Mapper
Microsoft GS Wavetable SW Synth
EDIROL UA-25
Real Time Sequencer
This Edirol can transmit only on one device and receive only on the other. So you might need to find out which registered device you can use for what. So, let's print that information as well:
import javax.sound.midi.MidiDevice;
import javax.sound.midi.MidiDevice.Info;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.MidiUnavailableException;

public class ListDevices {
	public static void main(String[] args) {
		Info[] infos = MidiSystem.getMidiDeviceInfo();
		int i = 0;
		MidiDevice dev = null;
		for(Info currInfo : infos) {
			try {
				dev = MidiSystem.getMidiDevice(currInfo);
				System.out.println("Idx: " + i++ + " - " + currInfo.getName() 
						+ " Rec: " + dev.getMaxReceivers() + " Trans: " + dev.getMaxTransmitters());
			} catch (MidiUnavailableException e) {
				e.printStackTrace();
			}
		}
	}
}
On my system the listing is:
Idx: 0 - Gervill Rec: -1 Trans: 0
Idx: 1 - EDIROL UA-25 Rec: 0 Trans: -1
Idx: 2 - Microsoft MIDI Mapper Rec: -1 Trans: 0
Idx: 3 - Microsoft GS Wavetable SW Synth Rec: -1 Trans: 0
Idx: 4 - EDIROL UA-25 Rec: -1 Trans: 0
Idx: 5 - Real Time Sequencer Rec: -1 Trans: -1
The -1 that is returned means there is no limit to the receivers / transmitters you can ask for. Once you have identified which device can receive data from you, you can use that one to send data to. As I want to send to my Edirol, the missing code (see above) is:
Info[] infos = MidiSystem.getMidiDeviceInfo();
Info devInfo = infos[4];

Functioning example

You can download an example that employs the steps described above (source). On opening (double-click, or
java -jar midiexample.jar
or
java -cp midiexample.jar de.fhapp.jme.scrap.MidiExample
) you will see this screen:
"list" shows the mididevices registered in your system with their index. Enter the index for the device you want to use in the field "Device index" and press "Connect". Then select the values you want to send and press "Send note".
For more information take a look at the MIDI-FAQ at Java Sound Resources.