NoteWith version 5.0, the |
The Java Sound API offers a flexible model for MIDI system configuration, just as it does for configuration of the sampled-audio system. An implementation of the Java Sound API can itself provide different sorts of MIDI devices, and additional ones can be supplied by service providers and installed by users. You can write your program in such a way that it makes few assumptions about which specific MIDI devices are installed on the computer. Instead, the program can take advantage of the MIDI system's defaults, or it can allow the user to select from whatever devices happen to be available.
This section shows how your program can learn what MIDI resources have been installed, and how to get access to the desired ones. After you've accessed and opened the devices, you can connect them to each other, as discussed in the next chapter, "Transmitting and Receiving MIDI Messages."
The role of the
MidiSystem
class in the Java Sound API's MIDI package
is directly analogous to the role of AudioSystem
in
the sampled-audio package. MidiSystem
acts as a
clearinghouse for accessing the installed MIDI resources.
You can query the
MidiSystem
to learn what sorts of devices are
installed, and then you can iterate over the available devices and
obtain access to the desired ones. For example, an application
program might start out by asking the MidiSystem
what
synthesizers are available, and then display a list of them, from
which the user can select one. A simpler application program might
just use the system's default synthesizer.
The MidiSystem
class also provides methods for translating between MIDI files and
Sequences
. It can report the file format of a MIDI
file and can write files of different types.
An application program can
obtain the following resources from the
MidiSystem
:
MidiSystem
class's file-handling facilities are
discussed in Chapter 11, "Playing,
Recording, and Editing MIDI Sequences," and Chapter 12,
"Synthesizing Sound." To understand
how the MIDI system itself gets access to all these resources, see
Part III of this guide, "Service Provider Interfaces."
A typical MIDI application program that uses the Java Sound API begins by obtaining the devices it needs, which can consist of one or more sequencers, synthesizers, input ports, or output ports.
There is a default
synthesizer device, a default sequencer device, a default
transmitting device, and a default receiving device. The latter two
devices normally represent the MIDI input and output ports,
respectively, if there are any available on the system. (It's easy
to get confused about the directionality here. Think of the ports'
transmission or reception in relation to the software, not in
relation to any external physical devices connected to the physical
ports. A MIDI input port transmits data from an external
device to a Java Sound API Receiver
, and likewise a
MIDI output port receives data from a software object and
relays the data to an external device.)
A simple application program
might just use the default instead of exploring all the installed
devices. The MidiSystem
class includes the following
methods for retrieving default resources:
static Sequencer getSequencer() static Synthesizer getSynthesizer() static Receiver getReceiver() static Transmitter getTransmitter()
The first two of these
methods obtain the system's default sequencing and synthesis
resources, which either represent physical devices or are
implemented wholly in software. The getReceiver
method
obtains a Receiver
object that takes MIDI messages
sent to it and relays them to the default receiving device.
Similarly, the getTransmitter method obtains a Transmitter object
that can send MIDI messages to some receiver on behalf of the
default transmitting device.
Instead of using the default
devices, a more thorough approach is to select the desired devices
from the full set of devices that are installed on the system. An
application program can select the desired devices
programmatically, or it can display a list of available devices and
let the user select which ones to use. The MidiSystem
class provides a method for learning which devices are installed,
and a corresponding method to obtain a device of a given type.
Here is the method for learning about the installed devices:
static MidiDevice.Info[] getMidiDeviceInfo()
As you can see, it returns
an array of information objects. Each of these returned
MidiDevice.Info
objects identifies one type of
sequencer, synthesizer, port, or other device that is installed.
(Usually a system has at most one instance of a given type. For
example, a given model of synthesizer from a certain vendor will be
installed only once. ) The MidiDevice.Info
includes
the following strings to describe the device:
However, to use the strings programmatically to select a device (as opposed to displaying the strings to the user), you need to know in advance what they might be. The company that provides each device should include this information in its documentation. An application program that requires or prefers a particular device can use this information to locate that device. This approach has the drawback of limiting the program to device implementations that it knows about in advance.
Another, more general,
approach is to go ahead and iterate over the
MidiDevice.Info
objects, obtaining each corresponding
device, and determining programmatically whether it's suitable to
use (or at least suitable to include in a list from which the user
can choose). The next section describes how to do this.
Once an appropriate device's
info object is found, the application program invokes the following
MidiSystem
method to obtain the corresponding device
itself:
static MidiDevice getMidiDevice(MidiDevice.Info info)
You can use this method if
you've already found the info object describing the device you
need. However, if you can't interpret the info objects returned by
getMidiDeviceInfo
to determine which device you need,
and if you don't want to display information about all the devices
to the user, you might be able to do the following instead: Iterate
over all the MidiDevice.Info
objects returned by
getMidiDeviceInfo
, get the corresponding devices using
the method above, and test each device to see whether it's
suitable. In other words, you can query each device for its class
and its capabilities before including it in the list that you
display to the user, or as a way to decide upon a device
programmatically without involving the user. For example, if your
program needs a synthesizer, you can obtain each of the installed
devices, see which are instances of classes that implement the
Synthesizer
interface, and then display them in a list
from which the user can choose one, as follows:
// Obtain information about all the installed synthesizers. Vector synthInfos; MidiDevice device; MidiDevice.Info[] infos = MidiSystem.getMidiDeviceInfo(); for (int i = 0; i < infos.length; i++) { try { device = MidiSystem.getMidiDevice(infos[i]); } catch (MidiUnavailableException e) { // Handle or throw exception... } if (device instanceof Synthesizer) { synthInfos.add(infos[i]); } } // Now, display strings from synthInfos list in GUI.
As another example, you
might choose a device programmatically, without involving the user.
Let's suppose you want to obtain the synthesizer that can play the
most notes simultaneously. You iterate over all the MidiDevice.Info
objects, as above, but after determining that a device is a
synthesizer, you query its capabilities by invoking the
getMaxPolyphony
method of Synthesizer
.
You reserve the synthesizer that has the greatest polyphony, as
described in the next section. Even though you're not asking the
user to choose a synthesizer, you might still display strings from
the chosen MidiDevice.Info
object, just for the user's
information.
The previous section showed
how to get an installed device. However, a device might be
installed but unavailable. For example, another application program
might have exclusive use of it. To actually reserve a device for
your program, you need to use the MidiDevice
method
open
:
if (!(device.isOpen())) { try { device.open(); } catch (MidiUnavailableException e) { // Handle or throw exception... } }
Once you've accessed a device and reserved it by opening it, you'll probably want to connect it to one or more other devices to let MIDI data flow between them. This procedure is described in Chapter 10, "Transmitting and Receiving MIDI Messages."
When done with a device, you
release it for other programs' use by invoking the
close
method of MidiDevice
.