Save This Page
Home » openjdk-7 » javax.sound » midi » [javadoc | source]
    1   /*
    2    * Copyright 1999-2006 Sun Microsystems, Inc.  All Rights Reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Sun designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Sun in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
   22    * CA 95054 USA or visit www.sun.com if you need additional information or
   23    * have any questions.
   24    */
   25   
   26   package javax.sound.midi;
   27   
   28   import java.io.FileInputStream;
   29   import java.io.File;
   30   import java.io.InputStream;
   31   import java.io.OutputStream;
   32   import java.io.IOException;
   33   
   34   import java.util.ArrayList;
   35   import java.util.HashSet;
   36   import java.util.Iterator;
   37   import java.util.List;
   38   import java.util.Set;
   39   
   40   import java.net.URL;
   41   
   42   import javax.sound.midi.spi.MidiFileWriter;
   43   import javax.sound.midi.spi.MidiFileReader;
   44   import javax.sound.midi.spi.SoundbankReader;
   45   import javax.sound.midi.spi.MidiDeviceProvider;
   46   
   47   import com.sun.media.sound.JDK13Services;
   48   import com.sun.media.sound.ReferenceCountingDevice;
   49   import com.sun.media.sound.AutoConnectSequencer;
   50   
   51   
   52   /**
   53    * The <code>MidiSystem</code> class provides access to the installed MIDI
   54    * system resources, including devices such as synthesizers, sequencers, and
   55    * MIDI input and output ports.  A typical simple MIDI application might
   56    * begin by invoking one or more <code>MidiSystem</code> methods to learn
   57    * what devices are installed and to obtain the ones needed in that
   58    * application.
   59    * <p>
   60    * The class also has methods for reading files, streams, and  URLs that
   61    * contain standard MIDI file data or soundbanks.  You can query the
   62    * <code>MidiSystem</code> for the format of a specified MIDI file.
   63    * <p>
   64    * You cannot instantiate a <code>MidiSystem</code>; all the methods are
   65    * static.
   66    *
   67    * <p>Properties can be used to specify default MIDI devices.
   68    * Both system properties and a properties file are considered.
   69    * The properties file is &quot;lib/sound.properties&quot; in the JRE
   70    * directory. If a property exists both as a system property and in the
   71    * properties file, the system property takes precedence. If none is
   72    * specified, a suitable default is chosen among the available devices.
   73    * The syntax of the properties file is specified in
   74    * {@link java.util.Properties#load(InputStream) Properties.load}. The
   75    * following table lists the available property keys and which methods
   76    * consider them:
   77    *
   78    * <table border=0>
   79    *  <tr>
   80    *   <th>Property Key</th>
   81    *   <th>Interface</th>
   82    *   <th>Affected Method</th>
   83    *  </tr>
   84    *  <tr>
   85    *   <td><code>javax.sound.midi.Receiver</code></td>
   86    *   <td>{@link Receiver}</td>
   87    *   <td>{@link #getReceiver}</td>
   88    *  </tr>
   89    *  <tr>
   90    *   <td><code>javax.sound.midi.Sequencer</code></td>
   91    *   <td>{@link Sequencer}</td>
   92    *   <td>{@link #getSequencer}</td>
   93    *  </tr>
   94    *  <tr>
   95    *   <td><code>javax.sound.midi.Synthesizer</code></td>
   96    *   <td>{@link Synthesizer}</td>
   97    *   <td>{@link #getSynthesizer}</td>
   98    *  </tr>
   99    *  <tr>
  100    *   <td><code>javax.sound.midi.Transmitter</code></td>
  101    *   <td>{@link Transmitter}</td>
  102    *   <td>{@link #getTransmitter}</td>
  103    *  </tr>
  104    * </table>
  105    *
  106    * The property value consists of the provider class name
  107    * and the device name, separated by the hash mark (&quot;#&quot;).
  108    * The provider class name is the fully-qualified
  109    * name of a concrete {@link javax.sound.midi.spi.MidiDeviceProvider
  110    * MIDI device provider} class. The device name is matched against
  111    * the <code>String</code> returned by the <code>getName</code>
  112    * method of <code>MidiDevice.Info</code>.
  113    * Either the class name, or the device name may be omitted.
  114    * If only the class name is specified, the trailing hash mark
  115    * is optional.
  116    *
  117    * <p>If the provider class is specified, and it can be
  118    * successully retrieved from the installed providers,
  119    * the list of
  120    * <code>MidiDevice.Info</code> objects is retrieved
  121    * from the provider. Otherwise, or when these devices
  122    * do not provide a subsequent match, the list is retrieved
  123    * from {@link #getMidiDeviceInfo} to contain
  124    * all available <code>MidiDevice.Info</code> objects.
  125    *
  126    * <p>If a device name is specified, the resulting list of
  127    * <code>MidiDevice.Info</code> objects is searched:
  128    * the first one with a matching name, and whose
  129    * <code>MidiDevice</code> implements the
  130    * respective interface, will be returned.
  131    * If no matching <code>MidiDevice.Info</code> object
  132    * is found, or the device name is not specified,
  133    * the first suitable device from the resulting
  134    * list will be returned. For Sequencer and Synthesizer,
  135    * a device is suitable if it implements the respective
  136    * interface; whereas for Receiver and Transmitter, a device is
  137    * suitable if it
  138    * implements neither Sequencer nor Synthesizer and provides
  139    * at least one Receiver or Transmitter, respectively.
  140    *
  141    * For example, the property <code>javax.sound.midi.Receiver</code>
  142    * with a value
  143    * <code>&quot;com.sun.media.sound.MidiProvider#SunMIDI1&quot;</code>
  144    * will have the following consequences when
  145    * <code>getReceiver</code> is called:
  146    * if the class <code>com.sun.media.sound.MidiProvider</code> exists
  147    * in the list of installed MIDI device providers,
  148    * the first <code>Receiver</code> device with name
  149    * <code>&quot;SunMIDI1&quot;</code> will be returned. If it cannot
  150    * be found, the first <code>Receiver</code> from that provider
  151    * will be returned, regardless of name.
  152    * If there is none, the first <code>Receiver</code> with name
  153    * <code>&quot;SunMIDI1&quot;</code> in the list of all devices
  154    * (as returned by <code>getMidiDeviceInfo</code>) will be returned,
  155    * or, if not found, the first <code>Receiver</code> that can
  156    * be found in the list of all devices is returned.
  157    * If that fails, too, a <code>MidiUnavailableException</code>
  158    * is thrown.
  159    *
  160    * @author Kara Kytle
  161    * @author Florian Bomers
  162    * @author Matthias Pfisterer
  163    */
  164   public class MidiSystem {
  165   
  166       /**
  167        * Private no-args constructor for ensuring against instantiation.
  168        */
  169       private MidiSystem() {
  170       }
  171   
  172   
  173       /**
  174        * Obtains an array of information objects representing
  175        * the set of all MIDI devices available on the system.
  176        * A returned information object can then be used to obtain the
  177        * corresponding device object, by invoking
  178        * {@link #getMidiDevice(MidiDevice.Info) getMidiDevice}.
  179        *
  180        * @return an array of <code>MidiDevice.Info</code> objects, one
  181        * for each installed MIDI device.  If no such devices are installed,
  182        * an array of length 0 is returned.
  183        */
  184       public static MidiDevice.Info[] getMidiDeviceInfo() {
  185           List allInfos = new ArrayList();
  186           List providers = getMidiDeviceProviders();
  187   
  188           for(int i = 0; i < providers.size(); i++) {
  189               MidiDeviceProvider provider = (MidiDeviceProvider) providers.get(i);
  190               MidiDevice.Info[] tmpinfo = provider.getDeviceInfo();
  191               for (int j = 0; j < tmpinfo.length; j++) {
  192                   allInfos.add( tmpinfo[j] );
  193               }
  194           }
  195           MidiDevice.Info[] infosArray = (MidiDevice.Info[]) allInfos.toArray(new MidiDevice.Info[0]);
  196           return infosArray;
  197       }
  198   
  199   
  200       /**
  201        * Obtains the requested MIDI device.
  202        *
  203        * @param info a device information object representing the desired device.
  204        * @return the requested device
  205        * @throws MidiUnavailableException if the requested device is not available
  206        * due to resource restrictions
  207        * @throws IllegalArgumentException if the info object does not represent
  208        * a MIDI device installed on the system
  209        * @see #getMidiDeviceInfo
  210        */
  211       public static MidiDevice getMidiDevice(MidiDevice.Info info) throws MidiUnavailableException {
  212           List providers = getMidiDeviceProviders();
  213   
  214           for(int i = 0; i < providers.size(); i++) {
  215               MidiDeviceProvider provider = (MidiDeviceProvider) providers.get(i);
  216               if (provider.isDeviceSupported(info)) {
  217                   MidiDevice device = provider.getDevice(info);
  218                   return device;
  219               }
  220           }
  221           throw new IllegalArgumentException("Requested device not installed: " + info);
  222       }
  223   
  224   
  225       /**
  226        * Obtains a MIDI receiver from an external MIDI port
  227        * or other default device.
  228        *
  229        * <p>If the system property
  230        * <code>javax.sound.midi.Receiver</code>
  231        * is defined or it is defined in the file &quot;sound.properties&quot;,
  232        * it is used to identify the device that provides the default receiver.
  233        * For details, refer to the {@link MidiSystem class description}.
  234        *
  235        * If a suitable MIDI port is not available, the Receiver is
  236        * retrieved from an installed synthesizer.
  237        *
  238        * <p>If this method returns successfully, the {@link
  239        * javax.sound.midi.MidiDevice MidiDevice} the
  240        * <code>Receiver</code> belongs to is opened implicitly, if it is
  241        * not already open. It is possible to close an implicitly opened
  242        * device by calling {@link javax.sound.midi.Receiver#close close}
  243        * on the returned <code>Receiver</code>. All open <code>Receiver</code>
  244        * instances have to be closed in order to release system resources
  245        * hold by the <code>MidiDevice</code>. For a
  246        * detailed description of open/close behaviour see the class
  247        * description of {@link javax.sound.midi.MidiDevice MidiDevice}.
  248        *
  249        *
  250        * @return the default MIDI receiver
  251        * @throws MidiUnavailableException if the default receiver is not
  252        *         available due to resource restrictions,
  253        *         or no device providing receivers is installed in the system
  254        */
  255       public static Receiver getReceiver() throws MidiUnavailableException {
  256           // may throw MidiUnavailableException
  257           MidiDevice device = getDefaultDeviceWrapper(Receiver.class);
  258           Receiver receiver;
  259           if (device instanceof ReferenceCountingDevice) {
  260               receiver = ((ReferenceCountingDevice) device).getReceiverReferenceCounting();
  261           } else {
  262               receiver = device.getReceiver();
  263           }
  264           return receiver;
  265       }
  266   
  267   
  268       /**
  269        * Obtains a MIDI transmitter from an external MIDI port
  270        * or other default source.
  271        *
  272        * <p>If the system property
  273        * <code>javax.sound.midi.Transmitter</code>
  274        * is defined or it is defined in the file &quot;sound.properties&quot;,
  275        * it is used to identify the device that provides the default transmitter.
  276        * For details, refer to the {@link MidiSystem class description}.
  277        *
  278        * If this method returns successfully, the {@link
  279        * javax.sound.midi.MidiDevice MidiDevice} the
  280        * <code>Transmitter</code> belongs to is opened implicitly, if it
  281        * is not already open. It is possible to close an implicitly
  282        * opened device by calling {@link
  283        * javax.sound.midi.Transmitter#close close} on the returned
  284        * <code>Transmitter</code>. All open <code>Transmitter</code>
  285        * instances have to be closed in order to release system resources
  286        * hold by the <code>MidiDevice</code>. For a detailed description
  287        * of open/close behaviour see the class description of {@link
  288        * javax.sound.midi.MidiDevice MidiDevice}.
  289        *
  290        * @return the default MIDI transmitter
  291        * @throws MidiUnavailableException if the default transmitter is not
  292        *         available due to resource restrictions,
  293        *         or no device providing transmitters is installed in the system
  294        */
  295       public static Transmitter getTransmitter() throws MidiUnavailableException {
  296           // may throw MidiUnavailableException
  297           MidiDevice device = getDefaultDeviceWrapper(Transmitter.class);
  298           Transmitter transmitter;
  299           if (device instanceof ReferenceCountingDevice) {
  300               transmitter = ((ReferenceCountingDevice) device).getTransmitterReferenceCounting();
  301           } else {
  302               transmitter = device.getTransmitter();
  303           }
  304           return transmitter;
  305       }
  306   
  307   
  308       /**
  309        * Obtains the default synthesizer.
  310        *
  311        * <p>If the system property
  312        * <code>javax.sound.midi.Synthesizer</code>
  313        * is defined or it is defined in the file &quot;sound.properties&quot;,
  314        * it is used to identify the default synthesizer.
  315        * For details, refer to the {@link MidiSystem class description}.
  316        *
  317        * @return the default synthesizer
  318        * @throws MidiUnavailableException if the synthesizer is not
  319        *         available due to resource restrictions,
  320        *         or no synthesizer is installed in the system
  321        */
  322       public static Synthesizer getSynthesizer() throws MidiUnavailableException {
  323           // may throw MidiUnavailableException
  324           return (Synthesizer) getDefaultDeviceWrapper(Synthesizer.class);
  325       }
  326   
  327   
  328       /**
  329        * Obtains the default <code>Sequencer</code>, connected to
  330        * a default device.
  331        * The returned <code>Sequencer</code> instance is
  332        * connected to the default <code>Synthesizer</code>,
  333        * as returned by {@link #getSynthesizer}.
  334        * If there is no <code>Synthesizer</code>
  335        * available, or the default <code>Synthesizer</code>
  336        * cannot be opened, the <code>sequencer</code> is connected
  337        * to the default <code>Receiver</code>, as returned
  338        * by {@link #getReceiver}.
  339        * The connection is made by retrieving a <code>Transmitter</code>
  340        * instance from the <code>Sequencer</code> and setting its
  341        * <code>Receiver</code>.
  342        * Closing and re-opening the sequencer will restore the
  343        * connection to the default device.
  344        *
  345        * <p>This method is equivalent to calling
  346        * <code>getSequencer(true)</code>.
  347        *
  348        * <p>If the system property
  349        * <code>javax.sound.midi.Sequencer</code>
  350        * is defined or it is defined in the file &quot;sound.properties&quot;,
  351        * it is used to identify the default sequencer.
  352        * For details, refer to the {@link MidiSystem class description}.
  353        *
  354        * @return the default sequencer, connected to a default Receiver
  355        * @throws MidiUnavailableException if the sequencer is not
  356        *         available due to resource restrictions,
  357        *         or there is no <code>Receiver</code> available by any
  358        *         installed <code>MidiDevice</code>,
  359        *         or no sequencer is installed in the system.
  360        * @see #getSequencer(boolean)
  361        * @see #getSynthesizer
  362        * @see #getReceiver
  363        */
  364       public static Sequencer getSequencer() throws MidiUnavailableException {
  365           return getSequencer(true);
  366       }
  367   
  368   
  369   
  370       /**
  371        * Obtains the default <code>Sequencer</code>, optionally
  372        * connected to a default device.
  373        *
  374        * <p>If <code>connected</code> is true, the returned
  375        * <code>Sequencer</code> instance is
  376        * connected to the default <code>Synthesizer</code>,
  377        * as returned by {@link #getSynthesizer}.
  378        * If there is no <code>Synthesizer</code>
  379        * available, or the default <code>Synthesizer</code>
  380        * cannot be opened, the <code>sequencer</code> is connected
  381        * to the default <code>Receiver</code>, as returned
  382        * by {@link #getReceiver}.
  383        * The connection is made by retrieving a <code>Transmitter</code>
  384        * instance from the <code>Sequencer</code> and setting its
  385        * <code>Receiver</code>.
  386        * Closing and re-opening the sequencer will restore the
  387        * connection to the default device.
  388        *
  389        * <p>If <code>connected</code> is false, the returned
  390        * <code>Sequencer</code> instance is not connected, it
  391        * has no open <code>Transmitters</code>. In order to
  392        * play the sequencer on a MIDI device, or a <code>Synthesizer</code>,
  393        * it is necessary to get a <code>Transmitter</code> and set its
  394        * <code>Receiver</code>.
  395        *
  396        * <p>If the system property
  397        * <code>javax.sound.midi.Sequencer</code>
  398        * is defined or it is defined in the file "sound.properties",
  399        * it is used to identify the default sequencer.
  400        * For details, refer to the {@link MidiSystem class description}.
  401        *
  402        * @return the default sequencer
  403        * @throws MidiUnavailableException if the sequencer is not
  404        *         available due to resource restrictions,
  405        *         or no sequencer is installed in the system,
  406        *         or if <code>connected</code> is true, and there is
  407        *         no <code>Receiver</code> available by any installed
  408        *         <code>MidiDevice</code>
  409        * @see #getSynthesizer
  410        * @see #getReceiver
  411        * @since 1.5
  412        */
  413       public static Sequencer getSequencer(boolean connected)
  414           throws MidiUnavailableException {
  415           Sequencer seq = (Sequencer) getDefaultDeviceWrapper(Sequencer.class);
  416   
  417           if (connected) {
  418               // IMPORTANT: this code needs to be synch'ed with
  419               //            all AutoConnectSequencer instances,
  420               //            (e.g. RealTimeSequencer) because the
  421               //            same algorithm for synth retrieval
  422               //            needs to be used!
  423   
  424               Receiver rec = null;
  425               MidiUnavailableException mue = null;
  426   
  427               // first try to connect to the default synthesizer
  428               try {
  429                   Synthesizer synth = getSynthesizer();
  430                   if (synth instanceof ReferenceCountingDevice) {
  431                       rec = ((ReferenceCountingDevice) synth).getReceiverReferenceCounting();
  432                       // only use MixerSynth if it could successfully load a soundbank
  433                       if (synth.getClass().toString().contains("com.sun.media.sound.MixerSynth")
  434                           && (synth.getDefaultSoundbank() == null)) {
  435                           // don't use this receiver if no soundbank available
  436                           rec = null;
  437                           synth.close();
  438                       }
  439                   } else {
  440                       synth.open();
  441                       try {
  442                           rec = synth.getReceiver();
  443                       } finally {
  444                           // make sure that the synth is properly closed
  445                           if (rec == null) {
  446                               synth.close();
  447                           }
  448                       }
  449                   }
  450               } catch (MidiUnavailableException e) {
  451                   // something went wrong with synth
  452                   if (e instanceof MidiUnavailableException) {
  453                       mue = (MidiUnavailableException) e;
  454                   }
  455               }
  456               if (rec == null) {
  457                   // then try to connect to the default Receiver
  458                   try {
  459                       rec = MidiSystem.getReceiver();
  460                   } catch (Exception e) {
  461                       // something went wrong. Nothing to do then!
  462                       if (e instanceof MidiUnavailableException) {
  463                           mue = (MidiUnavailableException) e;
  464                       }
  465                   }
  466               }
  467               if (rec != null) {
  468                   seq.getTransmitter().setReceiver(rec);
  469                   if (seq instanceof AutoConnectSequencer) {
  470                       ((AutoConnectSequencer) seq).setAutoConnect(rec);
  471                   }
  472               } else {
  473                   if (mue != null) {
  474                       throw mue;
  475                   }
  476                   throw new MidiUnavailableException("no receiver available");
  477               }
  478           }
  479           return seq;
  480       }
  481   
  482   
  483   
  484   
  485       /**
  486        * Constructs a MIDI sound bank by reading it from the specified stream.
  487        * The stream must point to
  488        * a valid MIDI soundbank file.  In general, MIDI soundbank providers may
  489        * need to read some data from the stream before determining whether they
  490        * support it.  These parsers must
  491        * be able to mark the stream, read enough data to determine whether they
  492        * support the stream, and, if not, reset the stream's read pointer to
  493        * its original position.  If the input stream does not support this,
  494        * this method may fail with an IOException.
  495        * @param stream the source of the sound bank data.
  496        * @return the sound bank
  497        * @throws InvalidMidiDataException if the stream does not point to
  498        * valid MIDI soundbank data recognized by the system
  499        * @throws IOException if an I/O error occurred when loading the soundbank
  500        * @see InputStream#markSupported
  501        * @see InputStream#mark
  502        */
  503       public static Soundbank getSoundbank(InputStream stream)
  504           throws InvalidMidiDataException, IOException {
  505   
  506           SoundbankReader sp = null;
  507           Soundbank s = null;
  508   
  509           List providers = getSoundbankReaders();
  510   
  511           for(int i = 0; i < providers.size(); i++) {
  512               sp = (SoundbankReader)providers.get(i);
  513               s = sp.getSoundbank(stream);
  514   
  515               if( s!= null) {
  516                   return s;
  517               }
  518           }
  519           throw new InvalidMidiDataException("cannot get soundbank from stream");
  520   
  521       }
  522   
  523   
  524       /**
  525        * Constructs a <code>Soundbank</code> by reading it from the specified URL.
  526        * The URL must point to a valid MIDI soundbank file.
  527        *
  528        * @param url the source of the sound bank data
  529        * @return the sound bank
  530        * @throws InvalidMidiDataException if the URL does not point to valid MIDI
  531        * soundbank data recognized by the system
  532        * @throws IOException if an I/O error occurred when loading the soundbank
  533        */
  534       public static Soundbank getSoundbank(URL url)
  535           throws InvalidMidiDataException, IOException {
  536   
  537           SoundbankReader sp = null;
  538           Soundbank s = null;
  539   
  540           List providers = getSoundbankReaders();
  541   
  542           for(int i = 0; i < providers.size(); i++) {
  543               sp = (SoundbankReader)providers.get(i);
  544               s = sp.getSoundbank(url);
  545   
  546               if( s!= null) {
  547                   return s;
  548               }
  549           }
  550           throw new InvalidMidiDataException("cannot get soundbank from stream");
  551   
  552       }
  553   
  554   
  555       /**
  556        * Constructs a <code>Soundbank</code> by reading it from the specified
  557        * <code>File</code>.
  558        * The <code>File</code> must point to a valid MIDI soundbank file.
  559        *
  560        * @param file the source of the sound bank data
  561        * @return the sound bank
  562        * @throws InvalidMidiDataException if the <code>File</code> does not
  563        * point to valid MIDI soundbank data recognized by the system
  564        * @throws IOException if an I/O error occurred when loading the soundbank
  565        */
  566       public static Soundbank getSoundbank(File file)
  567           throws InvalidMidiDataException, IOException {
  568   
  569           SoundbankReader sp = null;
  570           Soundbank s = null;
  571   
  572           List providers = getSoundbankReaders();
  573   
  574           for(int i = 0; i < providers.size(); i++) {
  575               sp = (SoundbankReader)providers.get(i);
  576               s = sp.getSoundbank(file);
  577   
  578               if( s!= null) {
  579                   return s;
  580               }
  581           }
  582           throw new InvalidMidiDataException("cannot get soundbank from stream");
  583       }
  584   
  585   
  586   
  587       /**
  588        * Obtains the MIDI file format of the data in the specified input stream.
  589        * The stream must point to valid MIDI file data for a file type recognized
  590        * by the system.
  591        * <p>
  592        * This method and/or the code it invokes may need to read some data from
  593        * the stream to determine whether its data format is supported.  The
  594        * implementation may therefore
  595        * need to mark the stream, read enough data to determine whether it is in
  596        * a supported format, and reset the stream's read pointer to its original
  597        * position.  If the input stream does not permit this set of operations,
  598        * this method may fail with an <code>IOException</code>.
  599        * <p>
  600        * This operation can only succeed for files of a type which can be parsed
  601        * by an installed file reader.  It may fail with an InvalidMidiDataException
  602        * even for valid files if no compatible file reader is installed.  It
  603        * will also fail with an InvalidMidiDataException if a compatible file reader
  604        * is installed, but encounters errors while determining the file format.
  605        *
  606        * @param stream the input stream from which file format information
  607        * should be extracted
  608        * @return an <code>MidiFileFormat</code> object describing the MIDI file
  609        * format
  610        * @throws InvalidMidiDataException if the stream does not point to valid
  611        * MIDI file data recognized by the system
  612        * @throws IOException if an I/O exception occurs while accessing the
  613        * stream
  614        * @see #getMidiFileFormat(URL)
  615        * @see #getMidiFileFormat(File)
  616        * @see InputStream#markSupported
  617        * @see InputStream#mark
  618        */
  619       public static MidiFileFormat getMidiFileFormat(InputStream stream)
  620           throws InvalidMidiDataException, IOException {
  621   
  622           List providers = getMidiFileReaders();
  623           MidiFileFormat format = null;
  624   
  625           for(int i = 0; i < providers.size(); i++) {
  626               MidiFileReader reader = (MidiFileReader) providers.get(i);
  627               try {
  628                   format = reader.getMidiFileFormat( stream ); // throws IOException
  629                   break;
  630               } catch (InvalidMidiDataException e) {
  631                   continue;
  632               }
  633           }
  634   
  635           if( format==null ) {
  636               throw new InvalidMidiDataException("input stream is not a supported file type");
  637           } else {
  638               return format;
  639           }
  640       }
  641   
  642   
  643       /**
  644        * Obtains the MIDI file format of the data in the specified URL.  The URL
  645        * must point to valid MIDI file data for a file type recognized
  646        * by the system.
  647        * <p>
  648        * This operation can only succeed for files of a type which can be parsed
  649        * by an installed file reader.  It may fail with an InvalidMidiDataException
  650        * even for valid files if no compatible file reader is installed.  It
  651        * will also fail with an InvalidMidiDataException if a compatible file reader
  652        * is installed, but encounters errors while determining the file format.
  653        *
  654        * @param url the URL from which file format information should be
  655        * extracted
  656        * @return a <code>MidiFileFormat</code> object describing the MIDI file
  657        * format
  658        * @throws InvalidMidiDataException if the URL does not point to valid MIDI
  659        * file data recognized by the system
  660        * @throws IOException if an I/O exception occurs while accessing the URL
  661        *
  662        * @see #getMidiFileFormat(InputStream)
  663        * @see #getMidiFileFormat(File)
  664        */
  665       public static MidiFileFormat getMidiFileFormat(URL url)
  666           throws InvalidMidiDataException, IOException {
  667   
  668           List providers = getMidiFileReaders();
  669           MidiFileFormat format = null;
  670   
  671           for(int i = 0; i < providers.size(); i++) {
  672               MidiFileReader reader = (MidiFileReader) providers.get(i);
  673               try {
  674                   format = reader.getMidiFileFormat( url ); // throws IOException
  675                   break;
  676               } catch (InvalidMidiDataException e) {
  677                   continue;
  678               }
  679           }
  680   
  681           if( format==null ) {
  682               throw new InvalidMidiDataException("url is not a supported file type");
  683           } else {
  684               return format;
  685           }
  686       }
  687   
  688   
  689       /**
  690        * Obtains the MIDI file format of the specified <code>File</code>.  The
  691        * <code>File</code> must point to valid MIDI file data for a file type
  692        * recognized by the system.
  693        * <p>
  694        * This operation can only succeed for files of a type which can be parsed
  695        * by an installed file reader.  It may fail with an InvalidMidiDataException
  696        * even for valid files if no compatible file reader is installed.  It
  697        * will also fail with an InvalidMidiDataException if a compatible file reader
  698        * is installed, but encounters errors while determining the file format.
  699        *
  700        * @param file the <code>File</code> from which file format information
  701        * should be extracted
  702        * @return a <code>MidiFileFormat</code> object describing the MIDI file
  703        * format
  704        * @throws InvalidMidiDataException if the <code>File</code> does not point
  705        *  to valid MIDI file data recognized by the system
  706        * @throws IOException if an I/O exception occurs while accessing the file
  707        *
  708        * @see #getMidiFileFormat(InputStream)
  709        * @see #getMidiFileFormat(URL)
  710        */
  711       public static MidiFileFormat getMidiFileFormat(File file)
  712           throws InvalidMidiDataException, IOException {
  713   
  714           List providers = getMidiFileReaders();
  715           MidiFileFormat format = null;
  716   
  717           for(int i = 0; i < providers.size(); i++) {
  718               MidiFileReader reader = (MidiFileReader) providers.get(i);
  719               try {
  720                   format = reader.getMidiFileFormat( file ); // throws IOException
  721                   break;
  722               } catch (InvalidMidiDataException e) {
  723                   continue;
  724               }
  725           }
  726   
  727           if( format==null ) {
  728               throw new InvalidMidiDataException("file is not a supported file type");
  729           } else {
  730               return format;
  731           }
  732       }
  733   
  734   
  735       /**
  736        * Obtains a MIDI sequence from the specified input stream.  The stream must
  737        * point to valid MIDI file data for a file type recognized
  738        * by the system.
  739        * <p>
  740        * This method and/or the code it invokes may need to read some data
  741        * from the stream to determine whether
  742        * its data format is supported.  The implementation may therefore
  743        * need to mark the stream, read enough data to determine whether it is in
  744        * a supported format, and reset the stream's read pointer to its original
  745        * position.  If the input stream does not permit this set of operations,
  746        * this method may fail with an <code>IOException</code>.
  747        * <p>
  748        * This operation can only succeed for files of a type which can be parsed
  749        * by an installed file reader.  It may fail with an InvalidMidiDataException
  750        * even for valid files if no compatible file reader is installed.  It
  751        * will also fail with an InvalidMidiDataException if a compatible file reader
  752        * is installed, but encounters errors while constructing the <code>Sequence</code>
  753        * object from the file data.
  754        *
  755        * @param stream the input stream from which the <code>Sequence</code>
  756        * should be constructed
  757        * @return a <code>Sequence</code> object based on the MIDI file data
  758        * contained in the input stream
  759        * @throws InvalidMidiDataException if the stream does not point to
  760        * valid MIDI file data recognized by the system
  761        * @throws IOException if an I/O exception occurs while accessing the
  762        * stream
  763        * @see InputStream#markSupported
  764        * @see InputStream#mark
  765        */
  766       public static Sequence getSequence(InputStream stream)
  767           throws InvalidMidiDataException, IOException {
  768   
  769           List providers = getMidiFileReaders();
  770           Sequence sequence = null;
  771   
  772           for(int i = 0; i < providers.size(); i++) {
  773               MidiFileReader reader = (MidiFileReader) providers.get(i);
  774               try {
  775                   sequence = reader.getSequence( stream ); // throws IOException
  776                   break;
  777               } catch (InvalidMidiDataException e) {
  778                   continue;
  779               }
  780           }
  781   
  782           if( sequence==null ) {
  783               throw new InvalidMidiDataException("could not get sequence from input stream");
  784           } else {
  785               return sequence;
  786           }
  787       }
  788   
  789   
  790       /**
  791        * Obtains a MIDI sequence from the specified URL.  The URL must
  792        * point to valid MIDI file data for a file type recognized
  793        * by the system.
  794        * <p>
  795        * This operation can only succeed for files of a type which can be parsed
  796        * by an installed file reader.  It may fail with an InvalidMidiDataException
  797        * even for valid files if no compatible file reader is installed.  It
  798        * will also fail with an InvalidMidiDataException if a compatible file reader
  799        * is installed, but encounters errors while constructing the <code>Sequence</code>
  800        * object from the file data.
  801        *
  802        * @param url the URL from which the <code>Sequence</code> should be
  803        * constructed
  804        * @return a <code>Sequence</code> object based on the MIDI file data
  805        * pointed to by the URL
  806        * @throws InvalidMidiDataException if the URL does not point to valid MIDI
  807        * file data recognized by the system
  808        * @throws IOException if an I/O exception occurs while accessing the URL
  809        */
  810       public static Sequence getSequence(URL url)
  811           throws InvalidMidiDataException, IOException {
  812   
  813           List providers = getMidiFileReaders();
  814           Sequence sequence = null;
  815   
  816           for(int i = 0; i < providers.size(); i++) {
  817               MidiFileReader reader = (MidiFileReader) providers.get(i);
  818               try {
  819                   sequence = reader.getSequence( url ); // throws IOException
  820                   break;
  821               } catch (InvalidMidiDataException e) {
  822                   continue;
  823               }
  824           }
  825   
  826           if( sequence==null ) {
  827               throw new InvalidMidiDataException("could not get sequence from URL");
  828           } else {
  829               return sequence;
  830           }
  831       }
  832   
  833   
  834       /**
  835        * Obtains a MIDI sequence from the specified <code>File</code>.
  836        * The <code>File</code> must point to valid MIDI file data
  837        * for a file type recognized by the system.
  838        * <p>
  839        * This operation can only succeed for files of a type which can be parsed
  840        * by an installed file reader.  It may fail with an InvalidMidiDataException
  841        * even for valid files if no compatible file reader is installed.  It
  842        * will also fail with an InvalidMidiDataException if a compatible file reader
  843        * is installed, but encounters errors while constructing the <code>Sequence</code>
  844        * object from the file data.
  845        *
  846        * @param file the <code>File</code> from which the <code>Sequence</code>
  847        * should be constructed
  848        * @return a <code>Sequence</code> object based on the MIDI file data
  849        * pointed to by the File
  850        * @throws InvalidMidiDataException if the File does not point to valid MIDI
  851        * file data recognized by the system
  852        * @throws IOException if an I/O exception occurs
  853        */
  854       public static Sequence getSequence(File file)
  855           throws InvalidMidiDataException, IOException {
  856   
  857           List providers = getMidiFileReaders();
  858           Sequence sequence = null;
  859   
  860           for(int i = 0; i < providers.size(); i++) {
  861               MidiFileReader reader = (MidiFileReader) providers.get(i);
  862               try {
  863                   sequence = reader.getSequence( file ); // throws IOException
  864                   break;
  865               } catch (InvalidMidiDataException e) {
  866                   continue;
  867               }
  868           }
  869   
  870           if( sequence==null ) {
  871               throw new InvalidMidiDataException("could not get sequence from file");
  872           } else {
  873               return sequence;
  874           }
  875       }
  876   
  877   
  878       /**
  879        * Obtains the set of MIDI file types for which file writing support is
  880        * provided by the system.
  881        * @return array of unique file types.  If no file types are supported,
  882        * an array of length 0 is returned.
  883        */
  884       public static int[] getMidiFileTypes() {
  885   
  886           List providers = getMidiFileWriters();
  887           Set allTypes = new HashSet();
  888   
  889           // gather from all the providers
  890   
  891           for (int i = 0; i < providers.size(); i++ ) {
  892               MidiFileWriter writer = (MidiFileWriter) providers.get(i);
  893               int[] types = writer.getMidiFileTypes();
  894               for (int j = 0; j < types.length; j++ ) {
  895                   allTypes.add(new Integer(types[j]));
  896               }
  897           }
  898           int resultTypes[] = new int[allTypes.size()];
  899           int index = 0;
  900           Iterator iterator = allTypes.iterator();
  901           while (iterator.hasNext()) {
  902               Integer integer = (Integer) iterator.next();
  903               resultTypes[index++] = integer.intValue();
  904           }
  905           return resultTypes;
  906       }
  907   
  908   
  909       /**
  910        * Indicates whether file writing support for the specified MIDI file type
  911        * is provided by the system.
  912        * @param fileType the file type for which write capabilities are queried
  913        * @return <code>true</code> if the file type is supported,
  914        * otherwise <code>false</code>
  915        */
  916       public static boolean isFileTypeSupported(int fileType) {
  917   
  918           List providers = getMidiFileWriters();
  919   
  920           for (int i = 0; i < providers.size(); i++ ) {
  921               MidiFileWriter writer = (MidiFileWriter) providers.get(i);
  922               if( writer.isFileTypeSupported(fileType)) {
  923                   return true;
  924               }
  925           }
  926           return false;
  927       }
  928   
  929   
  930       /**
  931        * Obtains the set of MIDI file types that the system can write from the
  932        * sequence specified.
  933        * @param sequence the sequence for which MIDI file type support
  934        * is queried
  935        * @return the set of unique supported file types.  If no file types are supported,
  936        * returns an array of length 0.
  937        */
  938       public static int[] getMidiFileTypes(Sequence sequence) {
  939   
  940           List providers = getMidiFileWriters();
  941           Set allTypes = new HashSet();
  942   
  943           // gather from all the providers
  944   
  945           for (int i = 0; i < providers.size(); i++ ) {
  946               MidiFileWriter writer = (MidiFileWriter) providers.get(i);
  947               int[] types = writer.getMidiFileTypes(sequence);
  948               for (int j = 0; j < types.length; j++ ) {
  949                   allTypes.add(new Integer(types[j]));
  950               }
  951           }
  952           int resultTypes[] = new int[allTypes.size()];
  953           int index = 0;
  954           Iterator iterator = allTypes.iterator();
  955           while (iterator.hasNext()) {
  956               Integer integer = (Integer) iterator.next();
  957               resultTypes[index++] = integer.intValue();
  958           }
  959           return resultTypes;
  960       }
  961   
  962   
  963       /**
  964        * Indicates whether a MIDI file of the file type specified can be written
  965        * from the sequence indicated.
  966        * @param fileType the file type for which write capabilities
  967        * are queried
  968        * @param sequence the sequence for which file writing support is queried
  969        * @return <code>true</code> if the file type is supported for this
  970        * sequence, otherwise <code>false</code>
  971        */
  972       public static boolean isFileTypeSupported(int fileType, Sequence sequence) {
  973   
  974           List providers = getMidiFileWriters();
  975   
  976           for (int i = 0; i < providers.size(); i++ ) {
  977               MidiFileWriter writer = (MidiFileWriter) providers.get(i);
  978               if( writer.isFileTypeSupported(fileType,sequence)) {
  979                   return true;
  980               }
  981           }
  982           return false;
  983       }
  984   
  985   
  986       /**
  987        * Writes a stream of bytes representing a file of the MIDI file type
  988        * indicated to the output stream provided.
  989        * @param in sequence containing MIDI data to be written to the file
  990        * @param fileType the file type of the file to be written to the output stream
  991        * @param out stream to which the file data should be written
  992        * @return the number of bytes written to the output stream
  993        * @throws IOException if an I/O exception occurs
  994        * @throws IllegalArgumentException if the file format is not supported by
  995        * the system
  996        * @see #isFileTypeSupported(int, Sequence)
  997        * @see     #getMidiFileTypes(Sequence)
  998        */
  999       public static int write(Sequence in, int fileType, OutputStream out) throws IOException {
 1000   
 1001           List providers = getMidiFileWriters();
 1002           //$$fb 2002-04-17: Fix for 4635287: Standard MidiFileWriter cannot write empty Sequences
 1003           int bytesWritten = -2;
 1004   
 1005           for (int i = 0; i < providers.size(); i++ ) {
 1006               MidiFileWriter writer = (MidiFileWriter) providers.get(i);
 1007               if( writer.isFileTypeSupported( fileType, in ) ) {
 1008   
 1009                   bytesWritten = writer.write(in, fileType, out);
 1010                   break;
 1011               }
 1012           }
 1013           if (bytesWritten == -2) {
 1014               throw new IllegalArgumentException("MIDI file type is not supported");
 1015           }
 1016           return bytesWritten;
 1017       }
 1018   
 1019   
 1020       /**
 1021        * Writes a stream of bytes representing a file of the MIDI file type
 1022        * indicated to the external file provided.
 1023        * @param in sequence containing MIDI data to be written to the file
 1024        * @param type the file type of the file to be written to the output stream
 1025        * @param out external file to which the file data should be written
 1026        * @return the number of bytes written to the file
 1027        * @throws IOException if an I/O exception occurs
 1028        * @throws IllegalArgumentException if the file type is not supported by
 1029        * the system
 1030        * @see #isFileTypeSupported(int, Sequence)
 1031        * @see     #getMidiFileTypes(Sequence)
 1032        */
 1033       public static int write(Sequence in, int type, File out) throws IOException {
 1034   
 1035           List providers = getMidiFileWriters();
 1036           //$$fb 2002-04-17: Fix for 4635287: Standard MidiFileWriter cannot write empty Sequences
 1037           int bytesWritten = -2;
 1038   
 1039           for (int i = 0; i < providers.size(); i++ ) {
 1040               MidiFileWriter writer = (MidiFileWriter) providers.get(i);
 1041               if( writer.isFileTypeSupported( type, in ) ) {
 1042   
 1043                   bytesWritten = writer.write(in, type, out);
 1044                   break;
 1045               }
 1046           }
 1047           if (bytesWritten == -2) {
 1048               throw new IllegalArgumentException("MIDI file type is not supported");
 1049           }
 1050           return bytesWritten;
 1051       }
 1052   
 1053   
 1054   
 1055       // HELPER METHODS
 1056   
 1057       private static List getMidiDeviceProviders() {
 1058           return getProviders(MidiDeviceProvider.class);
 1059       }
 1060   
 1061   
 1062       private static List getSoundbankReaders() {
 1063           return getProviders(SoundbankReader.class);
 1064       }
 1065   
 1066   
 1067       private static List getMidiFileWriters() {
 1068           return getProviders(MidiFileWriter.class);
 1069       }
 1070   
 1071   
 1072       private static List getMidiFileReaders() {
 1073           return getProviders(MidiFileReader.class);
 1074       }
 1075   
 1076   
 1077       /** Attempts to locate and return a default MidiDevice of the specified
 1078        * type.
 1079        *
 1080        * This method wraps {@link #getDefaultDevice}. It catches the
 1081        * <code>IllegalArgumentException</code> thrown by
 1082        * <code>getDefaultDevice</code> and instead throws a
 1083        * <code>MidiUnavailableException</code>, with the catched
 1084        * exception chained.
 1085        *
 1086        * @param deviceClass The requested device type, one of Synthesizer.class,
 1087        * Sequencer.class, Receiver.class or Transmitter.class.
 1088        * @throws  MidiUnavalableException on failure.
 1089        */
 1090       private static MidiDevice getDefaultDeviceWrapper(Class deviceClass)
 1091           throws MidiUnavailableException{
 1092           try {
 1093               return getDefaultDevice(deviceClass);
 1094           } catch (IllegalArgumentException iae) {
 1095               MidiUnavailableException mae = new MidiUnavailableException();
 1096               mae.initCause(iae);
 1097               throw mae;
 1098           }
 1099       }
 1100   
 1101   
 1102       /** Attempts to locate and return a default MidiDevice of the specified
 1103        * type.
 1104        *
 1105        * @param deviceClass The requested device type, one of Synthesizer.class,
 1106        * Sequencer.class, Receiver.class or Transmitter.class.
 1107        * @throws  IllegalArgumentException on failure.
 1108        */
 1109       private static MidiDevice getDefaultDevice(Class deviceClass) {
 1110           List providers = getMidiDeviceProviders();
 1111           String providerClassName = JDK13Services.getDefaultProviderClassName(deviceClass);
 1112           String instanceName = JDK13Services.getDefaultInstanceName(deviceClass);
 1113           MidiDevice device;
 1114   
 1115           if (providerClassName != null) {
 1116               MidiDeviceProvider defaultProvider = getNamedProvider(providerClassName, providers);
 1117               if (defaultProvider != null) {
 1118                   if (instanceName != null) {
 1119                       device = getNamedDevice(instanceName, defaultProvider, deviceClass);
 1120                       if (device != null) {
 1121                           return device;
 1122                       }
 1123                   }
 1124                   device = getFirstDevice(defaultProvider, deviceClass);
 1125                   if (device != null) {
 1126                       return device;
 1127                   }
 1128               }
 1129           }
 1130   
 1131           /* Provider class not specified or cannot be found, or
 1132              provider class specified, and no appropriate device available or
 1133              provider class and instance specified and instance cannot be found or is not appropriate */
 1134           if (instanceName != null) {
 1135               device = getNamedDevice(instanceName, providers, deviceClass);
 1136               if (device != null) {
 1137                   return device;
 1138               }
 1139           }
 1140   
 1141           /* No default are specified, or if something is specified, everything
 1142              failed. */
 1143           device = getFirstDevice(providers, deviceClass);
 1144           if (device != null) {
 1145               return device;
 1146           }
 1147           throw new IllegalArgumentException("Requested device not installed");
 1148       }
 1149   
 1150   
 1151   
 1152       /** Return a MidiDeviceProcider of a given class from the list of
 1153           MidiDeviceProviders.
 1154   
 1155           @param providerClassName The class name of the provider to be returned.
 1156           @param provider The list of MidiDeviceProviders that is searched.
 1157           @return A MidiDeviceProvider of the requested class, or null if none
 1158           is found.
 1159       */
 1160       private static MidiDeviceProvider getNamedProvider(String providerClassName, List providers) {
 1161           for(int i = 0; i < providers.size(); i++) {
 1162               MidiDeviceProvider provider = (MidiDeviceProvider) providers.get(i);
 1163               if (provider.getClass().getName().equals(providerClassName)) {
 1164                   return provider;
 1165               }
 1166           }
 1167           return null;
 1168       }
 1169   
 1170   
 1171       /** Return a MidiDevice with a given name from a given MidiDeviceProvider.
 1172           @param deviceName The name of the MidiDevice to be returned.
 1173           @param provider The MidiDeviceProvider to check for MidiDevices.
 1174           @param deviceClass The requested device type, one of Synthesizer.class,
 1175           Sequencer.class, Receiver.class or Transmitter.class.
 1176   
 1177           @return A MidiDevice matching the requirements, or null if none is found.
 1178       */
 1179       private static MidiDevice getNamedDevice(String deviceName,
 1180                                                MidiDeviceProvider provider,
 1181                                                Class deviceClass) {
 1182           MidiDevice device;
 1183           // try to get MIDI port
 1184           device = getNamedDevice(deviceName, provider, deviceClass,
 1185                                    false, false);
 1186           if (device != null) {
 1187               return device;
 1188           }
 1189   
 1190           if (deviceClass == Receiver.class) {
 1191               // try to get Synthesizer
 1192               device = getNamedDevice(deviceName, provider, deviceClass,
 1193                                        true, false);
 1194               if (device != null) {
 1195                   return device;
 1196               }
 1197           }
 1198   
 1199           return null;
 1200       }
 1201   
 1202   
 1203       /** Return a MidiDevice with a given name from a given MidiDeviceProvider.
 1204         @param deviceName The name of the MidiDevice to be returned.
 1205         @param provider The MidiDeviceProvider to check for MidiDevices.
 1206         @param deviceClass The requested device type, one of Synthesizer.class,
 1207         Sequencer.class, Receiver.class or Transmitter.class.
 1208   
 1209         @return A MidiDevice matching the requirements, or null if none is found.
 1210        */
 1211       private static MidiDevice getNamedDevice(String deviceName,
 1212                                                MidiDeviceProvider provider,
 1213                                                Class deviceClass,
 1214                                                boolean allowSynthesizer,
 1215                                                boolean allowSequencer) {
 1216           MidiDevice.Info[] infos = provider.getDeviceInfo();
 1217           for (int i = 0; i < infos.length; i++) {
 1218               if (infos[i].getName().equals(deviceName)) {
 1219                   MidiDevice device = provider.getDevice(infos[i]);
 1220                   if (isAppropriateDevice(device, deviceClass,
 1221                                           allowSynthesizer, allowSequencer)) {
 1222                       return device;
 1223                   }
 1224               }
 1225           }
 1226           return null;
 1227       }
 1228   
 1229   
 1230       /** Return a MidiDevice with a given name from a list of
 1231           MidiDeviceProviders.
 1232           @param deviceName The name of the MidiDevice to be returned.
 1233           @param providers The List of MidiDeviceProviders to check for
 1234           MidiDevices.
 1235           @param deviceClass The requested device type, one of Synthesizer.class,
 1236           Sequencer.class, Receiver.class or Transmitter.class.
 1237           @return A Mixer matching the requirements, or null if none is found.
 1238       */
 1239       private static MidiDevice getNamedDevice(String deviceName,
 1240                                                List providers,
 1241                                                Class deviceClass) {
 1242           MidiDevice device;
 1243           // try to get MIDI port
 1244           device = getNamedDevice(deviceName, providers, deviceClass,
 1245                                    false, false);
 1246           if (device != null) {
 1247               return device;
 1248           }
 1249   
 1250           if (deviceClass == Receiver.class) {
 1251               // try to get Synthesizer
 1252               device = getNamedDevice(deviceName, providers, deviceClass,
 1253                                        true, false);
 1254               if (device != null) {
 1255                   return device;
 1256               }
 1257           }
 1258   
 1259           return null;
 1260       }
 1261   
 1262   
 1263       /** Return a MidiDevice with a given name from a list of
 1264           MidiDeviceProviders.
 1265           @param deviceName The name of the MidiDevice to be returned.
 1266           @param providers The List of MidiDeviceProviders to check for
 1267           MidiDevices.
 1268           @param deviceClass The requested device type, one of Synthesizer.class,
 1269           Sequencer.class, Receiver.class or Transmitter.class.
 1270           @return A Mixer matching the requirements, or null if none is found.
 1271        */
 1272       private static MidiDevice getNamedDevice(String deviceName,
 1273                                                List providers,
 1274                                                Class deviceClass,
 1275                                                boolean allowSynthesizer,
 1276                                                boolean allowSequencer) {
 1277           for(int i = 0; i < providers.size(); i++) {
 1278               MidiDeviceProvider provider = (MidiDeviceProvider) providers.get(i);
 1279               MidiDevice device = getNamedDevice(deviceName, provider,
 1280                                                  deviceClass,
 1281                                                  allowSynthesizer,
 1282                                                  allowSequencer);
 1283               if (device != null) {
 1284                   return device;
 1285               }
 1286           }
 1287           return null;
 1288       }
 1289   
 1290   
 1291       /** From a given MidiDeviceProvider, return the first appropriate device.
 1292           @param provider The MidiDeviceProvider to check for MidiDevices.
 1293           @param deviceClass The requested device type, one of Synthesizer.class,
 1294           Sequencer.class, Receiver.class or Transmitter.class.
 1295           @return A MidiDevice is considered appropriate, or null if no
 1296           appropriate device is found.
 1297       */
 1298       private static MidiDevice getFirstDevice(MidiDeviceProvider provider,
 1299                                                Class deviceClass) {
 1300           MidiDevice device;
 1301           // try to get MIDI port
 1302           device = getFirstDevice(provider, deviceClass,
 1303                                   false, false);
 1304           if (device != null) {
 1305               return device;
 1306           }
 1307   
 1308           if (deviceClass == Receiver.class) {
 1309               // try to get Synthesizer
 1310               device = getFirstDevice(provider, deviceClass,
 1311                                       true, false);
 1312               if (device != null) {
 1313                   return device;
 1314               }
 1315           }
 1316   
 1317           return null;
 1318       }
 1319   
 1320   
 1321       /** From a given MidiDeviceProvider, return the first appropriate device.
 1322           @param provider The MidiDeviceProvider to check for MidiDevices.
 1323           @param deviceClass The requested device type, one of Synthesizer.class,
 1324           Sequencer.class, Receiver.class or Transmitter.class.
 1325           @return A MidiDevice is considered appropriate, or null if no
 1326           appropriate device is found.
 1327        */
 1328       private static MidiDevice getFirstDevice(MidiDeviceProvider provider,
 1329                                                Class deviceClass,
 1330                                                boolean allowSynthesizer,
 1331                                                boolean allowSequencer) {
 1332           MidiDevice.Info[] infos = provider.getDeviceInfo();
 1333           for (int j = 0; j < infos.length; j++) {
 1334               MidiDevice device = provider.getDevice(infos[j]);
 1335               if (isAppropriateDevice(device, deviceClass,
 1336                                       allowSynthesizer, allowSequencer)) {
 1337                   return device;
 1338               }
 1339           }
 1340           return null;
 1341       }
 1342   
 1343   
 1344       /** From a List of MidiDeviceProviders, return the first appropriate
 1345           MidiDevice.
 1346           @param providers The List of MidiDeviceProviders to search.
 1347           @param deviceClass The requested device type, one of Synthesizer.class,
 1348           Sequencer.class, Receiver.class or Transmitter.class.
 1349           @return A MidiDevice that is considered appropriate, or null
 1350           if none is found.
 1351       */
 1352       private static MidiDevice getFirstDevice(List providers,
 1353                                                Class deviceClass) {
 1354           MidiDevice device;
 1355           // try to get MIDI port
 1356           device = getFirstDevice(providers, deviceClass,
 1357                                   false, false);
 1358           if (device != null) {
 1359               return device;
 1360           }
 1361   
 1362           if (deviceClass == Receiver.class) {
 1363               // try to get Synthesizer
 1364               device = getFirstDevice(providers, deviceClass,
 1365                                       true, false);
 1366               if (device != null) {
 1367                   return device;
 1368               }
 1369           }
 1370   
 1371           return null;
 1372       }
 1373   
 1374   
 1375       /** From a List of MidiDeviceProviders, return the first appropriate
 1376           MidiDevice.
 1377           @param providers The List of MidiDeviceProviders to search.
 1378           @param deviceClass The requested device type, one of Synthesizer.class,
 1379           Sequencer.class, Receiver.class or Transmitter.class.
 1380           @return A MidiDevice that is considered appropriate, or null
 1381           if none is found.
 1382        */
 1383       private static MidiDevice getFirstDevice(List providers,
 1384                                                Class deviceClass,
 1385                                                boolean allowSynthesizer,
 1386                                                boolean allowSequencer) {
 1387           for(int i = 0; i < providers.size(); i++) {
 1388               MidiDeviceProvider provider = (MidiDeviceProvider) providers.get(i);
 1389               MidiDevice device = getFirstDevice(provider, deviceClass,
 1390                                                  allowSynthesizer,
 1391                                                  allowSequencer);
 1392               if (device != null) {
 1393                   return device;
 1394               }
 1395           }
 1396           return null;
 1397       }
 1398   
 1399   
 1400       /** Checks if a MidiDevice is appropriate.
 1401           If deviceClass is Synthesizer or Sequencer, a device implementing
 1402           the respective interface is considered appropriate. If deviceClass
 1403           is Receiver or Transmitter, a device is considered appropriate if
 1404           it implements neither Synthesizer nor Transmitter, and if it can
 1405           provide at least one Receiver or Transmitter, respectively.
 1406   
 1407           @param device the MidiDevice to test
 1408           @param allowSynthesizer if true, Synthesizers are considered
 1409           appropriate. Otherwise only pure MidiDevices are considered
 1410           appropriate (unless allowSequencer is true). This flag only has an
 1411           effect for deviceClass Receiver and Transmitter. For other device
 1412           classes (Sequencer and Synthesizer), this flag has no effect.
 1413           @param allowSequencer if true, Sequencers are considered
 1414           appropriate. Otherwise only pure MidiDevices are considered
 1415           appropriate (unless allowSynthesizer is true). This flag only has an
 1416           effect for deviceClass Receiver and Transmitter. For other device
 1417           classes (Sequencer and Synthesizer), this flag has no effect.
 1418           @return true if the device is considered appropriate according to the
 1419           rules given above, false otherwise.
 1420       */
 1421       private static boolean isAppropriateDevice(MidiDevice device,
 1422                                                  Class deviceClass,
 1423                                                  boolean allowSynthesizer,
 1424                                                  boolean allowSequencer) {
 1425           if (deviceClass.isInstance(device)) {
 1426               // This clause is for deviceClass being either Synthesizer
 1427               // or Sequencer.
 1428               return true;
 1429           } else {
 1430               // Now the case that deviceClass is Transmitter or
 1431               // Receiver. If neither allowSynthesizer nor allowSequencer is
 1432               // true, we require device instances to be
 1433               // neither Synthesizer nor Sequencer, since we only want
 1434               // devices representing MIDI ports.
 1435               // Otherwise, the respective type is accepted, too
 1436               if ( (! (device instanceof Sequencer) &&
 1437                     ! (device instanceof Synthesizer) ) ||
 1438                    ((device instanceof Sequencer) && allowSequencer) ||
 1439                    ((device instanceof Synthesizer) && allowSynthesizer)) {
 1440                   // And of cource, the device has to be able to provide
 1441                   // Receivers or Transmitters.
 1442                   if ((deviceClass == Receiver.class &&
 1443                        device.getMaxReceivers() != 0) ||
 1444                       (deviceClass == Transmitter.class &&
 1445                        device.getMaxTransmitters() != 0)) {
 1446                       return true;
 1447                   }
 1448               }
 1449           }
 1450           return false;
 1451       }
 1452   
 1453   
 1454       /**
 1455        * Obtains the set of services currently installed on the system
 1456        * using sun.misc.Service, the SPI mechanism in 1.3.
 1457        * @return a List of instances of providers for the requested service.
 1458        * If no providers are available, a List of length 0 will be returned.
 1459        */
 1460       private static List getProviders(Class providerClass) {
 1461           return JDK13Services.getProviders(providerClass);
 1462       }
 1463   }

Save This Page
Home » openjdk-7 » javax.sound » midi » [javadoc | source]