A Java Interface to the OS/2 Real-Time MIDI Subsystem

From EDM2
Jump to: navigation, search

by Michael Minnick

The Java(tm) programming language provides the ability to call functions compiled natively for the host machine. One use for these "native methods" is to directly access operating system specific resources such as device drivers. This article presents a Java package that takes advantage of the ability to call native methods to allow Java applications to interact with the OS/2 Real-Time MIDI Subsystem.

What is the Real-Time MIDI Subsystem?

The OS/2 Real-Time MIDI Subsystem (RTMIDI) provides real-time (non-streaming) access to hardware devices that support the Musical Instrument Digital Interface (MIDI) protocol. RTMIDI can be used by games or other applications that need efficient access t o MIDI devices for playing and recording music. RTMIDI represents MIDI devices and the applications that access them as a network of "nodes" and their interconnections. The following RTMIDI concepts are important to the application programmer:

  • RTMIDI Classes represent the types of nodes that can be added to the network. The Application class is used for nodes that allow application code to send data to and receive data from the network. The Hardware class is used for nodes that send dat a to and receive data from hardware devices.
  • RTMIDI Instances represent the nodes in the network. Each instance is of a particular class (Application or Hardware). Hardware nodes interface directly to the hardware, and are created automatically by the RTMIDI subsystem.
  • RTMIDI Links are the connections between nodes. For example, an Application node might be linked to a Hardware node for sending MIDI data to a device.
  • RTMIDI Messages are the data (musical information) passed between nodes. Messages can be time stamped to control the timing and order of delivery to the device.

The Java RTMIDI Package

The RTMIDI package provides the Java programmer access to the RTMIDI subsystem through a few simple classes. These classes provide an essentially straight "pass through" to RTMIDI using native methods that access RTMIDI. The main classes are:

  • The RTMidi class is used to perform setup operations, timing, and error handling.
  • The RTMidiClass class is used to query the types of nodes in the network.
  • The RTMidiInstance class is used query existing nodes and create new Application nodes. Methods of this class allow the node to be enabled, disabled, and linked to other nodes. There also are methods to send and receive MIDI messages on the node.
  • The RTMidiLink class is used to query the network configuration.
  • The RTMidiMessage class encapsulates MIDI data and methods to operate on the data.

The following code snippet shows how to query the node network for the names of all RTMIDI Instances and add this information to a Java AWT List component for display in a GUI:

  import rtmidi.*;
  import java.awt.*;
  ...
  List dev = new List(6, false);
  RTMidiInstance[] a = RTMidiInstance.getInstances();
  for (int i = 0; i < a.length; i++)
     dev.addItem(instances[i].getName());

The demonstration application MidiInfo.class provided with the RTMIDI package uses similar code to query the network and display a text representation of the nodes in the network:

Midiinfo.gif

The following code snippet shows how to send a single MIDI message to a hardware node.

  import rtmidi.*;
  import java.awt.*;
  ...
  RTMidi.midiTimer(RTMidi.START_TIMER);
  // Enable the hardware node to receive messages
  hwNode.enable(RTMidiInstance.ENABLE_RECEIVE);
  // Link the application node to the hardware node
  appNode.addLink(hwNode, 0);
  // Create and send a note-on message,
  // channel=0, key=60, velocity=64
  RTMidiMessage msg = new RTMidiMessage(appNode);
  msg.setData(144+0, 60, 64, 0);
  msg.send();

The demonstration application MidiPlay.class uses similar code to present a series of buttons that cause MIDI note-on and note-off messages to be sent to a specified device:

Midiplay.gif

Interfacing to Native Methods from Java

The internals of the RTMIDI package provide an example of calling native methods from Java. Building a native interface requires the following steps:

  1. Write Java classes with methods that use the native keyword to indicate they are implemented outside of Java.
  2. Write the native implementation code in C or C++.
  3. Use the javah utility to create C headers and stub interface code.
  4. Compile and link the native code into a shared library (a DLL on OS/2).

When the Java class that contains the native method signatures is loaded, it in turn calls the Java system loader to load the implementation DLL. The following code snippet from the RTMIDI package shows a native method signature and the code necessary to load the DLL:

  package rtmidi;
  public class RTMidi
  { ...
     public static native int midiTimer(int flag);
  ...
     static { System.loadLibrary("jrtmidi"); }
  }

Package Contents and Availability

The OS/2 Java RTMIDI package is included on the Developer Connection CD-ROM. OS/2 Warp Version 4 is required to run the RTMIDI subsystem, along with an audio device driver and sound hardware that support RTMIDI. The current RTMIDI package has been tested under Java for OS/2 version 1.02.

The RTMIDI package includes Java and C native method source code, compiled class files, example application code, and full RTMIDI API documentation in HTML format.

Reprint Courtesy of International Business Machines Corporation, © International Business Machines Corporation