/* | 
|
 * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. | 
|
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | 
|
 * | 
|
 * This code is free software; you can redistribute it and/or modify it | 
|
 * under the terms of the GNU General Public License version 2 only, as | 
|
 * published by the Free Software Foundation.  Oracle designates this | 
|
 * particular file as subject to the "Classpath" exception as provided | 
|
 * by Oracle in the LICENSE file that accompanied this code. | 
|
 * | 
|
 * This code is distributed in the hope that it will be useful, but WITHOUT | 
|
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | 
|
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License | 
|
 * version 2 for more details (a copy is included in the LICENSE file that | 
|
 * accompanied this code). | 
|
 * | 
|
 * You should have received a copy of the GNU General Public License version | 
|
 * 2 along with this work; if not, write to the Free Software Foundation, | 
|
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | 
|
 * | 
|
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | 
|
 * or visit www.oracle.com if you need additional information or have any | 
|
 * questions. | 
|
*/  | 
|
package javax.sound.midi;  | 
|
import java.io.FileInputStream;  | 
|
import java.io.File;  | 
|
import java.io.InputStream;  | 
|
import java.io.OutputStream;  | 
|
import java.io.IOException;  | 
|
import java.util.ArrayList;  | 
|
import java.util.HashSet;  | 
|
import java.util.Iterator;  | 
|
import java.util.List;  | 
|
import java.util.Set;  | 
|
import java.net.URL;  | 
|
import javax.sound.midi.spi.MidiFileWriter;  | 
|
import javax.sound.midi.spi.MidiFileReader;  | 
|
import javax.sound.midi.spi.SoundbankReader;  | 
|
import javax.sound.midi.spi.MidiDeviceProvider;  | 
|
import com.sun.media.sound.JDK13Services;  | 
|
import com.sun.media.sound.ReferenceCountingDevice;  | 
|
import com.sun.media.sound.AutoConnectSequencer;  | 
|
import com.sun.media.sound.MidiDeviceReceiverEnvelope;  | 
|
import com.sun.media.sound.MidiDeviceTransmitterEnvelope;  | 
|
/** | 
|
 * The <code>MidiSystem</code> class provides access to the installed MIDI | 
|
 * system resources, including devices such as synthesizers, sequencers, and | 
|
 * MIDI input and output ports.  A typical simple MIDI application might | 
|
 * begin by invoking one or more <code>MidiSystem</code> methods to learn | 
|
 * what devices are installed and to obtain the ones needed in that | 
|
 * application. | 
|
 * <p> | 
|
 * The class also has methods for reading files, streams, and  URLs that | 
|
 * contain standard MIDI file data or soundbanks.  You can query the | 
|
 * <code>MidiSystem</code> for the format of a specified MIDI file. | 
|
 * <p> | 
|
 * You cannot instantiate a <code>MidiSystem</code>; all the methods are | 
|
 * static. | 
|
 * | 
|
 * <p>Properties can be used to specify default MIDI devices. | 
|
 * Both system properties and a properties file are considered. | 
|
 * The <code>sound.properties</code> properties file is read from | 
|
 * an implementation-specific location (typically it is the <code>lib</code> | 
|
 * directory in the Java installation directory). | 
|
 * If a property exists both as a system property and in the | 
|
 * properties file, the system property takes precedence. If none is | 
|
 * specified, a suitable default is chosen among the available devices. | 
|
 * The syntax of the properties file is specified in | 
|
 * {@link java.util.Properties#load(InputStream) Properties.load}. The | 
|
 * following table lists the available property keys and which methods | 
|
 * consider them: | 
|
 * | 
|
 * <table border=0> | 
|
 *  <caption>MIDI System Property Keys</caption> | 
|
 *  <tr> | 
|
 *   <th>Property Key</th> | 
|
 *   <th>Interface</th> | 
|
 *   <th>Affected Method</th> | 
|
 *  </tr> | 
|
 *  <tr> | 
|
 *   <td><code>javax.sound.midi.Receiver</code></td> | 
|
 *   <td>{@link Receiver}</td> | 
|
 *   <td>{@link #getReceiver}</td> | 
|
 *  </tr> | 
|
 *  <tr> | 
|
 *   <td><code>javax.sound.midi.Sequencer</code></td> | 
|
 *   <td>{@link Sequencer}</td> | 
|
 *   <td>{@link #getSequencer}</td> | 
|
 *  </tr> | 
|
 *  <tr> | 
|
 *   <td><code>javax.sound.midi.Synthesizer</code></td> | 
|
 *   <td>{@link Synthesizer}</td> | 
|
 *   <td>{@link #getSynthesizer}</td> | 
|
 *  </tr> | 
|
 *  <tr> | 
|
 *   <td><code>javax.sound.midi.Transmitter</code></td> | 
|
 *   <td>{@link Transmitter}</td> | 
|
 *   <td>{@link #getTransmitter}</td> | 
|
 *  </tr> | 
|
 * </table> | 
|
 * | 
|
 * The property value consists of the provider class name | 
|
 * and the device name, separated by the hash mark ("#"). | 
|
 * The provider class name is the fully-qualified | 
|
 * name of a concrete {@link javax.sound.midi.spi.MidiDeviceProvider | 
|
 * MIDI device provider} class. The device name is matched against | 
|
 * the <code>String</code> returned by the <code>getName</code> | 
|
 * method of <code>MidiDevice.Info</code>. | 
|
 * Either the class name, or the device name may be omitted. | 
|
 * If only the class name is specified, the trailing hash mark | 
|
 * is optional. | 
|
 * | 
|
 * <p>If the provider class is specified, and it can be | 
|
 * successfully retrieved from the installed providers, | 
|
 * the list of | 
|
 * <code>MidiDevice.Info</code> objects is retrieved | 
|
 * from the provider. Otherwise, or when these devices | 
|
 * do not provide a subsequent match, the list is retrieved | 
|
 * from {@link #getMidiDeviceInfo} to contain | 
|
 * all available <code>MidiDevice.Info</code> objects. | 
|
 * | 
|
 * <p>If a device name is specified, the resulting list of | 
|
 * <code>MidiDevice.Info</code> objects is searched: | 
|
 * the first one with a matching name, and whose | 
|
 * <code>MidiDevice</code> implements the | 
|
 * respective interface, will be returned. | 
|
 * If no matching <code>MidiDevice.Info</code> object | 
|
 * is found, or the device name is not specified, | 
|
 * the first suitable device from the resulting | 
|
 * list will be returned. For Sequencer and Synthesizer, | 
|
 * a device is suitable if it implements the respective | 
|
 * interface; whereas for Receiver and Transmitter, a device is | 
|
 * suitable if it | 
|
 * implements neither Sequencer nor Synthesizer and provides | 
|
 * at least one Receiver or Transmitter, respectively. | 
|
 * | 
|
 * For example, the property <code>javax.sound.midi.Receiver</code> | 
|
 * with a value | 
|
 * <code>"com.sun.media.sound.MidiProvider#SunMIDI1"</code> | 
|
 * will have the following consequences when | 
|
 * <code>getReceiver</code> is called: | 
|
 * if the class <code>com.sun.media.sound.MidiProvider</code> exists | 
|
 * in the list of installed MIDI device providers, | 
|
 * the first <code>Receiver</code> device with name | 
|
 * <code>"SunMIDI1"</code> will be returned. If it cannot | 
|
 * be found, the first <code>Receiver</code> from that provider | 
|
 * will be returned, regardless of name. | 
|
 * If there is none, the first <code>Receiver</code> with name | 
|
 * <code>"SunMIDI1"</code> in the list of all devices | 
|
 * (as returned by <code>getMidiDeviceInfo</code>) will be returned, | 
|
 * or, if not found, the first <code>Receiver</code> that can | 
|
 * be found in the list of all devices is returned. | 
|
 * If that fails, too, a <code>MidiUnavailableException</code> | 
|
 * is thrown. | 
|
 * | 
|
 * @author Kara Kytle | 
|
 * @author Florian Bomers | 
|
 * @author Matthias Pfisterer | 
|
*/  | 
|
public class MidiSystem { | 
|
    /** | 
|
     * Private no-args constructor for ensuring against instantiation. | 
|
*/  | 
|
    private MidiSystem() { | 
|
}  | 
|
    /** | 
|
     * Obtains an array of information objects representing | 
|
     * the set of all MIDI devices available on the system. | 
|
     * A returned information object can then be used to obtain the | 
|
     * corresponding device object, by invoking | 
|
     * {@link #getMidiDevice(MidiDevice.Info) getMidiDevice}. | 
|
     * | 
|
     * @return an array of <code>MidiDevice.Info</code> objects, one | 
|
     * for each installed MIDI device.  If no such devices are installed, | 
|
     * an array of length 0 is returned. | 
|
*/  | 
|
public static MidiDevice.Info[] getMidiDeviceInfo() {  | 
|
List allInfos = new ArrayList();  | 
|
List providers = getMidiDeviceProviders();  | 
|
for(int i = 0; i < providers.size(); i++) {  | 
|
MidiDeviceProvider provider = (MidiDeviceProvider) providers.get(i);  | 
|
MidiDevice.Info[] tmpinfo = provider.getDeviceInfo();  | 
|
for (int j = 0; j < tmpinfo.length; j++) {  | 
|
allInfos.add( tmpinfo[j] );  | 
|
}  | 
|
}  | 
|
MidiDevice.Info[] infosArray = (MidiDevice.Info[]) allInfos.toArray(new MidiDevice.Info[0]);  | 
|
return infosArray;  | 
|
}  | 
|
    /** | 
|
     * Obtains the requested MIDI device. | 
|
     * | 
|
     * @param info a device information object representing the desired device. | 
|
     * @return the requested device | 
|
     * @throws MidiUnavailableException if the requested device is not available | 
|
     * due to resource restrictions | 
|
     * @throws IllegalArgumentException if the info object does not represent | 
|
     * a MIDI device installed on the system | 
|
     * @see #getMidiDeviceInfo | 
|
*/  | 
|
public static MidiDevice getMidiDevice(MidiDevice.Info info) throws MidiUnavailableException {  | 
|
List providers = getMidiDeviceProviders();  | 
|
for(int i = 0; i < providers.size(); i++) {  | 
|
MidiDeviceProvider provider = (MidiDeviceProvider) providers.get(i);  | 
|
if (provider.isDeviceSupported(info)) {  | 
|
MidiDevice device = provider.getDevice(info);  | 
|
return device;  | 
|
}  | 
|
}  | 
|
throw new IllegalArgumentException("Requested device not installed: " + info);  | 
|
}  | 
|
    /** | 
|
     * Obtains a MIDI receiver from an external MIDI port | 
|
     * or other default device. | 
|
     * The returned receiver always implements | 
|
     * the {@code MidiDeviceReceiver} interface. | 
|
     * | 
|
     * <p>If the system property | 
|
     * <code>javax.sound.midi.Receiver</code> | 
|
     * is defined or it is defined in the file "sound.properties", | 
|
     * it is used to identify the device that provides the default receiver. | 
|
     * For details, refer to the {@link MidiSystem class description}. | 
|
     * | 
|
     * If a suitable MIDI port is not available, the Receiver is | 
|
     * retrieved from an installed synthesizer. | 
|
     * | 
|
     * <p>If a native receiver provided by the default device does not implement | 
|
     * the {@code MidiDeviceReceiver} interface, it will be wrapped in a | 
|
     * wrapper class that implements the {@code MidiDeviceReceiver} interface. | 
|
     * The corresponding {@code Receiver} method calls will be forwarded | 
|
     * to the native receiver. | 
|
     * | 
|
     * <p>If this method returns successfully, the {@link | 
|
     * javax.sound.midi.MidiDevice MidiDevice} the | 
|
     * <code>Receiver</code> belongs to is opened implicitly, if it is | 
|
     * not already open. It is possible to close an implicitly opened | 
|
     * device by calling {@link javax.sound.midi.Receiver#close close} | 
|
     * on the returned <code>Receiver</code>. All open <code>Receiver</code> | 
|
     * instances have to be closed in order to release system resources | 
|
     * hold by the <code>MidiDevice</code>. For a | 
|
     * detailed description of open/close behaviour see the class | 
|
     * description of {@link javax.sound.midi.MidiDevice MidiDevice}. | 
|
     * | 
|
     * | 
|
     * @return the default MIDI receiver | 
|
     * @throws MidiUnavailableException if the default receiver is not | 
|
     *         available due to resource restrictions, | 
|
     *         or no device providing receivers is installed in the system | 
|
*/  | 
|
public static Receiver getReceiver() throws MidiUnavailableException {  | 
|
        // may throw MidiUnavailableException | 
|
MidiDevice device = getDefaultDeviceWrapper(Receiver.class);  | 
|
Receiver receiver;  | 
|
if (device instanceof ReferenceCountingDevice) {  | 
|
receiver = ((ReferenceCountingDevice) device).getReceiverReferenceCounting();  | 
|
        } else { | 
|
receiver = device.getReceiver();  | 
|
}  | 
|
if (!(receiver instanceof MidiDeviceReceiver)) {  | 
|
receiver = new MidiDeviceReceiverEnvelope(device, receiver);  | 
|
}  | 
|
return receiver;  | 
|
}  | 
|
    /** | 
|
     * Obtains a MIDI transmitter from an external MIDI port | 
|
     * or other default source. | 
|
     * The returned transmitter always implements | 
|
     * the {@code MidiDeviceTransmitter} interface. | 
|
     * | 
|
     * <p>If the system property | 
|
     * <code>javax.sound.midi.Transmitter</code> | 
|
     * is defined or it is defined in the file "sound.properties", | 
|
     * it is used to identify the device that provides the default transmitter. | 
|
     * For details, refer to the {@link MidiSystem class description}. | 
|
     * | 
|
     * <p>If a native transmitter provided by the default device does not implement | 
|
     * the {@code MidiDeviceTransmitter} interface, it will be wrapped in a | 
|
     * wrapper class that implements the {@code MidiDeviceTransmitter} interface. | 
|
     * The corresponding {@code Transmitter} method calls will be forwarded | 
|
     * to the native transmitter. | 
|
     * | 
|
     * <p>If this method returns successfully, the {@link | 
|
     * javax.sound.midi.MidiDevice MidiDevice} the | 
|
     * <code>Transmitter</code> belongs to is opened implicitly, if it | 
|
     * is not already open. It is possible to close an implicitly | 
|
     * opened device by calling {@link | 
|
     * javax.sound.midi.Transmitter#close close} on the returned | 
|
     * <code>Transmitter</code>. All open <code>Transmitter</code> | 
|
     * instances have to be closed in order to release system resources | 
|
     * hold by the <code>MidiDevice</code>. For a detailed description | 
|
     * of open/close behaviour see the class description of {@link | 
|
     * javax.sound.midi.MidiDevice MidiDevice}. | 
|
     * | 
|
     * @return the default MIDI transmitter | 
|
     * @throws MidiUnavailableException if the default transmitter is not | 
|
     *         available due to resource restrictions, | 
|
     *         or no device providing transmitters is installed in the system | 
|
*/  | 
|
public static Transmitter getTransmitter() throws MidiUnavailableException {  | 
|
        // may throw MidiUnavailableException | 
|
MidiDevice device = getDefaultDeviceWrapper(Transmitter.class);  | 
|
Transmitter transmitter;  | 
|
if (device instanceof ReferenceCountingDevice) {  | 
|
transmitter = ((ReferenceCountingDevice) device).getTransmitterReferenceCounting();  | 
|
        } else { | 
|
transmitter = device.getTransmitter();  | 
|
}  | 
|
if (!(transmitter instanceof MidiDeviceTransmitter)) {  | 
|
transmitter = new MidiDeviceTransmitterEnvelope(device, transmitter);  | 
|
}  | 
|
return transmitter;  | 
|
}  | 
|
    /** | 
|
     * Obtains the default synthesizer. | 
|
     * | 
|
     * <p>If the system property | 
|
     * <code>javax.sound.midi.Synthesizer</code> | 
|
     * is defined or it is defined in the file "sound.properties", | 
|
     * it is used to identify the default synthesizer. | 
|
     * For details, refer to the {@link MidiSystem class description}. | 
|
     * | 
|
     * @return the default synthesizer | 
|
     * @throws MidiUnavailableException if the synthesizer is not | 
|
     *         available due to resource restrictions, | 
|
     *         or no synthesizer is installed in the system | 
|
*/  | 
|
public static Synthesizer getSynthesizer() throws MidiUnavailableException {  | 
|
        // may throw MidiUnavailableException | 
|
return (Synthesizer) getDefaultDeviceWrapper(Synthesizer.class);  | 
|
}  | 
|
    /** | 
|
     * Obtains the default <code>Sequencer</code>, connected to | 
|
     * a default device. | 
|
     * The returned <code>Sequencer</code> instance is | 
|
     * connected to the default <code>Synthesizer</code>, | 
|
     * as returned by {@link #getSynthesizer}. | 
|
     * If there is no <code>Synthesizer</code> | 
|
     * available, or the default <code>Synthesizer</code> | 
|
     * cannot be opened, the <code>sequencer</code> is connected | 
|
     * to the default <code>Receiver</code>, as returned | 
|
     * by {@link #getReceiver}. | 
|
     * The connection is made by retrieving a <code>Transmitter</code> | 
|
     * instance from the <code>Sequencer</code> and setting its | 
|
     * <code>Receiver</code>. | 
|
     * Closing and re-opening the sequencer will restore the | 
|
     * connection to the default device. | 
|
     * | 
|
     * <p>This method is equivalent to calling | 
|
     * <code>getSequencer(true)</code>. | 
|
     * | 
|
     * <p>If the system property | 
|
     * <code>javax.sound.midi.Sequencer</code> | 
|
     * is defined or it is defined in the file "sound.properties", | 
|
     * it is used to identify the default sequencer. | 
|
     * For details, refer to the {@link MidiSystem class description}. | 
|
     * | 
|
     * @return the default sequencer, connected to a default Receiver | 
|
     * @throws MidiUnavailableException if the sequencer is not | 
|
     *         available due to resource restrictions, | 
|
     *         or there is no <code>Receiver</code> available by any | 
|
     *         installed <code>MidiDevice</code>, | 
|
     *         or no sequencer is installed in the system. | 
|
     * @see #getSequencer(boolean) | 
|
     * @see #getSynthesizer | 
|
     * @see #getReceiver | 
|
*/  | 
|
public static Sequencer getSequencer() throws MidiUnavailableException {  | 
|
return getSequencer(true);  | 
|
}  | 
|
    /** | 
|
     * Obtains the default <code>Sequencer</code>, optionally | 
|
     * connected to a default device. | 
|
     * | 
|
     * <p>If <code>connected</code> is true, the returned | 
|
     * <code>Sequencer</code> instance is | 
|
     * connected to the default <code>Synthesizer</code>, | 
|
     * as returned by {@link #getSynthesizer}. | 
|
     * If there is no <code>Synthesizer</code> | 
|
     * available, or the default <code>Synthesizer</code> | 
|
     * cannot be opened, the <code>sequencer</code> is connected | 
|
     * to the default <code>Receiver</code>, as returned | 
|
     * by {@link #getReceiver}. | 
|
     * The connection is made by retrieving a <code>Transmitter</code> | 
|
     * instance from the <code>Sequencer</code> and setting its | 
|
     * <code>Receiver</code>. | 
|
     * Closing and re-opening the sequencer will restore the | 
|
     * connection to the default device. | 
|
     * | 
|
     * <p>If <code>connected</code> is false, the returned | 
|
     * <code>Sequencer</code> instance is not connected, it | 
|
     * has no open <code>Transmitters</code>. In order to | 
|
     * play the sequencer on a MIDI device, or a <code>Synthesizer</code>, | 
|
     * it is necessary to get a <code>Transmitter</code> and set its | 
|
     * <code>Receiver</code>. | 
|
     * | 
|
     * <p>If the system property | 
|
     * <code>javax.sound.midi.Sequencer</code> | 
|
     * is defined or it is defined in the file "sound.properties", | 
|
     * it is used to identify the default sequencer. | 
|
     * For details, refer to the {@link MidiSystem class description}. | 
|
     * | 
|
     * @param connected whether or not the returned {@code Sequencer} | 
|
     * is connected to the default {@code Synthesizer} | 
|
     * @return the default sequencer | 
|
     * @throws MidiUnavailableException if the sequencer is not | 
|
     *         available due to resource restrictions, | 
|
     *         or no sequencer is installed in the system, | 
|
     *         or if <code>connected</code> is true, and there is | 
|
     *         no <code>Receiver</code> available by any installed | 
|
     *         <code>MidiDevice</code> | 
|
     * @see #getSynthesizer | 
|
     * @see #getReceiver | 
|
     * @since 1.5 | 
|
*/  | 
|
public static Sequencer getSequencer(boolean connected)  | 
|
throws MidiUnavailableException {  | 
|
Sequencer seq = (Sequencer) getDefaultDeviceWrapper(Sequencer.class);  | 
|
if (connected) {  | 
|
// IMPORTANT: this code needs to be synch'ed with  | 
|
// all AutoConnectSequencer instances,  | 
|
// (e.g. RealTimeSequencer) because the  | 
|
// same algorithm for synth retrieval  | 
|
// needs to be used!  | 
|
Receiver rec = null;  | 
|
MidiUnavailableException mue = null;  | 
|
            // first try to connect to the default synthesizer | 
|
            try { | 
|
Synthesizer synth = getSynthesizer();  | 
|
if (synth instanceof ReferenceCountingDevice) {  | 
|
rec = ((ReferenceCountingDevice) synth).getReceiverReferenceCounting();  | 
|
                } else { | 
|
synth.open();  | 
|
                    try { | 
|
rec = synth.getReceiver();  | 
|
                    } finally { | 
|
                        // make sure that the synth is properly closed | 
|
if (rec == null) {  | 
|
synth.close();  | 
|
}  | 
|
}  | 
|
}  | 
|
} catch (MidiUnavailableException e) {  | 
|
                // something went wrong with synth | 
|
if (e instanceof MidiUnavailableException) {  | 
|
mue = (MidiUnavailableException) e;  | 
|
}  | 
|
}  | 
|
if (rec == null) {  | 
|
                // then try to connect to the default Receiver | 
|
                try { | 
|
rec = MidiSystem.getReceiver();  | 
|
} catch (Exception e) {  | 
|
                    // something went wrong. Nothing to do then! | 
|
if (e instanceof MidiUnavailableException) {  | 
|
mue = (MidiUnavailableException) e;  | 
|
}  | 
|
}  | 
|
}  | 
|
if (rec != null) {  | 
|
seq.getTransmitter().setReceiver(rec);  | 
|
if (seq instanceof AutoConnectSequencer) {  | 
|
((AutoConnectSequencer) seq).setAutoConnect(rec);  | 
|
}  | 
|
            } else { | 
|
if (mue != null) {  | 
|
throw mue;  | 
|
}  | 
|
throw new MidiUnavailableException("no receiver available");  | 
|
}  | 
|
}  | 
|
return seq;  | 
|
}  | 
|
    /** | 
|
     * Constructs a MIDI sound bank by reading it from the specified stream. | 
|
     * The stream must point to | 
|
     * a valid MIDI soundbank file.  In general, MIDI soundbank providers may | 
|
     * need to read some data from the stream before determining whether they | 
|
     * support it.  These parsers must | 
|
     * be able to mark the stream, read enough data to determine whether they | 
|
     * support the stream, and, if not, reset the stream's read pointer to | 
|
     * its original position.  If the input stream does not support this, | 
|
     * this method may fail with an IOException. | 
|
     * @param stream the source of the sound bank data. | 
|
     * @return the sound bank | 
|
     * @throws InvalidMidiDataException if the stream does not point to | 
|
     * valid MIDI soundbank data recognized by the system | 
|
     * @throws IOException if an I/O error occurred when loading the soundbank | 
|
     * @see InputStream#markSupported | 
|
     * @see InputStream#mark | 
|
*/  | 
|
public static Soundbank getSoundbank(InputStream stream)  | 
|
throws InvalidMidiDataException, IOException {  | 
|
SoundbankReader sp = null;  | 
|
Soundbank s = null;  | 
|
List providers = getSoundbankReaders();  | 
|
for(int i = 0; i < providers.size(); i++) {  | 
|
sp = (SoundbankReader)providers.get(i);  | 
|
s = sp.getSoundbank(stream);  | 
|
if( s!= null) {  | 
|
return s;  | 
|
}  | 
|
}  | 
|
throw new InvalidMidiDataException("cannot get soundbank from stream");  | 
|
}  | 
|
    /** | 
|
     * Constructs a <code>Soundbank</code> by reading it from the specified URL. | 
|
     * The URL must point to a valid MIDI soundbank file. | 
|
     * | 
|
     * @param url the source of the sound bank data | 
|
     * @return the sound bank | 
|
     * @throws InvalidMidiDataException if the URL does not point to valid MIDI | 
|
     * soundbank data recognized by the system | 
|
     * @throws IOException if an I/O error occurred when loading the soundbank | 
|
*/  | 
|
public static Soundbank getSoundbank(URL url)  | 
|
throws InvalidMidiDataException, IOException {  | 
|
SoundbankReader sp = null;  | 
|
Soundbank s = null;  | 
|
List providers = getSoundbankReaders();  | 
|
for(int i = 0; i < providers.size(); i++) {  | 
|
sp = (SoundbankReader)providers.get(i);  | 
|
s = sp.getSoundbank(url);  | 
|
if( s!= null) {  | 
|
return s;  | 
|
}  | 
|
}  | 
|
throw new InvalidMidiDataException("cannot get soundbank from stream");  | 
|
}  | 
|
    /** | 
|
     * Constructs a <code>Soundbank</code> by reading it from the specified | 
|
     * <code>File</code>. | 
|
     * The <code>File</code> must point to a valid MIDI soundbank file. | 
|
     * | 
|
     * @param file the source of the sound bank data | 
|
     * @return the sound bank | 
|
     * @throws InvalidMidiDataException if the <code>File</code> does not | 
|
     * point to valid MIDI soundbank data recognized by the system | 
|
     * @throws IOException if an I/O error occurred when loading the soundbank | 
|
*/  | 
|
public static Soundbank getSoundbank(File file)  | 
|
throws InvalidMidiDataException, IOException {  | 
|
SoundbankReader sp = null;  | 
|
Soundbank s = null;  | 
|
List providers = getSoundbankReaders();  | 
|
for(int i = 0; i < providers.size(); i++) {  | 
|
sp = (SoundbankReader)providers.get(i);  | 
|
s = sp.getSoundbank(file);  | 
|
if( s!= null) {  | 
|
return s;  | 
|
}  | 
|
}  | 
|
throw new InvalidMidiDataException("cannot get soundbank from stream");  | 
|
}  | 
|
    /** | 
|
     * Obtains the MIDI file format of the data in the specified input stream. | 
|
     * The stream must point to valid MIDI file data for a file type recognized | 
|
     * by the system. | 
|
     * <p> | 
|
     * This method and/or the code it invokes may need to read some data from | 
|
     * the stream to determine whether its data format is supported.  The | 
|
     * implementation may therefore | 
|
     * need to mark the stream, read enough data to determine whether it is in | 
|
     * a supported format, and reset the stream's read pointer to its original | 
|
     * position.  If the input stream does not permit this set of operations, | 
|
     * this method may fail with an <code>IOException</code>. | 
|
     * <p> | 
|
     * This operation can only succeed for files of a type which can be parsed | 
|
     * by an installed file reader.  It may fail with an InvalidMidiDataException | 
|
     * even for valid files if no compatible file reader is installed.  It | 
|
     * will also fail with an InvalidMidiDataException if a compatible file reader | 
|
     * is installed, but encounters errors while determining the file format. | 
|
     * | 
|
     * @param stream the input stream from which file format information | 
|
     * should be extracted | 
|
     * @return an <code>MidiFileFormat</code> object describing the MIDI file | 
|
     * format | 
|
     * @throws InvalidMidiDataException if the stream does not point to valid | 
|
     * MIDI file data recognized by the system | 
|
     * @throws IOException if an I/O exception occurs while accessing the | 
|
     * stream | 
|
     * @see #getMidiFileFormat(URL) | 
|
     * @see #getMidiFileFormat(File) | 
|
     * @see InputStream#markSupported | 
|
     * @see InputStream#mark | 
|
*/  | 
|
public static MidiFileFormat getMidiFileFormat(InputStream stream)  | 
|
throws InvalidMidiDataException, IOException {  | 
|
List providers = getMidiFileReaders();  | 
|
MidiFileFormat format = null;  | 
|
for(int i = 0; i < providers.size(); i++) {  | 
|
MidiFileReader reader = (MidiFileReader) providers.get(i);  | 
|
            try { | 
|
format = reader.getMidiFileFormat( stream ); // throws IOException  | 
|
break;  | 
|
} catch (InvalidMidiDataException e) {  | 
|
continue;  | 
|
}  | 
|
}  | 
|
if( format==null ) {  | 
|
throw new InvalidMidiDataException("input stream is not a supported file type");  | 
|
        } else { | 
|
return format;  | 
|
}  | 
|
}  | 
|
    /** | 
|
     * Obtains the MIDI file format of the data in the specified URL.  The URL | 
|
     * must point to valid MIDI file data for a file type recognized | 
|
     * by the system. | 
|
     * <p> | 
|
     * This operation can only succeed for files of a type which can be parsed | 
|
     * by an installed file reader.  It may fail with an InvalidMidiDataException | 
|
     * even for valid files if no compatible file reader is installed.  It | 
|
     * will also fail with an InvalidMidiDataException if a compatible file reader | 
|
     * is installed, but encounters errors while determining the file format. | 
|
     * | 
|
     * @param url the URL from which file format information should be | 
|
     * extracted | 
|
     * @return a <code>MidiFileFormat</code> object describing the MIDI file | 
|
     * format | 
|
     * @throws InvalidMidiDataException if the URL does not point to valid MIDI | 
|
     * file data recognized by the system | 
|
     * @throws IOException if an I/O exception occurs while accessing the URL | 
|
     * | 
|
     * @see #getMidiFileFormat(InputStream) | 
|
     * @see #getMidiFileFormat(File) | 
|
*/  | 
|
public static MidiFileFormat getMidiFileFormat(URL url)  | 
|
throws InvalidMidiDataException, IOException {  | 
|
List providers = getMidiFileReaders();  | 
|
MidiFileFormat format = null;  | 
|
for(int i = 0; i < providers.size(); i++) {  | 
|
MidiFileReader reader = (MidiFileReader) providers.get(i);  | 
|
            try { | 
|
format = reader.getMidiFileFormat( url ); // throws IOException  | 
|
break;  | 
|
} catch (InvalidMidiDataException e) {  | 
|
continue;  | 
|
}  | 
|
}  | 
|
if( format==null ) {  | 
|
throw new InvalidMidiDataException("url is not a supported file type");  | 
|
        } else { | 
|
return format;  | 
|
}  | 
|
}  | 
|
    /** | 
|
     * Obtains the MIDI file format of the specified <code>File</code>.  The | 
|
     * <code>File</code> must point to valid MIDI file data for a file type | 
|
     * recognized by the system. | 
|
     * <p> | 
|
     * This operation can only succeed for files of a type which can be parsed | 
|
     * by an installed file reader.  It may fail with an InvalidMidiDataException | 
|
     * even for valid files if no compatible file reader is installed.  It | 
|
     * will also fail with an InvalidMidiDataException if a compatible file reader | 
|
     * is installed, but encounters errors while determining the file format. | 
|
     * | 
|
     * @param file the <code>File</code> from which file format information | 
|
     * should be extracted | 
|
     * @return a <code>MidiFileFormat</code> object describing the MIDI file | 
|
     * format | 
|
     * @throws InvalidMidiDataException if the <code>File</code> does not point | 
|
     *  to valid MIDI file data recognized by the system | 
|
     * @throws IOException if an I/O exception occurs while accessing the file | 
|
     * | 
|
     * @see #getMidiFileFormat(InputStream) | 
|
     * @see #getMidiFileFormat(URL) | 
|
*/  | 
|
public static MidiFileFormat getMidiFileFormat(File file)  | 
|
throws InvalidMidiDataException, IOException {  | 
|
List providers = getMidiFileReaders();  | 
|
MidiFileFormat format = null;  | 
|
for(int i = 0; i < providers.size(); i++) {  | 
|
MidiFileReader reader = (MidiFileReader) providers.get(i);  | 
|
            try { | 
|
format = reader.getMidiFileFormat( file ); // throws IOException  | 
|
break;  | 
|
} catch (InvalidMidiDataException e) {  | 
|
continue;  | 
|
}  | 
|
}  | 
|
if( format==null ) {  | 
|
throw new InvalidMidiDataException("file is not a supported file type");  | 
|
        } else { | 
|
return format;  | 
|
}  | 
|
}  | 
|
    /** | 
|
     * Obtains a MIDI sequence from the specified input stream.  The stream must | 
|
     * point to valid MIDI file data for a file type recognized | 
|
     * by the system. | 
|
     * <p> | 
|
     * This method and/or the code it invokes may need to read some data | 
|
     * from the stream to determine whether | 
|
     * its data format is supported.  The implementation may therefore | 
|
     * need to mark the stream, read enough data to determine whether it is in | 
|
     * a supported format, and reset the stream's read pointer to its original | 
|
     * position.  If the input stream does not permit this set of operations, | 
|
     * this method may fail with an <code>IOException</code>. | 
|
     * <p> | 
|
     * This operation can only succeed for files of a type which can be parsed | 
|
     * by an installed file reader.  It may fail with an InvalidMidiDataException | 
|
     * even for valid files if no compatible file reader is installed.  It | 
|
     * will also fail with an InvalidMidiDataException if a compatible file reader | 
|
     * is installed, but encounters errors while constructing the <code>Sequence</code> | 
|
     * object from the file data. | 
|
     * | 
|
     * @param stream the input stream from which the <code>Sequence</code> | 
|
     * should be constructed | 
|
     * @return a <code>Sequence</code> object based on the MIDI file data | 
|
     * contained in the input stream | 
|
     * @throws InvalidMidiDataException if the stream does not point to | 
|
     * valid MIDI file data recognized by the system | 
|
     * @throws IOException if an I/O exception occurs while accessing the | 
|
     * stream | 
|
     * @see InputStream#markSupported | 
|
     * @see InputStream#mark | 
|
*/  | 
|
public static Sequence getSequence(InputStream stream)  | 
|
throws InvalidMidiDataException, IOException {  | 
|
List providers = getMidiFileReaders();  | 
|
Sequence sequence = null;  | 
|
for(int i = 0; i < providers.size(); i++) {  | 
|
MidiFileReader reader = (MidiFileReader) providers.get(i);  | 
|
            try { | 
|
sequence = reader.getSequence( stream ); // throws IOException  | 
|
break;  | 
|
} catch (InvalidMidiDataException e) {  | 
|
continue;  | 
|
}  | 
|
}  | 
|
if( sequence==null ) {  | 
|
throw new InvalidMidiDataException("could not get sequence from input stream");  | 
|
        } else { | 
|
return sequence;  | 
|
}  | 
|
}  | 
|
    /** | 
|
     * Obtains a MIDI sequence from the specified URL.  The URL must | 
|
     * point to valid MIDI file data for a file type recognized | 
|
     * by the system. | 
|
     * <p> | 
|
     * This operation can only succeed for files of a type which can be parsed | 
|
     * by an installed file reader.  It may fail with an InvalidMidiDataException | 
|
     * even for valid files if no compatible file reader is installed.  It | 
|
     * will also fail with an InvalidMidiDataException if a compatible file reader | 
|
     * is installed, but encounters errors while constructing the <code>Sequence</code> | 
|
     * object from the file data. | 
|
     * | 
|
     * @param url the URL from which the <code>Sequence</code> should be | 
|
     * constructed | 
|
     * @return a <code>Sequence</code> object based on the MIDI file data | 
|
     * pointed to by the URL | 
|
     * @throws InvalidMidiDataException if the URL does not point to valid MIDI | 
|
     * file data recognized by the system | 
|
     * @throws IOException if an I/O exception occurs while accessing the URL | 
|
*/  | 
|
public static Sequence getSequence(URL url)  | 
|
throws InvalidMidiDataException, IOException {  | 
|
List providers = getMidiFileReaders();  | 
|
Sequence sequence = null;  | 
|
for(int i = 0; i < providers.size(); i++) {  | 
|
MidiFileReader reader = (MidiFileReader) providers.get(i);  | 
|
            try { | 
|
sequence = reader.getSequence( url ); // throws IOException  | 
|
break;  | 
|
} catch (InvalidMidiDataException e) {  | 
|
continue;  | 
|
}  | 
|
}  | 
|
if( sequence==null ) {  | 
|
throw new InvalidMidiDataException("could not get sequence from URL");  | 
|
        } else { | 
|
return sequence;  | 
|
}  | 
|
}  | 
|
    /** | 
|
     * Obtains a MIDI sequence from the specified <code>File</code>. | 
|
     * The <code>File</code> must point to valid MIDI file data | 
|
     * for a file type recognized by the system. | 
|
     * <p> | 
|
     * This operation can only succeed for files of a type which can be parsed | 
|
     * by an installed file reader.  It may fail with an InvalidMidiDataException | 
|
     * even for valid files if no compatible file reader is installed.  It | 
|
     * will also fail with an InvalidMidiDataException if a compatible file reader | 
|
     * is installed, but encounters errors while constructing the <code>Sequence</code> | 
|
     * object from the file data. | 
|
     * | 
|
     * @param file the <code>File</code> from which the <code>Sequence</code> | 
|
     * should be constructed | 
|
     * @return a <code>Sequence</code> object based on the MIDI file data | 
|
     * pointed to by the File | 
|
     * @throws InvalidMidiDataException if the File does not point to valid MIDI | 
|
     * file data recognized by the system | 
|
     * @throws IOException if an I/O exception occurs | 
|
*/  | 
|
public static Sequence getSequence(File file)  | 
|
throws InvalidMidiDataException, IOException {  | 
|
List providers = getMidiFileReaders();  | 
|
Sequence sequence = null;  | 
|
for(int i = 0; i < providers.size(); i++) {  | 
|
MidiFileReader reader = (MidiFileReader) providers.get(i);  | 
|
            try { | 
|
sequence = reader.getSequence( file ); // throws IOException  | 
|
break;  | 
|
} catch (InvalidMidiDataException e) {  | 
|
continue;  | 
|
}  | 
|
}  | 
|
if( sequence==null ) {  | 
|
throw new InvalidMidiDataException("could not get sequence from file");  | 
|
        } else { | 
|
return sequence;  | 
|
}  | 
|
}  | 
|
    /** | 
|
     * Obtains the set of MIDI file types for which file writing support is | 
|
     * provided by the system. | 
|
     * @return array of unique file types.  If no file types are supported, | 
|
     * an array of length 0 is returned. | 
|
*/  | 
|
    public static int[] getMidiFileTypes() { | 
|
List providers = getMidiFileWriters();  | 
|
Set allTypes = new HashSet();  | 
|
// gather from all the providers  | 
|
for (int i = 0; i < providers.size(); i++ ) {  | 
|
MidiFileWriter writer = (MidiFileWriter) providers.get(i);  | 
|
int[] types = writer.getMidiFileTypes();  | 
|
for (int j = 0; j < types.length; j++ ) {  | 
|
allTypes.add(new Integer(types[j]));  | 
|
}  | 
|
}  | 
|
int resultTypes[] = new int[allTypes.size()];  | 
|
int index = 0;  | 
|
Iterator iterator = allTypes.iterator();  | 
|
while (iterator.hasNext()) {  | 
|
Integer integer = (Integer) iterator.next();  | 
|
resultTypes[index++] = integer.intValue();  | 
|
}  | 
|
return resultTypes;  | 
|
}  | 
|
    /** | 
|
     * Indicates whether file writing support for the specified MIDI file type | 
|
     * is provided by the system. | 
|
     * @param fileType the file type for which write capabilities are queried | 
|
     * @return <code>true</code> if the file type is supported, | 
|
     * otherwise <code>false</code> | 
|
*/  | 
|
    public static boolean isFileTypeSupported(int fileType) { | 
|
List providers = getMidiFileWriters();  | 
|
for (int i = 0; i < providers.size(); i++ ) {  | 
|
MidiFileWriter writer = (MidiFileWriter) providers.get(i);  | 
|
if( writer.isFileTypeSupported(fileType)) {  | 
|
return true;  | 
|
}  | 
|
}  | 
|
return false;  | 
|
}  | 
|
    /** | 
|
     * Obtains the set of MIDI file types that the system can write from the | 
|
     * sequence specified. | 
|
     * @param sequence the sequence for which MIDI file type support | 
|
     * is queried | 
|
     * @return the set of unique supported file types.  If no file types are supported, | 
|
     * returns an array of length 0. | 
|
*/  | 
|
public static int[] getMidiFileTypes(Sequence sequence) {  | 
|
List providers = getMidiFileWriters();  | 
|
Set allTypes = new HashSet();  | 
|
// gather from all the providers  | 
|
for (int i = 0; i < providers.size(); i++ ) {  | 
|
MidiFileWriter writer = (MidiFileWriter) providers.get(i);  | 
|
int[] types = writer.getMidiFileTypes(sequence);  | 
|
for (int j = 0; j < types.length; j++ ) {  | 
|
allTypes.add(new Integer(types[j]));  | 
|
}  | 
|
}  | 
|
int resultTypes[] = new int[allTypes.size()];  | 
|
int index = 0;  | 
|
Iterator iterator = allTypes.iterator();  | 
|
while (iterator.hasNext()) {  | 
|
Integer integer = (Integer) iterator.next();  | 
|
resultTypes[index++] = integer.intValue();  | 
|
}  | 
|
return resultTypes;  | 
|
}  | 
|
    /** | 
|
     * Indicates whether a MIDI file of the file type specified can be written | 
|
     * from the sequence indicated. | 
|
     * @param fileType the file type for which write capabilities | 
|
     * are queried | 
|
     * @param sequence the sequence for which file writing support is queried | 
|
     * @return <code>true</code> if the file type is supported for this | 
|
     * sequence, otherwise <code>false</code> | 
|
*/  | 
|
public static boolean isFileTypeSupported(int fileType, Sequence sequence) {  | 
|
List providers = getMidiFileWriters();  | 
|
for (int i = 0; i < providers.size(); i++ ) {  | 
|
MidiFileWriter writer = (MidiFileWriter) providers.get(i);  | 
|
if( writer.isFileTypeSupported(fileType,sequence)) {  | 
|
return true;  | 
|
}  | 
|
}  | 
|
return false;  | 
|
}  | 
|
    /** | 
|
     * Writes a stream of bytes representing a file of the MIDI file type | 
|
     * indicated to the output stream provided. | 
|
     * @param in sequence containing MIDI data to be written to the file | 
|
     * @param fileType the file type of the file to be written to the output stream | 
|
     * @param out stream to which the file data should be written | 
|
     * @return the number of bytes written to the output stream | 
|
     * @throws IOException if an I/O exception occurs | 
|
     * @throws IllegalArgumentException if the file format is not supported by | 
|
     * the system | 
|
     * @see #isFileTypeSupported(int, Sequence) | 
|
     * @see     #getMidiFileTypes(Sequence) | 
|
*/  | 
|
public static int write(Sequence in, int fileType, OutputStream out) throws IOException {  | 
|
List providers = getMidiFileWriters();  | 
|
        //$$fb 2002-04-17: Fix for 4635287: Standard MidiFileWriter cannot write empty Sequences | 
|
int bytesWritten = -2;  | 
|
for (int i = 0; i < providers.size(); i++ ) {  | 
|
MidiFileWriter writer = (MidiFileWriter) providers.get(i);  | 
|
if( writer.isFileTypeSupported( fileType, in ) ) {  | 
|
bytesWritten = writer.write(in, fileType, out);  | 
|
break;  | 
|
}  | 
|
}  | 
|
if (bytesWritten == -2) {  | 
|
throw new IllegalArgumentException("MIDI file type is not supported");  | 
|
}  | 
|
return bytesWritten;  | 
|
}  | 
|
    /** | 
|
     * Writes a stream of bytes representing a file of the MIDI file type | 
|
     * indicated to the external file provided. | 
|
     * @param in sequence containing MIDI data to be written to the file | 
|
     * @param type the file type of the file to be written to the output stream | 
|
     * @param out external file to which the file data should be written | 
|
     * @return the number of bytes written to the file | 
|
     * @throws IOException if an I/O exception occurs | 
|
     * @throws IllegalArgumentException if the file type is not supported by | 
|
     * the system | 
|
     * @see #isFileTypeSupported(int, Sequence) | 
|
     * @see     #getMidiFileTypes(Sequence) | 
|
*/  | 
|
public static int write(Sequence in, int type, File out) throws IOException {  | 
|
List providers = getMidiFileWriters();  | 
|
        //$$fb 2002-04-17: Fix for 4635287: Standard MidiFileWriter cannot write empty Sequences | 
|
int bytesWritten = -2;  | 
|
for (int i = 0; i < providers.size(); i++ ) {  | 
|
MidiFileWriter writer = (MidiFileWriter) providers.get(i);  | 
|
if( writer.isFileTypeSupported( type, in ) ) {  | 
|
bytesWritten = writer.write(in, type, out);  | 
|
break;  | 
|
}  | 
|
}  | 
|
if (bytesWritten == -2) {  | 
|
throw new IllegalArgumentException("MIDI file type is not supported");  | 
|
}  | 
|
return bytesWritten;  | 
|
}  | 
|
// HELPER METHODS  | 
|
private static List getMidiDeviceProviders() {  | 
|
return getProviders(MidiDeviceProvider.class);  | 
|
}  | 
|
private static List getSoundbankReaders() {  | 
|
return getProviders(SoundbankReader.class);  | 
|
}  | 
|
private static List getMidiFileWriters() {  | 
|
return getProviders(MidiFileWriter.class);  | 
|
}  | 
|
private static List getMidiFileReaders() {  | 
|
return getProviders(MidiFileReader.class);  | 
|
}  | 
|
    /** Attempts to locate and return a default MidiDevice of the specified | 
|
     * type. | 
|
     * | 
|
     * This method wraps {@link #getDefaultDevice}. It catches the | 
|
     * <code>IllegalArgumentException</code> thrown by | 
|
     * <code>getDefaultDevice</code> and instead throws a | 
|
     * <code>MidiUnavailableException</code>, with the catched | 
|
     * exception chained. | 
|
     * | 
|
     * @param deviceClass The requested device type, one of Synthesizer.class, | 
|
     * Sequencer.class, Receiver.class or Transmitter.class. | 
|
     * @throws  MidiUnavalableException on failure. | 
|
*/  | 
|
private static MidiDevice getDefaultDeviceWrapper(Class deviceClass)  | 
|
throws MidiUnavailableException{  | 
|
        try { | 
|
return getDefaultDevice(deviceClass);  | 
|
} catch (IllegalArgumentException iae) {  | 
|
MidiUnavailableException mae = new MidiUnavailableException();  | 
|
mae.initCause(iae);  | 
|
throw mae;  | 
|
}  | 
|
}  | 
|
    /** Attempts to locate and return a default MidiDevice of the specified | 
|
     * type. | 
|
     * | 
|
     * @param deviceClass The requested device type, one of Synthesizer.class, | 
|
     * Sequencer.class, Receiver.class or Transmitter.class. | 
|
     * @throws  IllegalArgumentException on failure. | 
|
*/  | 
|
private static MidiDevice getDefaultDevice(Class deviceClass) {  | 
|
List providers = getMidiDeviceProviders();  | 
|
String providerClassName = JDK13Services.getDefaultProviderClassName(deviceClass);  | 
|
String instanceName = JDK13Services.getDefaultInstanceName(deviceClass);  | 
|
MidiDevice device;  | 
|
if (providerClassName != null) {  | 
|
MidiDeviceProvider defaultProvider = getNamedProvider(providerClassName, providers);  | 
|
if (defaultProvider != null) {  | 
|
if (instanceName != null) {  | 
|
device = getNamedDevice(instanceName, defaultProvider, deviceClass);  | 
|
if (device != null) {  | 
|
return device;  | 
|
}  | 
|
}  | 
|
device = getFirstDevice(defaultProvider, deviceClass);  | 
|
if (device != null) {  | 
|
return device;  | 
|
}  | 
|
}  | 
|
}  | 
|
        /* Provider class not specified or cannot be found, or | 
|
           provider class specified, and no appropriate device available or | 
|
provider class and instance specified and instance cannot be found or is not appropriate */  | 
|
if (instanceName != null) {  | 
|
device = getNamedDevice(instanceName, providers, deviceClass);  | 
|
if (device != null) {  | 
|
return device;  | 
|
}  | 
|
}  | 
|
        /* No default are specified, or if something is specified, everything | 
|
failed. */  | 
|
device = getFirstDevice(providers, deviceClass);  | 
|
if (device != null) {  | 
|
return device;  | 
|
}  | 
|
throw new IllegalArgumentException("Requested device not installed");  | 
|
}  | 
|
    /** Return a MidiDeviceProcider of a given class from the list of | 
|
        MidiDeviceProviders. | 
|
 | 
|
        @param providerClassName The class name of the provider to be returned. | 
|
        @param provider The list of MidiDeviceProviders that is searched. | 
|
        @return A MidiDeviceProvider of the requested class, or null if none | 
|
        is found. | 
|
*/  | 
|
private static MidiDeviceProvider getNamedProvider(String providerClassName, List providers) {  | 
|
for(int i = 0; i < providers.size(); i++) {  | 
|
MidiDeviceProvider provider = (MidiDeviceProvider) providers.get(i);  | 
|
if (provider.getClass().getName().equals(providerClassName)) {  | 
|
return provider;  | 
|
}  | 
|
}  | 
|
return null;  | 
|
}  | 
|
    /** Return a MidiDevice with a given name from a given MidiDeviceProvider. | 
|
        @param deviceName The name of the MidiDevice to be returned. | 
|
        @param provider The MidiDeviceProvider to check for MidiDevices. | 
|
        @param deviceClass The requested device type, one of Synthesizer.class, | 
|
        Sequencer.class, Receiver.class or Transmitter.class. | 
|
 | 
|
        @return A MidiDevice matching the requirements, or null if none is found. | 
|
*/  | 
|
private static MidiDevice getNamedDevice(String deviceName,  | 
|
MidiDeviceProvider provider,  | 
|
Class deviceClass) {  | 
|
MidiDevice device;  | 
|
        // try to get MIDI port | 
|
device = getNamedDevice(deviceName, provider, deviceClass,  | 
|
false, false);  | 
|
if (device != null) {  | 
|
return device;  | 
|
}  | 
|
if (deviceClass == Receiver.class) {  | 
|
            // try to get Synthesizer | 
|
device = getNamedDevice(deviceName, provider, deviceClass,  | 
|
true, false);  | 
|
if (device != null) {  | 
|
return device;  | 
|
}  | 
|
}  | 
|
return null;  | 
|
}  | 
|
    /** Return a MidiDevice with a given name from a given MidiDeviceProvider. | 
|
      @param deviceName The name of the MidiDevice to be returned. | 
|
      @param provider The MidiDeviceProvider to check for MidiDevices. | 
|
      @param deviceClass The requested device type, one of Synthesizer.class, | 
|
      Sequencer.class, Receiver.class or Transmitter.class. | 
|
 | 
|
      @return A MidiDevice matching the requirements, or null if none is found. | 
|
*/  | 
|
private static MidiDevice getNamedDevice(String deviceName,  | 
|
MidiDeviceProvider provider,  | 
|
Class deviceClass,  | 
|
boolean allowSynthesizer,  | 
|
                                             boolean allowSequencer) { | 
|
MidiDevice.Info[] infos = provider.getDeviceInfo();  | 
|
for (int i = 0; i < infos.length; i++) {  | 
|
if (infos[i].getName().equals(deviceName)) {  | 
|
MidiDevice device = provider.getDevice(infos[i]);  | 
|
if (isAppropriateDevice(device, deviceClass,  | 
|
allowSynthesizer, allowSequencer)) {  | 
|
return device;  | 
|
}  | 
|
}  | 
|
}  | 
|
return null;  | 
|
}  | 
|
    /** Return a MidiDevice with a given name from a list of | 
|
        MidiDeviceProviders. | 
|
        @param deviceName The name of the MidiDevice to be returned. | 
|
        @param providers The List of MidiDeviceProviders to check for | 
|
        MidiDevices. | 
|
        @param deviceClass The requested device type, one of Synthesizer.class, | 
|
        Sequencer.class, Receiver.class or Transmitter.class. | 
|
        @return A Mixer matching the requirements, or null if none is found. | 
|
*/  | 
|
private static MidiDevice getNamedDevice(String deviceName,  | 
|
List providers,  | 
|
Class deviceClass) {  | 
|
MidiDevice device;  | 
|
        // try to get MIDI port | 
|
device = getNamedDevice(deviceName, providers, deviceClass,  | 
|
false, false);  | 
|
if (device != null) {  | 
|
return device;  | 
|
}  | 
|
if (deviceClass == Receiver.class) {  | 
|
            // try to get Synthesizer | 
|
device = getNamedDevice(deviceName, providers, deviceClass,  | 
|
true, false);  | 
|
if (device != null) {  | 
|
return device;  | 
|
}  | 
|
}  | 
|
return null;  | 
|
}  | 
|
    /** Return a MidiDevice with a given name from a list of | 
|
        MidiDeviceProviders. | 
|
        @param deviceName The name of the MidiDevice to be returned. | 
|
        @param providers The List of MidiDeviceProviders to check for | 
|
        MidiDevices. | 
|
        @param deviceClass The requested device type, one of Synthesizer.class, | 
|
        Sequencer.class, Receiver.class or Transmitter.class. | 
|
        @return A Mixer matching the requirements, or null if none is found. | 
|
*/  | 
|
private static MidiDevice getNamedDevice(String deviceName,  | 
|
List providers,  | 
|
Class deviceClass,  | 
|
boolean allowSynthesizer,  | 
|
                                             boolean allowSequencer) { | 
|
for(int i = 0; i < providers.size(); i++) {  | 
|
MidiDeviceProvider provider = (MidiDeviceProvider) providers.get(i);  | 
|
MidiDevice device = getNamedDevice(deviceName, provider,  | 
|
deviceClass,  | 
|
allowSynthesizer,  | 
|
allowSequencer);  | 
|
if (device != null) {  | 
|
return device;  | 
|
}  | 
|
}  | 
|
return null;  | 
|
}  | 
|
    /** From a given MidiDeviceProvider, return the first appropriate device. | 
|
        @param provider The MidiDeviceProvider to check for MidiDevices. | 
|
        @param deviceClass The requested device type, one of Synthesizer.class, | 
|
        Sequencer.class, Receiver.class or Transmitter.class. | 
|
        @return A MidiDevice is considered appropriate, or null if no | 
|
        appropriate device is found. | 
|
*/  | 
|
private static MidiDevice getFirstDevice(MidiDeviceProvider provider,  | 
|
Class deviceClass) {  | 
|
MidiDevice device;  | 
|
        // try to get MIDI port | 
|
device = getFirstDevice(provider, deviceClass,  | 
|
false, false);  | 
|
if (device != null) {  | 
|
return device;  | 
|
}  | 
|
if (deviceClass == Receiver.class) {  | 
|
            // try to get Synthesizer | 
|
device = getFirstDevice(provider, deviceClass,  | 
|
true, false);  | 
|
if (device != null) {  | 
|
return device;  | 
|
}  | 
|
}  | 
|
return null;  | 
|
}  | 
|
    /** From a given MidiDeviceProvider, return the first appropriate device. | 
|
        @param provider The MidiDeviceProvider to check for MidiDevices. | 
|
        @param deviceClass The requested device type, one of Synthesizer.class, | 
|
        Sequencer.class, Receiver.class or Transmitter.class. | 
|
        @return A MidiDevice is considered appropriate, or null if no | 
|
        appropriate device is found. | 
|
*/  | 
|
private static MidiDevice getFirstDevice(MidiDeviceProvider provider,  | 
|
Class deviceClass,  | 
|
boolean allowSynthesizer,  | 
|
                                             boolean allowSequencer) { | 
|
MidiDevice.Info[] infos = provider.getDeviceInfo();  | 
|
for (int j = 0; j < infos.length; j++) {  | 
|
MidiDevice device = provider.getDevice(infos[j]);  | 
|
if (isAppropriateDevice(device, deviceClass,  | 
|
allowSynthesizer, allowSequencer)) {  | 
|
return device;  | 
|
}  | 
|
}  | 
|
return null;  | 
|
}  | 
|
    /** From a List of MidiDeviceProviders, return the first appropriate | 
|
        MidiDevice. | 
|
        @param providers The List of MidiDeviceProviders to search. | 
|
        @param deviceClass The requested device type, one of Synthesizer.class, | 
|
        Sequencer.class, Receiver.class or Transmitter.class. | 
|
        @return A MidiDevice that is considered appropriate, or null | 
|
        if none is found. | 
|
*/  | 
|
private static MidiDevice getFirstDevice(List providers,  | 
|
Class deviceClass) {  | 
|
MidiDevice device;  | 
|
        // try to get MIDI port | 
|
device = getFirstDevice(providers, deviceClass,  | 
|
false, false);  | 
|
if (device != null) {  | 
|
return device;  | 
|
}  | 
|
if (deviceClass == Receiver.class) {  | 
|
            // try to get Synthesizer | 
|
device = getFirstDevice(providers, deviceClass,  | 
|
true, false);  | 
|
if (device != null) {  | 
|
return device;  | 
|
}  | 
|
}  | 
|
return null;  | 
|
}  | 
|
    /** From a List of MidiDeviceProviders, return the first appropriate | 
|
        MidiDevice. | 
|
        @param providers The List of MidiDeviceProviders to search. | 
|
        @param deviceClass The requested device type, one of Synthesizer.class, | 
|
        Sequencer.class, Receiver.class or Transmitter.class. | 
|
        @return A MidiDevice that is considered appropriate, or null | 
|
        if none is found. | 
|
*/  | 
|
private static MidiDevice getFirstDevice(List providers,  | 
|
Class deviceClass,  | 
|
boolean allowSynthesizer,  | 
|
                                             boolean allowSequencer) { | 
|
for(int i = 0; i < providers.size(); i++) {  | 
|
MidiDeviceProvider provider = (MidiDeviceProvider) providers.get(i);  | 
|
MidiDevice device = getFirstDevice(provider, deviceClass,  | 
|
allowSynthesizer,  | 
|
allowSequencer);  | 
|
if (device != null) {  | 
|
return device;  | 
|
}  | 
|
}  | 
|
return null;  | 
|
}  | 
|
    /** Checks if a MidiDevice is appropriate. | 
|
        If deviceClass is Synthesizer or Sequencer, a device implementing | 
|
        the respective interface is considered appropriate. If deviceClass | 
|
        is Receiver or Transmitter, a device is considered appropriate if | 
|
        it implements neither Synthesizer nor Transmitter, and if it can | 
|
        provide at least one Receiver or Transmitter, respectively. | 
|
 | 
|
        @param device the MidiDevice to test | 
|
        @param allowSynthesizer if true, Synthesizers are considered | 
|
        appropriate. Otherwise only pure MidiDevices are considered | 
|
        appropriate (unless allowSequencer is true). This flag only has an | 
|
        effect for deviceClass Receiver and Transmitter. For other device | 
|
        classes (Sequencer and Synthesizer), this flag has no effect. | 
|
        @param allowSequencer if true, Sequencers are considered | 
|
        appropriate. Otherwise only pure MidiDevices are considered | 
|
        appropriate (unless allowSynthesizer is true). This flag only has an | 
|
        effect for deviceClass Receiver and Transmitter. For other device | 
|
        classes (Sequencer and Synthesizer), this flag has no effect. | 
|
        @return true if the device is considered appropriate according to the | 
|
        rules given above, false otherwise. | 
|
*/  | 
|
private static boolean isAppropriateDevice(MidiDevice device,  | 
|
Class deviceClass,  | 
|
boolean allowSynthesizer,  | 
|
                                               boolean allowSequencer) { | 
|
if (deviceClass.isInstance(device)) {  | 
|
// This clause is for deviceClass being either Synthesizer  | 
|
            // or Sequencer. | 
|
return true;  | 
|
        } else { | 
|
// Now the case that deviceClass is Transmitter or  | 
|
// Receiver. If neither allowSynthesizer nor allowSequencer is  | 
|
// true, we require device instances to be  | 
|
// neither Synthesizer nor Sequencer, since we only want  | 
|
// devices representing MIDI ports.  | 
|
            // Otherwise, the respective type is accepted, too | 
|
if ( (! (device instanceof Sequencer) &&  | 
|
! (device instanceof Synthesizer) ) ||  | 
|
((device instanceof Sequencer) && allowSequencer) ||  | 
|
((device instanceof Synthesizer) && allowSynthesizer)) {  | 
|
// And of cource, the device has to be able to provide  | 
|
                // Receivers or Transmitters. | 
|
if ((deviceClass == Receiver.class &&  | 
|
device.getMaxReceivers() != 0) ||  | 
|
(deviceClass == Transmitter.class &&  | 
|
device.getMaxTransmitters() != 0)) {  | 
|
return true;  | 
|
}  | 
|
}  | 
|
}  | 
|
return false;  | 
|
}  | 
|
    /** | 
|
     * Obtains the set of services currently installed on the system | 
|
     * using sun.misc.Service, the SPI mechanism in 1.3. | 
|
     * @return a List of instances of providers for the requested service. | 
|
     * If no providers are available, a List of length 0 will be returned. | 
|
*/  | 
|
private static List getProviders(Class providerClass) {  | 
|
return JDK13Services.getProviders(providerClass);  | 
|
}  | 
|
}  |