KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > sound > midi > MidiSystem


1 /*
2  * @(#)MidiSystem.java 1.66 04/04/15
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package javax.sound.midi;
9
10 import java.io.FileInputStream JavaDoc;
11 import java.io.File JavaDoc;
12 import java.io.InputStream JavaDoc;
13 import java.io.OutputStream JavaDoc;
14 import java.io.IOException JavaDoc;
15
16 import java.util.ArrayList JavaDoc;
17 import java.util.HashSet JavaDoc;
18 import java.util.Iterator JavaDoc;
19 import java.util.List JavaDoc;
20 import java.util.Set JavaDoc;
21
22 import java.net.URL JavaDoc;
23
24 import javax.sound.midi.spi.MidiFileWriter JavaDoc;
25 import javax.sound.midi.spi.MidiFileReader JavaDoc;
26 import javax.sound.midi.spi.SoundbankReader JavaDoc;
27 import javax.sound.midi.spi.MidiDeviceProvider JavaDoc;
28
29 import com.sun.media.sound.JDK13Services;
30 import com.sun.media.sound.ReferenceCountingDevice;
31 import com.sun.media.sound.AutoConnectSequencer;
32
33
34 /**
35  * The <code>MidiSystem</code> class provides access to the installed MIDI
36  * system resources, including devices such as synthesizers, sequencers, and
37  * MIDI input and output ports. A typical simple MIDI application might
38  * begin by invoking one or more <code>MidiSystem</code> methods to learn
39  * what devices are installed and to obtain the ones needed in that
40  * application.
41  * <p>
42  * The class also has methods for reading files, streams, and URLs that
43  * contain standard MIDI file data or soundbanks. You can query the
44  * <code>MidiSystem</code> for the format of a specified MIDI file.
45  * <p>
46  * You cannot instantiate a <code>MidiSystem</code>; all the methods are
47  * static.
48  *
49  * <p>Properties can be used to specify default MIDI devices.
50  * Both system properties and a properties file are considered.
51  * The properties file is &quot;lib/sound.properties&quot; in the JRE
52  * directory. If a property exists both as a system property and in the
53  * properties file, the system property takes precedence. If none is
54  * specified, a suitable default is chosen among the available devices.
55  * The syntax of the properties file is specified in
56  * {@link java.util.Properties#load(InputStream) Properties.load}. The
57  * following table lists the available property keys and which methods
58  * consider them:
59  *
60  * <table border=0>
61  * <tr>
62  * <th>Property Key</th>
63  * <th>Interface</th>
64  * <th>Affected Method</th>
65  * </tr>
66  * <tr>
67  * <td><code>javax.sound.midi.Receiver</code></td>
68  * <td>{@link Receiver}</td>
69  * <td>{@link #getReceiver}</td>
70  * </tr>
71  * <tr>
72  * <td><code>javax.sound.midi.Sequencer</code></td>
73  * <td>{@link Sequencer}</td>
74  * <td>{@link #getSequencer}</td>
75  * </tr>
76  * <tr>
77  * <td><code>javax.sound.midi.Synthesizer</code></td>
78  * <td>{@link Synthesizer}</td>
79  * <td>{@link #getSynthesizer}</td>
80  * </tr>
81  * <tr>
82  * <td><code>javax.sound.midi.Transmitter</code></td>
83  * <td>{@link Transmitter}</td>
84  * <td>{@link #getTransmitter}</td>
85  * </tr>
86  * </table>
87  *
88  * The property value consists of the provider class name
89  * and the device name, separated by the hash mark (&quot;#&quot;).
90  * The provider class name is the fully-qualified
91  * name of a concrete {@link javax.sound.midi.spi.MidiDeviceProvider
92  * MIDI device provider} class. The device name is matched against
93  * the <code>String</code> returned by the <code>getName</code>
94  * method of <code>MidiDevice.Info</code>.
95  * Either the class name, or the device name may be omitted.
96  * If only the class name is specified, the trailing hash mark
97  * is optional.
98  *
99  * <p>If the provider class is specified, and it can be
100  * successully retrieved from the installed providers,
101  * the list of
102  * <code>MidiDevice.Info</code> objects is retrieved
103  * from the provider. Otherwise, or when these devices
104  * do not provide a subsequent match, the list is retrieved
105  * from {@link #getMidiDeviceInfo} to contain
106  * all available <code>MidiDevice.Info</code> objects.
107  *
108  * <p>If a device name is specified, the resulting list of
109  * <code>MidiDevice.Info</code> objects is searched:
110  * the first one with a matching name, and whose
111  * <code>MidiDevice</code> implements the
112  * respective interface, will be returned.
113  * If no matching <code>MidiDevice.Info</code> object
114  * is found, or the device name is not specified,
115  * the first suitable device from the resulting
116  * list will be returned. For Sequencer and Synthesizer,
117  * a device is suitable if it implements the respective
118  * interface; whereas for Receiver and Transmitter, a device is
119  * suitable if it
120  * implements neither Sequencer nor Synthesizer and provides
121  * at least one Receiver or Transmitter, respectively.
122  *
123  * For example, the property <code>javax.sound.midi.Receiver</code>
124  * with a value
125  * <code>&quot;com.sun.media.sound.MidiProvider#SunMIDI1&quot;</code>
126  * will have the following consequences when
127  * <code>getReceiver</code> is called:
128  * if the class <code>com.sun.media.sound.MidiProvider</code> exists
129  * in the list of installed MIDI device providers,
130  * the first <code>Receiver</code> device with name
131  * <code>&quot;SunMIDI1&quot;</code> will be returned. If it cannot
132  * be found, the first <code>Receiver</code> from that provider
133  * will be returned, regardless of name.
134  * If there is none, the first <code>Receiver</code> with name
135  * <code>&quot;SunMIDI1&quot;</code> in the list of all devices
136  * (as returned by <code>getMidiDeviceInfo</code>) will be returned,
137  * or, if not found, the first <code>Receiver</code> that can
138  * be found in the list of all devices is returned.
139  * If that fails, too, a <code>MidiUnavailableException</code>
140  * is thrown.
141  *
142  * @version 1.66, 04/04/15
143  * @author Kara Kytle
144  * @author Florian Bomers
145  * @author Matthias Pfisterer
146  */

