Question

I've inherited a Java project that used an old C++ dll to receive MIDI data from a piano connected to the computer.

Now that Java has built-in support for MIDI devices, I want to get rid of the legacy C++ dll and just use pure Java. Does Java support receiving data from a piano connected to the computer? I've searched Google for examples to no avail.

Was it helpful?

Solution

Yes, the JavaSound API can be used to read MIDI data from a MIDI device.

JFugue is a Java API for music programming that uses the JavaSound API, and can help simplify your interaction with JavaSound. In JFugue 5.x, sample code to capture 10 seconds of MIDI data from a MIDI device is as follows:

MidiDevice device = /* specify a MIDI device */
MusicTransmitterToSequence transmitter = new MusicTransmitterToSequence(device); 
transmitter.listenForMillis(10000); 
Sequence music = transmitter.getSequence();

You can also start and stop listening to a device:

MidiDevice device = /* specify a MIDI device */
MusicTransmitterToSequence transmitter = new MusicTransmitterToSequence(device); 
transmitter.startListening(); 
// Do stuff
transmitter.stopListening(); 
Sequence music = transmitter.getSequence();

OTHER TIPS

If you want to record with just the MIDI api by Java (javax.sound.midi.*) this is done very easily. This is not code to copy and paste, but it should help you to start programming your own MIDI recorder, which is quite easy actually.

The first step is to define your input and output MidiDevice. So first you will have to find a list of IO possibilities and make a GUI in which you can select the input and output device for your MIDI recording and playback.

Info[] infos = MidiSystem.getMidiDeviceInfo();
for(int i=0;i<infos.length;i++)
{
    System.out.println(infos[i].getName() + " - " + infos[i].getDescription());
}

So there is a list of your MIDI devices. Next you want to select a MIDI device, for example you get to choose the indexes in the infos array.

MidiDevice inputDevice = MidiSystem.getMidiDevice(infos[x]);
MidiDevice outputDevice = MidiSystem.getMidiDevice(infos[y]);

You also will want to specify some globals: sequencer, transmitter and receiver.

Sequencer sequencer = MidiSystem.getSequencer();
Transmitter transmitter;
Receiver receiver;

Now there is a record button you want to use.

// Open a connection to your input device
inputDevice.open();
// Open a connection to the default sequencer (as specified by MidiSystem)
sequencer.open();
// Get the transmitter class from your input device
transmitter = inputDevice.getTransmitter();
// Get the receiver class from your sequencer
receiver = sequencer.getReceiver();
// Bind the transmitter to the receiver so the receiver gets input from the transmitter
transmitter.setReceiver(receiver);

// Create a new sequence
Sequence seq = new Sequence(Sequence.PPQ, 24);
// And of course a track to record the input on
Track currentTrack = seq.createTrack();
// Do some sequencer settings
sequencer.setSequence(seq);
sequencer.setTickPosition(0);
sequencer.recordEnable(currentTrack, -1);
// And start recording
sequencer.startRecording();

Beware, this code can throw MidiUnavailableExceptions and you should call the close methods on all the things you've opened in a finally statement.

But this is just the core of what the code should look like. It records everything to the Sequence seq as soon as you call the method sequencer.startRecording().

Then you want to stop the recording, and be able to save the sequence as MIDI to a file, or do a playback. For example this could be code when you press the Stop record button or something.

// Stop recording
if(sequencer.isRecording())
{
    // Tell sequencer to stop recording
    sequencer.stopRecording();

    // Retrieve the sequence containing the stuff you played on the MIDI instrument
    Sequence tmp = sequencer.getSequence();

    // Save to file
    MidiSystem.write(tmp, 0, new File("MyMidiFile.mid"));
}

Also the Track class (a sequence can have multiple tracks) contains the actual input data, which you can easily access by a get method. The Track class consists of MidiEvents. For example the Track is:

MidiEvent 0: The C key is pressed
MidiEvent 1: The D key is pressed
MidiEvent 2: The C key of MidiEvent 0 is released
MidiEvent 3: The sustain pedal is pressed
etc...

And every MidiEvent has a certain timestamp, which is expressed in MIDI Ticks, thus you can easily change the tempo by increasing or decreasing the number of ticks per second.

The hardest problem here is that MidiEvents are expressed in byte code, thus you will have to use a reference byte code sheet which tells you what byte represents what action. This should get you started with that: http://www.onicos.com/staff/iz/formats/midi-event.html

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top