1480 lines · 58.2 KB · Java
RawDownload
/* * Copyright (c) 1999, 2011, 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 properties file is &quot;lib/sound.properties&quot; in the JRE * 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> *  <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 (&quot;#&quot;). * 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 * successully 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>&quot;com.sun.media.sound.MidiProvider#SunMIDI1&quot;</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>&quot;SunMIDI1&quot;</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>&quot;SunMIDI1&quot;</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 &quot;sound.properties&quot;,     * 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 &quot;sound.properties&quot;,     * 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 &quot;sound.properties&quot;,     * 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 &quot;sound.properties&quot;,     * 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}.     *     * @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;    }   

Lines 1–500 of 1480.