147 public class MidiSystem {
148
149     /**
150      * Private no-args constructor for ensuring against instantiation.
151      */

152     private MidiSystem() {
153     }
154
155
156     /**
157      * Obtains an array of information objects representing
158      * the set of all MIDI devices available on the system.
159      * A returned information object can then be used to obtain the
160      * corresponding device object, by invoking
161      * {@link #getMidiDevice(MidiDevice.Info) getMidiDevice}.
162      *
163      * @return an array of <code>MidiDevice.Info</code> objects, one
164      * for each installed MIDI device. If no such devices are installed,
165      * an array of length 0 is returned.
166      */

167     public static MidiDevice.Info JavaDoc[] getMidiDeviceInfo() {
168     List JavaDoc allInfos = new ArrayList JavaDoc();
169     List JavaDoc providers = getMidiDeviceProviders();
170
171     for(int i = 0; i < providers.size(); i++) {
172         MidiDeviceProvider JavaDoc provider = (MidiDeviceProvider JavaDoc) providers.get(i);
173         MidiDevice.Info JavaDoc[] tmpinfo = provider.getDeviceInfo();
174         for (int j = 0; j < tmpinfo.length; j++) {
175         allInfos.add( tmpinfo[j] );
176         }
177     }
178     MidiDevice.Info JavaDoc[] infosArray = (MidiDevice.Info JavaDoc[]) allInfos.toArray(new MidiDevice.Info JavaDoc[0]);
179     return infosArray;
180     }
181
182
183     /**
184      * Obtains the requested MIDI device.
185      *
186      * @param info a device information object representing the desired device.
187      * @return the requested device
188      * @throws MidiUnavailableException if the requested device is not available
189      * due to resource restrictions
190      * @throws IllegalArgumentException if the info object does not represent
191      * a MIDI device installed on the system
192      * @see #getMidiDeviceInfo
193      */

194     public static MidiDevice JavaDoc getMidiDevice(MidiDevice.Info JavaDoc info) throws MidiUnavailableException JavaDoc {
195     List JavaDoc providers = getMidiDeviceProviders();
196
197     for(int i = 0; i < providers.size(); i++) {
198         MidiDeviceProvider JavaDoc provider = (MidiDeviceProvider JavaDoc) providers.get(i);
199         if (provider.isDeviceSupported(info)) {
200         MidiDevice JavaDoc device = provider.getDevice(info);
201         return device;
202         }
203     }
204     throw new IllegalArgumentException JavaDoc("Requested device not installed: " + info);
205     }
206
207
208     /**
209      * Obtains a MIDI receiver from an external MIDI port
210      * or other default device.
211      *
212      * <p>If the system property
213      * <code>javax.sound.midi.Receiver</code>
214      * is defined or it is defined in the file &quot;sound.properties&quot;,
215      * it is used to identify the device that provides the default receiver.
216      * For details, refer to the {@link MidiSystem class description}.
217      *
218      * If a suitable MIDI port is not available, the Receiver is
219      * retrieved from an installed synthesizer.
220      *
221      * <p>If this method returns successfully, the {@link
222      * javax.sound.midi.MidiDevice MidiDevice} the
223      * <code>Receiver</code> belongs to is opened implicitly, if it is
224      * not already open. It is possible to close an implicitly opened
225      * device by calling {@link javax.sound.midi.Receiver#close close}
226      * on the returned <code>Receiver</code>. All open <code>Receiver</code>
227      * instances have to be closed in order to release system resources
228      * hold by the <code>MidiDevice</code>. For a
229      * detailed description of open/close behaviour see the class
230      * description of {@link javax.sound.midi.MidiDevice MidiDevice}.
231      *
232      *
233      * @return the default MIDI receiver
234      * @throws MidiUnavailableException if the default receiver is not
235      * available due to resource restrictions,
236      * or no device providing receivers is installed in the system
237      */

238     public static Receiver JavaDoc getReceiver() throws MidiUnavailableException JavaDoc {
239     // may throw MidiUnavailableException
240
MidiDevice JavaDoc device = getDefaultDeviceWrapper(Receiver JavaDoc.class);
241     Receiver JavaDoc receiver;
242     if (device instanceof ReferenceCountingDevice) {
243         receiver = ((ReferenceCountingDevice) device).getReceiverReferenceCounting();
244     } else {
245         receiver = device.getReceiver();
246     }
247     return receiver;
248     }
249
250
251     /**
252      * Obtains a MIDI transmitter from an external MIDI port
253      * or other default source.
254      *
255      * <p>If the system property
256      * <code>javax.sound.midi.Transmitter</code>
257      * is defined or it is defined in the file &quot;sound.properties&quot;,
258      * it is used to identify the device that provides the default transmitter.
259      * For details, refer to the {@link MidiSystem class description}.
260      *
261      * If this method returns successfully, the {@link
262      * javax.sound.midi.MidiDevice MidiDevice} the
263      * <code>Transmitter</code> belongs to is opened implicitly, if it
264      * is not already open. It is possible to close an implicitly
265      * opened device by calling {@link
266      * javax.sound.midi.Transmitter#close close} on the returned
267      * <code>Transmitter</code>. All open <code>Transmitter</code>
268      * instances have to be closed in order to release system resources
269      * hold by the <code>MidiDevice</code>. For a detailed description
270      * of open/close behaviour see the class description of {@link
271      * javax.sound.midi.MidiDevice MidiDevice}.
272      *
273      * @return the default MIDI transmitter
274      * @throws MidiUnavailableException if the default transmitter is not
275      * available due to resource restrictions,
276      * or no device providing transmitters is installed in the system
277      */

278     public static Transmitter JavaDoc getTransmitter() throws MidiUnavailableException JavaDoc {
279     // may throw MidiUnavailableException
280
MidiDevice JavaDoc device = getDefaultDeviceWrapper(Transmitter JavaDoc.class);
281     Transmitter JavaDoc transmitter;
282     if (device instanceof ReferenceCountingDevice) {
283         transmitter = ((ReferenceCountingDevice) device).getTransmitterReferenceCounting();
284     } else {
285         transmitter = device.getTransmitter();
286     }
287     return transmitter;
288     }
289
290
291     /**
292      * Obtains the default synthesizer.
293      *
294      * <p>If the system property
295      * <code>javax.sound.midi.Synthesizer</code>
296      * is defined or it is defined in the file &quot;sound.properties&quot;,
297      * it is used to identify the default synthesizer.
298      * For details, refer to the {@link MidiSystem class description}.
299      *
300      * @return the default synthesizer
301      * @throws MidiUnavailableException if the synthesizer is not
302      * available due to resource restrictions,
303      * or no synthesizer is installed in the system
304      */

305     public static Synthesizer JavaDoc getSynthesizer() throws MidiUnavailableException JavaDoc {
306     // may throw MidiUnavailableException
307
return (Synthesizer JavaDoc) getDefaultDeviceWrapper(Synthesizer JavaDoc.class);
308     }
309
310
311     /**
312      * Obtains the default <code>Sequencer</code>, connected to
313      * a default device.
314      * The returned <code>Sequencer</code> instance is
315      * connected to the default <code>Synthesizer</code>,
316      * as returned by {@link #getSynthesizer}.
317      * If there is no <code>Synthesizer</code>
318      * available, or the default <code>Synthesizer</code>
319      * cannot be opened, the <code>sequencer</code> is connected
320      * to the default <code>Receiver</code>, as returned
321      * by {@link #getReceiver}.
322      * The connection is made by retrieving a <code>Transmitter</code>
323      * instance from the <code>Sequencer</code> and setting its
324      * <code>Receiver</code>.
325      * Closing and re-opening the sequencer will restore the
326      * connection to the default device.
327      *
328      * <p>This method is equivalent to calling
329      * <code>getSequencer(true)</code>.
330      *
331      * <p>If the system property
332      * <code>javax.sound.midi.Sequencer</code>
333      * is defined or it is defined in the file &quot;sound.properties&quot;,
334      * it is used to identify the default sequencer.
335      * For details, refer to the {@link MidiSystem class description}.
336      *
337      * @return the default sequencer, connected to a default Receiver
338      * @throws MidiUnavailableException if the sequencer is not
339      * available due to resource restrictions,
340      * or there is no <code>Receiver</code> available by any
341      * installed <code>MidiDevice</code>,
342      * or no sequencer is installed in the system.
343      * @see #getSequencer(boolean)
344      * @see #getSynthesizer
345      * @see #getReceiver
346      */

347     public static Sequencer JavaDoc getSequencer() throws MidiUnavailableException JavaDoc {
348     return getSequencer(true);
349     }
350  
351  
352  
353     /**
354      * Obtains the default <code>Sequencer</code>, optionally
355      * connected to a default device.
356      *
357      * <p>If <code>connected</code> is true, the returned
358      * <code>Sequencer</code> instance is
359      * connected to the default <code>Synthesizer</code>,
360      * as returned by {@link #getSynthesizer}.
361      * If there is no <code>Synthesizer</code>
362      * available, or the default <code>Synthesizer</code>
363      * cannot be opened, the <code>sequencer</code> is connected
364      * to the default <code>Receiver</code>, as returned
365      * by {@link #getReceiver}.
366      * The connection is made by retrieving a <code>Transmitter</code>
367      * instance from the <code>Sequencer</code> and setting its
368      * <code>Receiver</code>.
369      * Closing and re-opening the sequencer will restore the
370      * connection to the default device.
371      *
372      * <p>If <code>connected</code> is false, the returned
373      * <code>Sequencer</code> instance is not connected, it
374      * has no open <code>Transmitters</code>. In order to
375      * play the sequencer on a MIDI device, or a <code>Synthesizer</code>,
376      * it is necessary to get a <code>Transmitter</code> and set its
377      * <code>Receiver</code>.
378      *
379      * <p>If the system property
380      * <code>javax.sound.midi.Sequencer</code>
381      * is defined or it is defined in the file "sound.properties",
382      * it is used to identify the default sequencer.
383      * For details, refer to the {@link MidiSystem class description}.
384      *
385      * @return the default sequencer
386      * @throws MidiUnavailableException if the sequencer is not
387      * available due to resource restrictions,
388      * or no sequencer is installed in the system,
389      * or if <code>connected</code> is true, and there is
390      * no <code>Receiver</code> available by any installed
391      * <code>MidiDevice</code>
392      * @see #getSynthesizer
393      * @see #getReceiver
394      * @since 1.5
395      */

396     public static Sequencer JavaDoc getSequencer(boolean connected)
397     throws MidiUnavailableException JavaDoc {
398     Sequencer JavaDoc seq = (Sequencer JavaDoc) getDefaultDeviceWrapper(Sequencer JavaDoc.class);
399
400     if (connected) {
401         // IMPORTANT: this code needs to be synch'ed with
402
// all AutoConnectSequencer instances,
403
// (e.g. RealTimeSequencer) because the
404
// same algorithm for synth retrieval
405
// needs to be used!
406

407         Receiver JavaDoc rec = null;
408         MidiUnavailableException JavaDoc mue = null;
409
410         // first try to connect to the default synthesizer
411
try {
412         Synthesizer JavaDoc synth = getSynthesizer();
413         if (synth instanceof ReferenceCountingDevice) {
414             rec = ((ReferenceCountingDevice) synth).getReceiverReferenceCounting();
415             // only use MixerSynth if it could successfully load a soundbank
416
if (synth.getClass().toString().contains("com.sun.media.sound.MixerSynth")
417             && (synth.getDefaultSoundbank() == null)) {
418             // don't use this receiver if no soundbank available
419
rec = null;
420             synth.close();
421             }
422         } else {
423             synth.open();
424             try {
425             rec = synth.getReceiver();
426             } finally {
427             // make sure that the synth is properly closed
428
if (rec == null) {
429                 synth.close();
430             }
431             }
432         }
433         } catch (MidiUnavailableException JavaDoc e) {
434         // something went wrong with synth
435
if (e instanceof MidiUnavailableException JavaDoc) {
436             mue = (MidiUnavailableException JavaDoc) e;
437         }
438         }
439         if (rec == null) {
440         // then try to connect to the default Receiver
441
try {
442             rec = MidiSystem.getReceiver();
443         } catch (Exception JavaDoc e) {
444             // something went wrong. Nothing to do then!
445
if (e instanceof MidiUnavailableException JavaDoc) {
446             mue = (MidiUnavailableException JavaDoc) e;
447             }
448         }
449         }
450         if (rec != null) {
451         seq.getTransmitter().setReceiver(rec);
452         if (seq instanceof AutoConnectSequencer) {
453             ((AutoConnectSequencer) seq).setAutoConnect(rec);
454         }
455         } else {
456         if (mue != null) {
457             throw mue;
458         }
459         throw new MidiUnavailableException JavaDoc("no receiver available");
460         }
461     }
462     return seq;
463     }
464  
465
466
467
468     /**
469      * Constructs a MIDI sound bank by reading it from the specified stream.
470      * The stream must point to
471      * a valid MIDI soundbank file. In general, MIDI soundbank providers may
472      * need to read some data from the stream before determining whether they
473      * support it. These parsers must
474      * be able to mark the stream, read enough data to determine whether they
475      * support the stream, and, if not, reset the stream's read pointer to
476      * its original position. If the input stream does not support this,
477      * this method may fail with an IOException.
478      * @param stream the source of the sound bank data.
479      * @return the sound bank
480      * @throws InvalidMidiDataException if the stream does not point to
481      * valid MIDI soundbank data recognized by the system
482      * @throws IOException if an I/O error occurred when loading the soundbank
483      * @see InputStream#markSupported
484      * @see InputStream#mark
485      */

486     public static Soundbank JavaDoc getSoundbank(InputStream JavaDoc stream)
487     throws InvalidMidiDataException JavaDoc, IOException JavaDoc {
488
489     SoundbankReader JavaDoc sp = null;
490     Soundbank JavaDoc s = null;
491
492     List JavaDoc providers = getSoundbankReaders();
493
494     for(int i = 0; i < providers.size(); i++) {
495         sp = (SoundbankReader JavaDoc)providers.get(i);
496         s = sp.getSoundbank(stream);
497
498         if( s!= null) {
499         return s;
500         }
501     }
502     throw new InvalidMidiDataException JavaDoc("cannot get soundbank from stream");
503
504     }
505
506
507     /**
508      * Constructs a <code>Soundbank</code> by reading it from the specified URL.
509      * The URL must point to a valid MIDI soundbank file.
510      *
511      * @param url the source of the sound bank data
512      * @return the sound bank
513      * @throws InvalidMidiDataException if the URL does not point to valid MIDI
514      * soundbank data recognized by the system
515      * @throws IOException if an I/O error occurred when loading the soundbank
516      */

517     public static Soundbank JavaDoc getSoundbank(URL JavaDoc url)
518     throws InvalidMidiDataException JavaDoc, IOException JavaDoc {
519
520     SoundbankReader JavaDoc sp = null;
521     Soundbank JavaDoc s = null;
522
523     List JavaDoc providers = getSoundbankReaders();
524
525     for(int i = 0; i < providers.size(); i++) {
526         sp = (SoundbankReader JavaDoc)providers.get(i);
527         s = sp.getSoundbank(url);
528
529         if( s!= null) {
530         return s;
531         }
532     }
533     throw new InvalidMidiDataException JavaDoc("cannot get soundbank from stream");
534
535     }
536
537
538     /**
539      * Constructs a <code>Soundbank</code> by reading it from the specified
540      * <code>File</code>.
541      * The <code>File</code> must point to a valid MIDI soundbank file.
542      *
543      * @param file the source of the sound bank data
544      * @return the sound bank
545      * @throws InvalidMidiDataException if the <code>File</code> does not
546      * point to valid MIDI soundbank data recognized by the system
547      * @throws IOException if an I/O error occurred when loading the soundbank
548      */

549     public static Soundbank JavaDoc getSoundbank(File JavaDoc file)
550     throws InvalidMidiDataException JavaDoc, IOException JavaDoc {
551
552     SoundbankReader JavaDoc sp = null;
553     Soundbank JavaDoc s = null;
554
555     List JavaDoc providers = getSoundbankReaders();
556
557     for(int i = 0; i < providers.size(); i++) {
558         sp = (SoundbankReader JavaDoc)providers.get(i);
559         s = sp.getSoundbank(file);
560
561         if( s!= null) {
562         return s;
563         }
564     }
565     throw new InvalidMidiDataException JavaDoc("cannot get soundbank from stream");
566     }
567
568
569
570     /**
571      * Obtains the MIDI file format of the data in the specified input stream.
572      * The stream must point to valid MIDI file data for a file type recognized
573      * by the system.
574      * <p>
575      * This method and/or the code it invokes may need to read some data from
576      * the stream to determine whether its data format is supported. The
577      * implementation may therefore
578      * need to mark the stream, read enough data to determine whether it is in
579      * a supported format, and reset the stream's read pointer to its original
580      * position. If the input stream does not permit this set of operations,
581      * this method may fail with an <code>IOException</code>.
582      * <p>
583      * This operation can only succeed for files of a type which can be parsed
584      * by an installed file reader. It may fail with an InvalidMidiDataException
585      * even for valid files if no compatible file reader is installed. It
586      * will also fail with an InvalidMidiDataException if a compatible file reader
587      * is installed, but encounters errors while determining the file format.
588      *
589      * @param stream the input stream from which file format information
590      * should be extracted
591      * @return an <code>MidiFileFormat</code> object describing the MIDI file
592      * format
593      * @throws InvalidMidiDataException if the stream does not point to valid
594      * MIDI file data recognized by the system
595      * @throws IOException if an I/O exception occurs while accessing the
596      * stream
597      * @see #getMidiFileFormat(URL)
598      * @see #getMidiFileFormat(File)
599      * @see InputStream#markSupported
600      * @see InputStream#mark
601      */

602     public static MidiFileFormat JavaDoc getMidiFileFormat(InputStream JavaDoc stream)
603     throws InvalidMidiDataException JavaDoc, IOException JavaDoc {
604
605     List JavaDoc providers = getMidiFileReaders();
606     MidiFileFormat JavaDoc format = null;
607
608     for(int i = 0; i < providers.size(); i++) {
609         MidiFileReader JavaDoc reader = (MidiFileReader JavaDoc) providers.get(i);
610         try {
611         format = reader.getMidiFileFormat( stream ); // throws IOException
612
break;
613         } catch (InvalidMidiDataException JavaDoc e) {
614         continue;
615         }
616     }
617
618     if( format==null ) {
619         throw new InvalidMidiDataException JavaDoc("input stream is not a supported file type");
620     } else {
621         return format;
622     }
623     }
624
625
626     /**
627      * Obtains the MIDI file format of the data in the specified URL. The URL
628      * must point to valid MIDI file data for a file type recognized
629      * by the system.
630      * <p>
631      * This operation can only succeed for files of a type which can be parsed
632      * by an installed file reader. It may fail with an InvalidMidiDataException
633      * even for valid files if no compatible file reader is installed. It
634      * will also fail with an InvalidMidiDataException if a compatible file reader
635      * is installed, but encounters errors while determining the file format.
636      *
637      * @param url the URL from which file format information should be
638      * extracted
639      * @return a <code>MidiFileFormat</code> object describing the MIDI file
640      * format
641      * @throws InvalidMidiDataException if the URL does not point to valid MIDI
642      * file data recognized by the system
643      * @throws IOException if an I/O exception occurs while accessing the URL
644      *
645      * @see #getMidiFileFormat(InputStream)
646      * @see #getMidiFileFormat(File)
647      */

648     public static MidiFileFormat JavaDoc getMidiFileFormat(URL JavaDoc url)
649     throws InvalidMidiDataException JavaDoc, IOException JavaDoc {
650
651     List JavaDoc providers = getMidiFileReaders();
652     MidiFileFormat JavaDoc format = null;
653
654     for(int i = 0; i < providers.size(); i++) {
655         MidiFileReader JavaDoc reader = (MidiFileReader JavaDoc) providers.get(i);
656         try {
657         format = reader.getMidiFileFormat( url ); // throws IOException
658
break;
659         } catch (InvalidMidiDataException JavaDoc e) {
660         continue;
661         }
662     }
663
664     if( format==null ) {
665         throw new InvalidMidiDataException JavaDoc("url is not a supported file type");
666     } else {
667         return format;
668     }
669     }
670
671
672     /**
673      * Obtains the MIDI file format of the specified <code>File</code>. The
674      * <code>File</code> must point to valid MIDI file data for a file type
675      * recognized by the system.
676      * <p>
677      * This operation can only succeed for files of a type which can be parsed
678      * by an installed file reader. It may fail with an InvalidMidiDataException
679      * even for valid files if no compatible file reader is installed. It
680      * will also fail with an InvalidMidiDataException if a compatible file reader
681      * is installed, but encounters errors while determining the file format.
682      *
683      * @param file the <code>File</code> from which file format information
684      * should be extracted
685      * @return a <code>MidiFileFormat</code> object describing the MIDI file
686      * format
687      * @throws InvalidMidiDataException if the <code>File</code> does not point
688      * to valid MIDI file data recognized by the system
689      * @throws IOException if an I/O exception occurs while accessing the file
690      *
691      * @see #getMidiFileFormat(InputStream)
692      * @see #getMidiFileFormat(URL)
693      */

694     public static MidiFileFormat JavaDoc getMidiFileFormat(File JavaDoc file)
695     throws InvalidMidiDataException JavaDoc, IOException JavaDoc {
696
697     List JavaDoc providers = getMidiFileReaders();
698     MidiFileFormat JavaDoc format = null;
699
700     for(int i = 0; i < providers.size(); i++) {
701         MidiFileReader JavaDoc reader = (MidiFileReader JavaDoc) providers.get(i);
702         try {
703         format = reader.getMidiFileFormat( file ); // throws IOException
704
break;
705         } catch (InvalidMidiDataException JavaDoc e) {
706         continue;
707         }
708     }
709
710     if( format==null ) {
711         throw new InvalidMidiDataException JavaDoc("file is not a supported file type");
712     } else {
713         return format;
714     }
715     }
716
717
718     /**
719      * Obtains a MIDI sequence from the specified input stream. The stream must
720      * point to valid MIDI file data for a file type recognized
721      * by the system.
722      * <p>
723      * This method and/or the code it invokes may need to read some data
724      * from the stream to determine whether
725      * its data format is supported. The implementation may therefore
726      * need to mark the stream, read enough data to determine whether it is in
727      * a supported format, and reset the stream's read pointer to its original
728      * position. If the input stream does not permit this set of operations,
729      * this method may fail with an <code>IOException</code>.
730      * <p>
731      * This operation can only succeed for files of a type which can be parsed
732      * by an installed file reader. It may fail with an InvalidMidiDataException
733      * even for valid files if no compatible file reader is installed. It
734      * will also fail with an InvalidMidiDataException if a compatible file reader
735      * is installed, but encounters errors while constructing the <code>Sequence</code>
736      * object from the file data.
737      *
738      * @param stream the input stream from which the <code>Sequence</code>
739      * should be constructed
740      * @return a <code>Sequence</code> object based on the MIDI file data
741      * contained in the input stream
742      * @throws InvalidMidiDataException if the stream does not point to
743      * valid MIDI file data recognized by the system
744      * @throws IOException if an I/O exception occurs while accessing the
745      * stream
746      * @see InputStream#markSupported
747      * @see InputStream#mark
748      */

749     public static Sequence JavaDoc getSequence(InputStream JavaDoc stream)
750     throws InvalidMidiDataException JavaDoc, IOException JavaDoc {
751
752     List JavaDoc providers = getMidiFileReaders();
753     Sequence JavaDoc sequence = null;
754
755     for(int i = 0; i < providers.size(); i++) {
756         MidiFileReader JavaDoc reader = (MidiFileReader JavaDoc) providers.get(i);
757         try {
758         sequence = reader.getSequence( stream ); // throws IOException
759
break;
760         } catch (InvalidMidiDataException JavaDoc e) {
761         continue;
762         }
763     }
764
765     if( sequence==null ) {
766         throw new InvalidMidiDataException JavaDoc("could not get sequence from input stream");
767     } else {
768         return sequence;
769     }
770     }
771
772
773     /**
774      * Obtains a MIDI sequence from the specified URL. The URL must
775      * point to valid MIDI file data for a file type recognized
776      * by the system.
777      * <p>
778      * This operation can only succeed for files of a type which can be parsed
779      * by an installed file reader. It may fail with an InvalidMidiDataException
780      * even for valid files if no compatible file reader is installed. It
781      * will also fail with an InvalidMidiDataException if a compatible file reader
782      * is installed, but encounters errors while constructing the <code>Sequence</code>
783      * object from the file data.
784      *
785      * @param url the URL from which the <code>Sequence</code> should be
786      * constructed
787      * @return a <code>Sequence</code> object based on the MIDI file data
788      * pointed to by the URL
789      * @throws InvalidMidiDataException if the URL does not point to valid MIDI
790      * file data recognized by the system
791      * @throws IOException if an I/O exception occurs while accessing the URL
792      */

793     public static Sequence JavaDoc getSequence(URL JavaDoc url)
794     throws InvalidMidiDataException JavaDoc, IOException JavaDoc {
795
796     List JavaDoc providers = getMidiFileReaders();
797     Sequence JavaDoc sequence = null;
798
799     for(int i = 0; i < providers.size(); i++) {
800         MidiFileReader JavaDoc reader = (MidiFileReader JavaDoc) providers.get(i);
801         try {
802         sequence = reader.getSequence( url ); // throws IOException
803
break;
804         } catch (InvalidMidiDataException JavaDoc e) {
805         continue;
806         }
807     }
808
809     if( sequence==null ) {
810         throw new InvalidMidiDataException JavaDoc("could not get sequence from URL");
811     } else {
812         return sequence;
813     }
814     }
815
816
817     /**
818      * Obtains a MIDI sequence from the specified <code>File</code>.
819      * The <code>File</code> must point to valid MIDI file data
820      * for a file type recognized by the system.
821      * <p>
822      * This operation can only succeed for files of a type which can be parsed
823      * by an installed file reader. It may fail with an InvalidMidiDataException
824      * even for valid files if no compatible file reader is installed. It
825      * will also fail with an InvalidMidiDataException if a compatible file reader
826      * is installed, but encounters errors while constructing the <code>Sequence</code>
827      * object from the file data.
828      *
829      * @param file the <code>File</code> from which the <code>Sequence</code>
830      * should be constructed
831      * @return a <code>Sequence</code> object based on the MIDI file data
832      * pointed to by the File
833      * @throws InvalidMidiDataException if the File does not point to valid MIDI
834      * file data recognized by the system
835      * @throws IOException if an I/O exception occurs
836      */

837     public static Sequence JavaDoc getSequence(File JavaDoc file)
838     throws InvalidMidiDataException JavaDoc, IOException JavaDoc {
839
840     List JavaDoc providers = getMidiFileReaders();
841     Sequence JavaDoc sequence = null;
842
843     for(int i = 0; i < providers.size(); i++) {
844         MidiFileReader JavaDoc reader = (MidiFileReader JavaDoc) providers.get(i);
845         try {
846         sequence = reader.getSequence( file ); // throws IOException
847
break;
848         } catch (InvalidMidiDataException JavaDoc e) {
849         continue;
850         }
851     }
852
853     if( sequence==null ) {
854         throw new InvalidMidiDataException JavaDoc("could not get sequence from file");
855     } else {
856         return sequence;
857     }
858     }
859
860
861     /**
862      * Obtains the set of MIDI file types for which file writing support is
863      * provided by the system.
864      * @return array of unique file types. If no file types are supported,
865      * an array of length 0 is returned.
866      */

867     public static int[] getMidiFileTypes() {
868
869     List JavaDoc providers = getMidiFileWriters();
870     Set JavaDoc allTypes = new HashSet JavaDoc();
871
872     // gather from all the providers
873

874     for (int i = 0; i < providers.size(); i++ ) {
875         MidiFileWriter JavaDoc writer = (MidiFileWriter JavaDoc) providers.get(i);
876         int[] types = writer.getMidiFileTypes();
877         for (int j = 0; j < types.length; j++ ) {
878         allTypes.add(new Integer JavaDoc(types[j]));
879         }
880     }
881     int resultTypes[] = new int[allTypes.size()];
882     int index = 0;
883     Iterator JavaDoc iterator = allTypes.iterator();
884     while (iterator.hasNext()) {
885         Integer JavaDoc integer = (Integer JavaDoc) iterator.next();
886         resultTypes[index++] = integer.intValue();
887     }
888     return resultTypes;
889     }
890
891
892     /**
893      * Indicates whether file writing support for the specified MIDI file type
894      * is provided by the system.
895      * @param fileType the file type for which write capabilities are queried
896      * @return <code>true</code> if the file type is supported,
897      * otherwise <code>false</code>
898      */

899     public static boolean isFileTypeSupported(int fileType) {
900
901     List JavaDoc providers = getMidiFileWriters();
902
903     for (int i = 0; i < providers.size(); i++ ) {
904         MidiFileWriter JavaDoc writer = (MidiFileWriter JavaDoc) providers.get(i);
905         if( writer.isFileTypeSupported(fileType)) {
906         return true;
907         }
908     }
909     return false;
910     }
911
912
913     /**
914      * Obtains the set of MIDI file types that the system can write from the
915      * sequence specified.
916      * @param sequence the sequence for which MIDI file type support
917      * is queried
918      * @return the set of unique supported file types. If no file types are supported,
919      * returns an array of length 0.
920      */

921     public static int[] getMidiFileTypes(Sequence JavaDoc sequence) {
922
923     List JavaDoc providers = getMidiFileWriters();
924     Set JavaDoc allTypes = new HashSet JavaDoc();
925
926     // gather from all the providers
927

928     for (int i = 0; i < providers.size(); i++ ) {
929         MidiFileWriter JavaDoc writer = (MidiFileWriter JavaDoc) providers.get(i);
930         int[] types = writer.getMidiFileTypes(sequence);
931         for (int j = 0; j < types.length; j++ ) {
932         allTypes.add(new Integer JavaDoc(types[j]));
933         }
934     }
935     int resultTypes[] = new int[allTypes.size()];
936     int index = 0;
937     Iterator JavaDoc iterator = allTypes.iterator();
938     while (iterator.hasNext()) {
939         Integer JavaDoc integer = (Integer JavaDoc) iterator.next();
940         resultTypes[index++] = integer.intValue();
941     }
942     return resultTypes;
943     }
944
945
946     /**
947      * Indicates whether a MIDI file of the file type specified can be written
948      * from the sequence indicated.
949      * @param fileType the file type for which write capabilities
950      * are queried
951      * @param sequence the sequence for which file writing support is queried
952      * @return <code>true</code> if the file type is supported for this
953      * sequence, otherwise <code>false</code>
954      */

955     public static boolean isFileTypeSupported(int fileType, Sequence JavaDoc sequence) {
956
957     List JavaDoc providers = getMidiFileWriters();
958
959     for (int i = 0; i < providers.size(); i++ ) {
960         MidiFileWriter JavaDoc writer = (MidiFileWriter JavaDoc) providers.get(i);
961         if( writer.isFileTypeSupported(fileType,sequence)) {
962         return true;
963         }
964     }
965     return false;
966     }
967
968
969     /**
970      * Writes a stream of bytes representing a file of the MIDI file type
971      * indicated to the output stream provided.
972      * @param in sequence containing MIDI data to be written to the file
973      * @param fileType the file type of the file to be written to the output stream
974      * @param out stream to which the file data should be written
975      * @return the number of bytes written to the output stream
976      * @throws IOException if an I/O exception occurs
977      * @throws IllegalArgumentException if the file format is not supported by
978      * the system
979      * @see #isFileTypeSupported(int, Sequence)
980      * @see #getMidiFileTypes(Sequence)
981      */

982     public static int write(Sequence JavaDoc in, int fileType, OutputStream JavaDoc out) throws IOException JavaDoc {
983
984     List JavaDoc providers = getMidiFileWriters();
985     //$$fb 2002-04-17: Fix for 4635287: Standard MidiFileWriter cannot write empty Sequences
986
int bytesWritten = -2;
987
988     for (int i = 0; i < providers.size(); i++ ) {
989         MidiFileWriter JavaDoc writer = (MidiFileWriter JavaDoc) providers.get(i);
990         if( writer.isFileTypeSupported( fileType, in ) ) {
991
992         bytesWritten = writer.write(in, fileType, out);
993         break;
994         }
995     }
996     if (bytesWritten == -2) {
997         throw new IllegalArgumentException JavaDoc("MIDI file type is not supported");
998     }
999     return bytesWritten;
1000    }
1001
1002
1003    /**
1004     * Writes a stream of bytes representing a file of the MIDI file type
1005     * indicated to the external file provided.
1006     * @param in sequence containing MIDI data to be written to the file
1007     * @param type the file type of the file to be written to the output stream
1008     * @param out external file to which the file data should be written
1009     * @return the number of bytes written to the file
1010     * @throws IOException if an I/O exception occurs
1011     * @throws IllegalArgumentException if the file type is not supported by
1012     * the system
1013     * @see #isFileTypeSupported(int, Sequence)
1014     * @see #getMidiFileTypes(Sequence)
1015     */

1016    public static int write(Sequence JavaDoc in, int type, File JavaDoc out) throws IOException JavaDoc {
1017
1018    List JavaDoc providers = getMidiFileWriters();
1019    //$$fb 2002-04-17: Fix for 4635287: Standard MidiFileWriter cannot write empty Sequences
1020
int bytesWritten = -2;
1021
1022    for (int i = 0; i < providers.size(); i++ ) {
1023        MidiFileWriter JavaDoc writer = (MidiFileWriter JavaDoc) providers.get(i);
1024        if( writer.isFileTypeSupported( type, in ) ) {
1025
1026        bytesWritten = writer.write(in, type, out);
1027        break;
1028        }
1029    }
1030    if (bytesWritten == -2) {
1031        throw new IllegalArgumentException JavaDoc("MIDI file type is not supported");
1032    }
1033    return bytesWritten;
1034    }
1035
1036
1037
1038    // HELPER METHODS
1039

1040    private static List JavaDoc getMidiDeviceProviders() {
1041    return getProviders(MidiDeviceProvider JavaDoc.class);
1042    }
1043
1044
1045    private static List JavaDoc getSoundbankReaders() {
1046    return getProviders(SoundbankReader JavaDoc.class);
1047    }
1048
1049
1050    private static List JavaDoc getMidiFileWriters() {
1051    return getProviders(MidiFileWriter JavaDoc.class);
1052    }
1053
1054
1055    private static List JavaDoc getMidiFileReaders() {
1056    return getProviders(MidiFileReader JavaDoc.class);
1057    }
1058
1059
1060    /** Attempts to locate and return a default MidiDevice of the specified
1061     * type.
1062     *
1063     * This method wraps {@link #getDefaultDevice}. It catches the
1064     * <code>IllegalArgumentException</code> thrown by
1065     * <code>getDefaultDevice</code> and instead throws a
1066     * <code>MidiUnavailableException</code>, with the catched
1067     * exception chained.
1068     *
1069     * @param deviceClass The requested device type, one of Synthesizer.class,
1070     * Sequencer.class, Receiver.class or Transmitter.class.
1071     * @throws MidiUnavalableException on failure.
1072     */

1073    private static MidiDevice JavaDoc getDefaultDeviceWrapper(Class JavaDoc deviceClass)
1074    throws MidiUnavailableException JavaDoc{
1075    try {
1076        return getDefaultDevice(deviceClass);
1077    } catch (IllegalArgumentException JavaDoc iae) {
1078        MidiUnavailableException JavaDoc mae = new MidiUnavailableException JavaDoc();
1079        mae.initCause(iae);
1080        throw mae;
1081    }
1082    }
1083
1084
1085    /** Attempts to locate and return a default MidiDevice of the specified
1086     * type.
1087     *
1088     * @param deviceClass The requested device type, one of Synthesizer.class,
1089     * Sequencer.class, Receiver.class or Transmitter.class.
1090     * @throws IllegalArgumentException on failure.
1091     */

1092    private static MidiDevice JavaDoc getDefaultDevice(Class JavaDoc deviceClass) {
1093    List JavaDoc providers = getMidiDeviceProviders();
1094    String JavaDoc providerClassName = JDK13Services.getDefaultProviderClassName(deviceClass);
1095    String JavaDoc instanceName = JDK13Services.getDefaultInstanceName(deviceClass);
1096    MidiDevice JavaDoc device;
1097
1098    if (providerClassName != null) {
1099        MidiDeviceProvider JavaDoc defaultProvider = getNamedProvider(providerClassName, providers);
1100        if (defaultProvider != null) {
1101        if (instanceName != null) {
1102            device = getNamedDevice(instanceName, defaultProvider, deviceClass);
1103            if (device != null) {
1104            return device;
1105            }
1106        }
1107        device = getFirstDevice(defaultProvider, deviceClass);
1108        if (device != null) {
1109            return device;
1110        }
1111        }
1112    }
1113
1114    /* Provider class not specified or cannot be found, or
1115       provider class specified, and no appropriate device available or
1116       provider class and instance specified and instance cannot be found or is not appropriate */

1117    if (instanceName != null) {
1118        device = getNamedDevice(instanceName, providers, deviceClass);
1119        if (device != null) {
1120        return device;
1121        }
1122    }
1123
1124    /* No default are specified, or if something is specified, everything
1125       failed. */

1126    device = getFirstDevice(providers, deviceClass);
1127    if (device != null) {
1128        return device;
1129    }
1130    throw new IllegalArgumentException JavaDoc("Requested device not installed");
1131    }
1132
1133
1134
1135    /** Return a MidiDeviceProcider of a given class from the list of
1136    MidiDeviceProviders.
1137
1138    @param providerClassName The class name of the provider to be returned.
1139    @param provider The list of MidiDeviceProviders that is searched.
1140    @return A MidiDeviceProvider of the requested class, or null if none
1141    is found.
1142    */

1143    private static MidiDeviceProvider JavaDoc getNamedProvider(String JavaDoc providerClassName, List JavaDoc providers) {
1144    for(int i = 0; i < providers.size(); i++) {
1145        MidiDeviceProvider JavaDoc provider = (MidiDeviceProvider JavaDoc) providers.get(i);
1146        if (provider.getClass().getName().equals(providerClassName)) {
1147        return provider;
1148        }
1149    }
1150    return null;
1151    }
1152
1153
1154    /** Return a MidiDevice with a given name from a given MidiDeviceProvider.
1155    @param deviceName The name of the MidiDevice to be returned.
1156    @param provider The MidiDeviceProvider to check for MidiDevices.
1157    @param deviceClass The requested device type, one of Synthesizer.class,
1158    Sequencer.class, Receiver.class or Transmitter.class.
1159
1160    @return A MidiDevice matching the requirements, or null if none is found.
1161    */

1162    private static MidiDevice JavaDoc getNamedDevice(String JavaDoc deviceName,
1163                         MidiDeviceProvider JavaDoc provider,
1164                         Class JavaDoc deviceClass) {
1165    MidiDevice JavaDoc device;
1166    // try to get MIDI port
1167
device = getNamedDevice(deviceName, provider, deviceClass,
1168                 false, false);
1169    if (device != null) {
1170        return device;
1171    }
1172
1173    if (deviceClass == Receiver JavaDoc.class) {
1174        // try to get Synthesizer
1175
device = getNamedDevice(deviceName, provider, deviceClass,
1176                     true, false);
1177        if (device != null) {
1178        return device;
1179        }
1180    }
1181
1182    // try to get Sequncer or Synthesizer
1183
return getNamedDevice(deviceName, provider, deviceClass,
1184                   true, true);
1185    }
1186
1187
1188    /** Return a MidiDevice with a given name from a given MidiDeviceProvider.
1189      @param deviceName The name of the MidiDevice to be returned.
1190      @param provider The MidiDeviceProvider to check for MidiDevices.
1191      @param deviceClass The requested device type, one of Synthesizer.class,
1192      Sequencer.class, Receiver.class or Transmitter.class.
1193
1194      @return A MidiDevice matching the requirements, or null if none is found.
1195     */

1196    private static MidiDevice JavaDoc getNamedDevice(String JavaDoc deviceName,
1197                         MidiDeviceProvider JavaDoc provider,
1198                         Class JavaDoc deviceClass,
1199                         boolean allowSynthesizer,
1200                         boolean allowSequencer) {
1201    MidiDevice.Info JavaDoc[] infos = provider.getDeviceInfo();
1202    for (int i = 0; i < infos.length; i++) {
1203        if (infos[i].getName().equals(deviceName)) {
1204        MidiDevice JavaDoc device = provider.getDevice(infos[i]);
1205        if (isAppropriateDevice(device, deviceClass,
1206                    allowSynthesizer, allowSequencer)) {
1207            return device;
1208        }
1209        }
1210    }
1211    return null;
1212    }
1213
1214
1215    /** Return a MidiDevice with a given name from a list of
1216    MidiDeviceProviders.
1217    @param deviceName The name of the MidiDevice to be returned.
1218    @param providers The List of MidiDeviceProviders to check for
1219    MidiDevices.
1220    @param deviceClass The requested device type, one of Synthesizer.class,
1221    Sequencer.class, Receiver.class or Transmitter.class.
1222    @return A Mixer matching the requirements, or null if none is found.
1223    */

1224    private static MidiDevice JavaDoc getNamedDevice(String JavaDoc deviceName,
1225                         List JavaDoc providers,
1226                         Class JavaDoc deviceClass) {
1227    MidiDevice JavaDoc device;
1228    // try to get MIDI port
1229
device = getNamedDevice(deviceName, providers, deviceClass,
1230                 false, false);
1231    if (device != null) {
1232        return device;
1233    }
1234
1235    if (deviceClass == Receiver JavaDoc.class) {
1236        // try to get Synthesizer
1237
device = getNamedDevice(deviceName, providers, deviceClass,
1238                     true, false);
1239        if (device != null) {
1240        return device;
1241        }
1242    }
1243
1244    // try to get Sequncer or Synthesizer
1245
return getNamedDevice(deviceName, providers, deviceClass,
1246                   true, true);
1247    }
1248
1249
1250    /** Return a MidiDevice with a given name from a list of
1251    MidiDeviceProviders.
1252    @param deviceName The name of the MidiDevice to be returned.
1253    @param providers The List of MidiDeviceProviders to check for
1254    MidiDevices.
1255    @param deviceClass The requested device type, one of Synthesizer.class,
1256    Sequencer.class, Receiver.class or Transmitter.class.
1257    @return A Mixer matching the requirements, or null if none is found.
1258     */

1259    private static MidiDevice JavaDoc getNamedDevice(String JavaDoc deviceName,
1260                         List JavaDoc providers,
1261                         Class JavaDoc deviceClass,
1262                         boolean allowSynthesizer,
1263                         boolean allowSequencer) {
1264    for(int i = 0; i < providers.size(); i++) {
1265        MidiDeviceProvider JavaDoc provider = (MidiDeviceProvider JavaDoc) providers.get(i);
1266        MidiDevice JavaDoc device = getNamedDevice(deviceName, provider,
1267                           deviceClass,
1268                           allowSynthesizer,
1269                           allowSequencer);
1270        if (device != null) {
1271        return device;
1272        }
1273    }
1274    return null;
1275    }
1276
1277
1278    /** From a given MidiDeviceProvider, return the first appropriate device.
1279    @param provider The MidiDeviceProvider to check for MidiDevices.
1280    @param deviceClass The requested device type, one of Synthesizer.class,
1281    Sequencer.class, Receiver.class or Transmitter.class.
1282    @return A MidiDevice is considered appropriate, or null if no
1283    appropriate device is found.
1284    */

1285    private static MidiDevice JavaDoc getFirstDevice(MidiDeviceProvider JavaDoc provider,
1286                         Class JavaDoc deviceClass) {
1287    MidiDevice JavaDoc device;
1288    // try to get MIDI port
1289
device = getFirstDevice(provider, deviceClass,
1290                false, false);
1291    if (device != null) {
1292        return device;
1293    }
1294
1295    if (deviceClass == Receiver JavaDoc.class) {
1296        // try to get Synthesizer
1297
device = getFirstDevice(provider, deviceClass,
1298                    true, false);
1299        if (device != null) {
1300        return device;
1301        }
1302    }
1303
1304    // try to get Sequncer or Synthesizer
1305
return getFirstDevice(provider, deviceClass,
1306                  true, true);
1307    }
1308
1309
1310    /** From a given MidiDeviceProvider, return the first appropriate device.
1311    @param provider The MidiDeviceProvider to check for MidiDevices.
1312    @param deviceClass The requested device type, one of Synthesizer.class,
1313    Sequencer.class, Receiver.class or Transmitter.class.
1314    @return A MidiDevice is considered appropriate, or null if no
1315    appropriate device is found.
1316     */

1317    private static MidiDevice JavaDoc getFirstDevice(MidiDeviceProvider JavaDoc provider,
1318                         Class JavaDoc deviceClass,
1319                         boolean allowSynthesizer,
1320                         boolean allowSequencer) {
1321    MidiDevice.Info JavaDoc[] infos = provider.getDeviceInfo();
1322    for (int j = 0; j < infos.length; j++) {
1323        MidiDevice JavaDoc device = provider.getDevice(infos[j]);
1324        if (isAppropriateDevice(device, deviceClass,
1325                    allowSynthesizer, allowSequencer)) {
1326        return device;
1327        }
1328    }
1329    return null;
1330    }
1331
1332
1333    /** From a List of MidiDeviceProviders, return the first appropriate
1334    MidiDevice.
1335    @param providers The List of MidiDeviceProviders to search.
1336    @param deviceClass The requested device type, one of Synthesizer.class,
1337    Sequencer.class, Receiver.class or Transmitter.class.
1338    @return A MidiDevice that is considered appropriate, or null
1339    if none is found.
1340    */

1341    private static MidiDevice JavaDoc getFirstDevice(List JavaDoc providers,
1342                         Class JavaDoc deviceClass) {
1343    MidiDevice JavaDoc device;
1344    // try to get MIDI port
1345
device = getFirstDevice(providers, deviceClass,
1346                false, false);
1347    if (device != null) {
1348        return device;
1349    }
1350
1351    if (deviceClass == Receiver JavaDoc.class) {
1352        // try to get Synthesizer
1353
device = getFirstDevice(providers, deviceClass,
1354                    true, false);
1355        if (device != null) {
1356        return device;
1357        }
1358    }
1359
1360    // try to get Sequncer or Synthesizer
1361
return getFirstDevice(providers, deviceClass,
1362                  true, true);
1363    }
1364
1365
1366    /** From a List of MidiDeviceProviders, return the first appropriate
1367    MidiDevice.
1368    @param providers The List of MidiDeviceProviders to search.
1369    @param deviceClass The requested device type, one of Synthesizer.class,
1370    Sequencer.class, Receiver.class or Transmitter.class.
1371    @return A MidiDevice that is considered appropriate, or null
1372    if none is found.
1373     */

1374    private static MidiDevice JavaDoc getFirstDevice(List JavaDoc providers,
1375                         Class JavaDoc deviceClass,
1376                         boolean allowSynthesizer,
1377                         boolean allowSequencer) {
1378    for(int i = 0; i < providers.size(); i++) {
1379        MidiDeviceProvider JavaDoc provider = (MidiDeviceProvider JavaDoc) providers.get(i);
1380        MidiDevice JavaDoc device = getFirstDevice(provider, deviceClass,
1381                           allowSynthesizer,
1382                           allowSequencer);
1383        if (device != null) {
1384        return device;
1385        }
1386    }
1387    return null;
1388    }
1389
1390
1391    /** Checks if a MidiDevice is appropriate.
1392    If deviceClass is Synthesizer or Sequencer, a device implementing
1393    the respective interface is considered appropriate. If deviceClass
1394    is Receiver or Transmitter, a device is considered appropriate if
1395    it implements neither Synthesizer nor Transmitter, and if it can
1396    provide at least one Receiver or Transmitter, respectively.
1397
1398    @param device the MidiDevice to test
1399    @param allowSynthesizer if true, Synthesizers are considered
1400    appropriate. Otherwise only pure MidiDevices are considered
1401    appropriate (unless allowSequencer is true). This flag only has an
1402    effect for deviceClass Receiver and Transmitter. For other device
1403    classes (Sequencer and Synthesizer), this flag has no effect.
1404    @param allowSequencer if true, Sequencers are considered
1405    appropriate. Otherwise only pure MidiDevices are considered
1406    appropriate (unless allowSynthesizer is true). This flag only has an
1407    effect for deviceClass Receiver and Transmitter. For other device
1408    classes (Sequencer and Synthesizer), this flag has no effect.
1409    @return true if the device is considered appropriate according to the
1410    rules given above, false otherwise.
1411    */

1412    private static boolean isAppropriateDevice(MidiDevice JavaDoc device,
1413                           Class JavaDoc deviceClass,
1414                           boolean allowSynthesizer,
1415                           boolean allowSequencer) {
1416    if (deviceClass.isInstance(device)) {
1417        // This clause is for deviceClass being either Synthesizer
1418
// or Sequencer.
1419
return true;
1420    } else {
1421        // Now the case that deviceClass is Transmitter or
1422
// Receiver. If neither allowSynthesizer nor allowSequencer is
1423
// true, we require device instances to be
1424
// neither Synthesizer nor Sequencer, since we only want
1425
// devices representing MIDI ports.
1426
// Otherwise, the respective type is accepted, too
1427
if ( (! (device instanceof Sequencer JavaDoc) &&
1428          ! (device instanceof Synthesizer JavaDoc) ) ||
1429         ((device instanceof Sequencer JavaDoc) && allowSequencer) ||
1430         ((device instanceof Synthesizer JavaDoc) && allowSynthesizer)) {
1431        // And of cource, the device has to be able to provide
1432
// Receivers or Transmitters.
1433
if ((deviceClass == Receiver JavaDoc.class &&
1434             device.getMaxReceivers() != 0) ||
1435            (deviceClass == Transmitter JavaDoc.class &&
1436             device.getMaxTransmitters() != 0)) {
1437            return true;
1438        }
1439        }
1440    }
1441    return false;
1442    }
1443
1444
1445    /**
1446     * Obtains the set of services currently installed on the system
1447     * using sun.misc.Service, the SPI mechanism in 1.3.
1448     * @return a List of instances of providers for the requested service.
1449     * If no providers are available, a List of length 0 will be returned.
1450     */

1451    private static List JavaDoc getProviders(Class JavaDoc providerClass) {
1452    return JDK13Services.getProviders(providerClass);
1453    }
1454}
1455
Popular Tags