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