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+
26+package javax.sound.midi;
27+
28+import java.io.FileInputStream;
29+import java.io.File;
30+import java.io.InputStream;
31+import java.io.OutputStream;
32+import java.io.IOException;
33+
34+import java.util.ArrayList;
35+import java.util.HashSet;
36+import java.util.Iterator;
37+import java.util.List;
38+import java.util.Set;
39+
40+import java.net.URL;
41+
42+import javax.sound.midi.spi.MidiFileWriter;
43+import javax.sound.midi.spi.MidiFileReader;
44+import javax.sound.midi.spi.SoundbankReader;
45+import javax.sound.midi.spi.MidiDeviceProvider;
46+
47+import com.sun.media.sound.JDK13Services;
48+import com.sun.media.sound.ReferenceCountingDevice;
49+import com.sun.media.sound.AutoConnectSequencer;
50+import com.sun.media.sound.MidiDeviceReceiverEnvelope;
51+import 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+ */
166+public 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+}