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;
8