History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/javax/sound/midi/MidiSystem.java (1 of 18352 files). Show all

Unified · Split

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