package jmsltestsuite; /** * open a MIDI output device and send it timestamped noteon's * If the device supports timestamped output, you will hear an ascending melody, * If not, you will hear a chord. * * Discovered that JavaSound MIDI using a JavaSound Synthesizer (soundbank) DOES support timestamped output under Windows * but not OSX * * Nick Didkovsky, Dec 3, 2017 * */ import java.awt.Dimension; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import javax.sound.midi.*; import javax.swing.JFrame; public class TestTimeStampedMidiOutput { boolean isInputDevice(MidiDevice midiDevice) { boolean isInputDevice = true; try { midiDevice.getTransmitter(); } catch (MidiUnavailableException e) { isInputDevice = false; } return isInputDevice; } boolean isOutputDevice(MidiDevice midiDevice) { boolean isOutputDevice = true; try { midiDevice.getReceiver(); } catch (MidiUnavailableException e) { isOutputDevice = false; } return isOutputDevice; } public void listMidiDevices() { System.out.println("Your MIDI Devices"); MidiDevice midiDevice = null; MidiDevice.Info[] infos = MidiSystem.getMidiDeviceInfo(); for (int i = 0; i < infos.length; i++) { try { midiDevice = MidiSystem.getMidiDevice(infos[i]); System.out.println(i + ") " + infos[i] + (isInputDevice(midiDevice) ? " INPUT" : "") + (isOutputDevice(midiDevice) ? " OUTPUT" : "")); } catch (MidiUnavailableException e) { System.out.println(midiDevice.getDeviceInfo().getName() + " " + e); } } } public void openPlayClose(int deviceIndex) throws MidiUnavailableException, InterruptedException, InvalidMidiDataException { MidiDevice dev = MidiSystem.getMidiDevice(MidiSystem.getMidiDeviceInfo()[deviceIndex]); System.out.println("opening [" + deviceIndex + "], \"" + dev.getDeviceInfo().getName() + "\""); dev.open(); long timeStampZero = dev.getMicrosecondPosition(); System.out.println("timeStampZero=" + timeStampZero + ", " + (timeStampZero == -1 ? " timestamped output NOT supported" : "timeStamped output IS supported")); System.out.println( "If timestamps NOT supported, you'll hear a chord cluster. if it is, you'll hear an ascending melody"); if (isOutputDevice(dev)) { long timeStamp = timeStampZero; ShortMessage msg = new ShortMessage(); for (int i = 0; i < 5; i++) { int pitch = 60 + 3 * i; msg.setMessage(ShortMessage.NOTE_ON, 1, pitch, 80); javax.sound.midi.Receiver rcvr = dev.getReceiver(); if (timeStamp != -1) timeStamp += 1000000 * 0.10; System.out.println("note_on. timeStamp=" + timeStamp); rcvr.send(msg, timeStamp); // Thread.sleep(200); msg.setMessage(ShortMessage.NOTE_ON, 1, pitch, 0); if (timeStamp != -1) timeStamp += 1000000 * 0.10; System.out.println("note_off. timeStamp=" + timeStamp); rcvr.send(msg, timeStamp); // Thread.sleep(200); } } Thread.sleep(2000); System.out.print("closing device..."); dev.close(); System.out.println("closed. "); } public static void main(String[] args) { JFrame jf = new JFrame("close to exit"); jf.setSize(new Dimension(200, 100)); jf.setVisible(true); jf.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent arg0) { System.exit(0); } }); TestTimeStampedMidiOutput test = new TestTimeStampedMidiOutput(); test.listMidiDevices(); // CHANGE ME TO AN OUTPUT DEVICE AFTER SEEING THE "Your MIDI Devices" // LISTING int deviceToTest = 0; try { for (int i = 0; i < 3; i++) { System.out.println("\n\n***** Trial " + (i + 1) + "*****"); test.openPlayClose(deviceToTest); Thread.sleep(1000); } System.out.println("done"); } catch (MidiUnavailableException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } catch (InvalidMidiDataException e) { e.printStackTrace(); } } }