src/share/classes/javax/sound/midi/MidiSystem.java

Print this page




 170 
 171     /**
 172      * Private no-args constructor for ensuring against instantiation.
 173      */
 174     private MidiSystem() {
 175     }
 176 
 177 
 178     /**
 179      * Obtains an array of information objects representing
 180      * the set of all MIDI devices available on the system.
 181      * A returned information object can then be used to obtain the
 182      * corresponding device object, by invoking
 183      * {@link #getMidiDevice(MidiDevice.Info) getMidiDevice}.
 184      *
 185      * @return an array of <code>MidiDevice.Info</code> objects, one
 186      * for each installed MIDI device.  If no such devices are installed,
 187      * an array of length 0 is returned.
 188      */
 189     public static MidiDevice.Info[] getMidiDeviceInfo() {
 190         List allInfos = new ArrayList();
 191         List providers = getMidiDeviceProviders();
 192 
 193         for(int i = 0; i < providers.size(); i++) {
 194             MidiDeviceProvider provider = (MidiDeviceProvider) providers.get(i);
 195             MidiDevice.Info[] tmpinfo = provider.getDeviceInfo();
 196             for (int j = 0; j < tmpinfo.length; j++) {
 197                 allInfos.add( tmpinfo[j] );
 198             }
 199         }
 200         MidiDevice.Info[] infosArray = (MidiDevice.Info[]) allInfos.toArray(new MidiDevice.Info[0]);
 201         return infosArray;
 202     }
 203 
 204 
 205     /**
 206      * Obtains the requested MIDI device.
 207      *
 208      * @param info a device information object representing the desired device.
 209      * @return the requested device
 210      * @throws MidiUnavailableException if the requested device is not available
 211      * due to resource restrictions
 212      * @throws IllegalArgumentException if the info object does not represent
 213      * a MIDI device installed on the system
 214      * @see #getMidiDeviceInfo
 215      */
 216     public static MidiDevice getMidiDevice(MidiDevice.Info info) throws MidiUnavailableException {
 217         List providers = getMidiDeviceProviders();
 218 
 219         for(int i = 0; i < providers.size(); i++) {
 220             MidiDeviceProvider provider = (MidiDeviceProvider) providers.get(i);
 221             if (provider.isDeviceSupported(info)) {
 222                 MidiDevice device = provider.getDevice(info);
 223                 return device;
 224             }
 225         }
 226         throw new IllegalArgumentException("Requested device not installed: " + info);
 227     }
 228 
 229 
 230     /**
 231      * Obtains a MIDI receiver from an external MIDI port
 232      * or other default device.
 233      * The returned receiver always implements
 234      * the {@code MidiDeviceReceiver} interface.
 235      *
 236      * <p>If the system property
 237      * <code>javax.sound.midi.Receiver</code>
 238      * is defined or it is defined in the file &quot;sound.properties&quot;,
 239      * it is used to identify the device that provides the default receiver.
 240      * For details, refer to the {@link MidiSystem class description}.


 511      * need to read some data from the stream before determining whether they
 512      * support it.  These parsers must
 513      * be able to mark the stream, read enough data to determine whether they
 514      * support the stream, and, if not, reset the stream's read pointer to
 515      * its original position.  If the input stream does not support this,
 516      * this method may fail with an IOException.
 517      * @param stream the source of the sound bank data.
 518      * @return the sound bank
 519      * @throws InvalidMidiDataException if the stream does not point to
 520      * valid MIDI soundbank data recognized by the system
 521      * @throws IOException if an I/O error occurred when loading the soundbank
 522      * @see InputStream#markSupported
 523      * @see InputStream#mark
 524      */
 525     public static Soundbank getSoundbank(InputStream stream)
 526         throws InvalidMidiDataException, IOException {
 527 
 528         SoundbankReader sp = null;
 529         Soundbank s = null;
 530 
 531         List providers = getSoundbankReaders();
 532 
 533         for(int i = 0; i < providers.size(); i++) {
 534             sp = (SoundbankReader)providers.get(i);
 535             s = sp.getSoundbank(stream);
 536 
 537             if( s!= null) {
 538                 return s;
 539             }
 540         }
 541         throw new InvalidMidiDataException("cannot get soundbank from stream");
 542 
 543     }
 544 
 545 
 546     /**
 547      * Constructs a <code>Soundbank</code> by reading it from the specified URL.
 548      * The URL must point to a valid MIDI soundbank file.
 549      *
 550      * @param url the source of the sound bank data
 551      * @return the sound bank
 552      * @throws InvalidMidiDataException if the URL does not point to valid MIDI
 553      * soundbank data recognized by the system
 554      * @throws IOException if an I/O error occurred when loading the soundbank
 555      */
 556     public static Soundbank getSoundbank(URL url)
 557         throws InvalidMidiDataException, IOException {
 558 
 559         SoundbankReader sp = null;
 560         Soundbank s = null;
 561 
 562         List providers = getSoundbankReaders();
 563 
 564         for(int i = 0; i < providers.size(); i++) {
 565             sp = (SoundbankReader)providers.get(i);
 566             s = sp.getSoundbank(url);
 567 
 568             if( s!= null) {
 569                 return s;
 570             }
 571         }
 572         throw new InvalidMidiDataException("cannot get soundbank from stream");
 573 
 574     }
 575 
 576 
 577     /**
 578      * Constructs a <code>Soundbank</code> by reading it from the specified
 579      * <code>File</code>.
 580      * The <code>File</code> must point to a valid MIDI soundbank file.
 581      *
 582      * @param file the source of the sound bank data
 583      * @return the sound bank
 584      * @throws InvalidMidiDataException if the <code>File</code> does not
 585      * point to valid MIDI soundbank data recognized by the system
 586      * @throws IOException if an I/O error occurred when loading the soundbank
 587      */
 588     public static Soundbank getSoundbank(File file)
 589         throws InvalidMidiDataException, IOException {
 590 
 591         SoundbankReader sp = null;
 592         Soundbank s = null;
 593 
 594         List providers = getSoundbankReaders();
 595 
 596         for(int i = 0; i < providers.size(); i++) {
 597             sp = (SoundbankReader)providers.get(i);
 598             s = sp.getSoundbank(file);
 599 
 600             if( s!= null) {
 601                 return s;
 602             }
 603         }
 604         throw new InvalidMidiDataException("cannot get soundbank from stream");
 605     }
 606 
 607 
 608 
 609     /**
 610      * Obtains the MIDI file format of the data in the specified input stream.
 611      * The stream must point to valid MIDI file data for a file type recognized
 612      * by the system.
 613      * <p>
 614      * This method and/or the code it invokes may need to read some data from
 615      * the stream to determine whether its data format is supported.  The
 616      * implementation may therefore
 617      * need to mark the stream, read enough data to determine whether it is in


 624      * even for valid files if no compatible file reader is installed.  It
 625      * will also fail with an InvalidMidiDataException if a compatible file reader
 626      * is installed, but encounters errors while determining the file format.
 627      *
 628      * @param stream the input stream from which file format information
 629      * should be extracted
 630      * @return an <code>MidiFileFormat</code> object describing the MIDI file
 631      * format
 632      * @throws InvalidMidiDataException if the stream does not point to valid
 633      * MIDI file data recognized by the system
 634      * @throws IOException if an I/O exception occurs while accessing the
 635      * stream
 636      * @see #getMidiFileFormat(URL)
 637      * @see #getMidiFileFormat(File)
 638      * @see InputStream#markSupported
 639      * @see InputStream#mark
 640      */
 641     public static MidiFileFormat getMidiFileFormat(InputStream stream)
 642         throws InvalidMidiDataException, IOException {
 643 
 644         List providers = getMidiFileReaders();
 645         MidiFileFormat format = null;
 646 
 647         for(int i = 0; i < providers.size(); i++) {
 648             MidiFileReader reader = (MidiFileReader) providers.get(i);
 649             try {
 650                 format = reader.getMidiFileFormat( stream ); // throws IOException
 651                 break;
 652             } catch (InvalidMidiDataException e) {
 653                 continue;
 654             }
 655         }
 656 
 657         if( format==null ) {
 658             throw new InvalidMidiDataException("input stream is not a supported file type");
 659         } else {
 660             return format;
 661         }
 662     }
 663 
 664 
 665     /**
 666      * Obtains the MIDI file format of the data in the specified URL.  The URL
 667      * must point to valid MIDI file data for a file type recognized
 668      * by the system.


 670      * This operation can only succeed for files of a type which can be parsed
 671      * by an installed file reader.  It may fail with an InvalidMidiDataException
 672      * even for valid files if no compatible file reader is installed.  It
 673      * will also fail with an InvalidMidiDataException if a compatible file reader
 674      * is installed, but encounters errors while determining the file format.
 675      *
 676      * @param url the URL from which file format information should be
 677      * extracted
 678      * @return a <code>MidiFileFormat</code> object describing the MIDI file
 679      * format
 680      * @throws InvalidMidiDataException if the URL does not point to valid MIDI
 681      * file data recognized by the system
 682      * @throws IOException if an I/O exception occurs while accessing the URL
 683      *
 684      * @see #getMidiFileFormat(InputStream)
 685      * @see #getMidiFileFormat(File)
 686      */
 687     public static MidiFileFormat getMidiFileFormat(URL url)
 688         throws InvalidMidiDataException, IOException {
 689 
 690         List providers = getMidiFileReaders();
 691         MidiFileFormat format = null;
 692 
 693         for(int i = 0; i < providers.size(); i++) {
 694             MidiFileReader reader = (MidiFileReader) providers.get(i);
 695             try {
 696                 format = reader.getMidiFileFormat( url ); // throws IOException
 697                 break;
 698             } catch (InvalidMidiDataException e) {
 699                 continue;
 700             }
 701         }
 702 
 703         if( format==null ) {
 704             throw new InvalidMidiDataException("url is not a supported file type");
 705         } else {
 706             return format;
 707         }
 708     }
 709 
 710 
 711     /**
 712      * Obtains the MIDI file format of the specified <code>File</code>.  The
 713      * <code>File</code> must point to valid MIDI file data for a file type
 714      * recognized by the system.


 716      * This operation can only succeed for files of a type which can be parsed
 717      * by an installed file reader.  It may fail with an InvalidMidiDataException
 718      * even for valid files if no compatible file reader is installed.  It
 719      * will also fail with an InvalidMidiDataException if a compatible file reader
 720      * is installed, but encounters errors while determining the file format.
 721      *
 722      * @param file the <code>File</code> from which file format information
 723      * should be extracted
 724      * @return a <code>MidiFileFormat</code> object describing the MIDI file
 725      * format
 726      * @throws InvalidMidiDataException if the <code>File</code> does not point
 727      *  to valid MIDI file data recognized by the system
 728      * @throws IOException if an I/O exception occurs while accessing the file
 729      *
 730      * @see #getMidiFileFormat(InputStream)
 731      * @see #getMidiFileFormat(URL)
 732      */
 733     public static MidiFileFormat getMidiFileFormat(File file)
 734         throws InvalidMidiDataException, IOException {
 735 
 736         List providers = getMidiFileReaders();
 737         MidiFileFormat format = null;
 738 
 739         for(int i = 0; i < providers.size(); i++) {
 740             MidiFileReader reader = (MidiFileReader) providers.get(i);
 741             try {
 742                 format = reader.getMidiFileFormat( file ); // throws IOException
 743                 break;
 744             } catch (InvalidMidiDataException e) {
 745                 continue;
 746             }
 747         }
 748 
 749         if( format==null ) {
 750             throw new InvalidMidiDataException("file is not a supported file type");
 751         } else {
 752             return format;
 753         }
 754     }
 755 
 756 
 757     /**
 758      * Obtains a MIDI sequence from the specified input stream.  The stream must
 759      * point to valid MIDI file data for a file type recognized
 760      * by the system.


 771      * by an installed file reader.  It may fail with an InvalidMidiDataException
 772      * even for valid files if no compatible file reader is installed.  It
 773      * will also fail with an InvalidMidiDataException if a compatible file reader
 774      * is installed, but encounters errors while constructing the <code>Sequence</code>
 775      * object from the file data.
 776      *
 777      * @param stream the input stream from which the <code>Sequence</code>
 778      * should be constructed
 779      * @return a <code>Sequence</code> object based on the MIDI file data
 780      * contained in the input stream
 781      * @throws InvalidMidiDataException if the stream does not point to
 782      * valid MIDI file data recognized by the system
 783      * @throws IOException if an I/O exception occurs while accessing the
 784      * stream
 785      * @see InputStream#markSupported
 786      * @see InputStream#mark
 787      */
 788     public static Sequence getSequence(InputStream stream)
 789         throws InvalidMidiDataException, IOException {
 790 
 791         List providers = getMidiFileReaders();
 792         Sequence sequence = null;
 793 
 794         for(int i = 0; i < providers.size(); i++) {
 795             MidiFileReader reader = (MidiFileReader) providers.get(i);
 796             try {
 797                 sequence = reader.getSequence( stream ); // throws IOException
 798                 break;
 799             } catch (InvalidMidiDataException e) {
 800                 continue;
 801             }
 802         }
 803 
 804         if( sequence==null ) {
 805             throw new InvalidMidiDataException("could not get sequence from input stream");
 806         } else {
 807             return sequence;
 808         }
 809     }
 810 
 811 
 812     /**
 813      * Obtains a MIDI sequence from the specified URL.  The URL must
 814      * point to valid MIDI file data for a file type recognized
 815      * by the system.
 816      * <p>
 817      * This operation can only succeed for files of a type which can be parsed
 818      * by an installed file reader.  It may fail with an InvalidMidiDataException
 819      * even for valid files if no compatible file reader is installed.  It
 820      * will also fail with an InvalidMidiDataException if a compatible file reader
 821      * is installed, but encounters errors while constructing the <code>Sequence</code>
 822      * object from the file data.
 823      *
 824      * @param url the URL from which the <code>Sequence</code> should be
 825      * constructed
 826      * @return a <code>Sequence</code> object based on the MIDI file data
 827      * pointed to by the URL
 828      * @throws InvalidMidiDataException if the URL does not point to valid MIDI
 829      * file data recognized by the system
 830      * @throws IOException if an I/O exception occurs while accessing the URL
 831      */
 832     public static Sequence getSequence(URL url)
 833         throws InvalidMidiDataException, IOException {
 834 
 835         List providers = getMidiFileReaders();
 836         Sequence sequence = null;
 837 
 838         for(int i = 0; i < providers.size(); i++) {
 839             MidiFileReader reader = (MidiFileReader) providers.get(i);
 840             try {
 841                 sequence = reader.getSequence( url ); // throws IOException
 842                 break;
 843             } catch (InvalidMidiDataException e) {
 844                 continue;
 845             }
 846         }
 847 
 848         if( sequence==null ) {
 849             throw new InvalidMidiDataException("could not get sequence from URL");
 850         } else {
 851             return sequence;
 852         }
 853     }
 854 
 855 
 856     /**
 857      * Obtains a MIDI sequence from the specified <code>File</code>.
 858      * The <code>File</code> must point to valid MIDI file data
 859      * for a file type recognized by the system.
 860      * <p>
 861      * This operation can only succeed for files of a type which can be parsed
 862      * by an installed file reader.  It may fail with an InvalidMidiDataException
 863      * even for valid files if no compatible file reader is installed.  It
 864      * will also fail with an InvalidMidiDataException if a compatible file reader
 865      * is installed, but encounters errors while constructing the <code>Sequence</code>
 866      * object from the file data.
 867      *
 868      * @param file the <code>File</code> from which the <code>Sequence</code>
 869      * should be constructed
 870      * @return a <code>Sequence</code> object based on the MIDI file data
 871      * pointed to by the File
 872      * @throws InvalidMidiDataException if the File does not point to valid MIDI
 873      * file data recognized by the system
 874      * @throws IOException if an I/O exception occurs
 875      */
 876     public static Sequence getSequence(File file)
 877         throws InvalidMidiDataException, IOException {
 878 
 879         List providers = getMidiFileReaders();
 880         Sequence sequence = null;
 881 
 882         for(int i = 0; i < providers.size(); i++) {
 883             MidiFileReader reader = (MidiFileReader) providers.get(i);
 884             try {
 885                 sequence = reader.getSequence( file ); // throws IOException
 886                 break;
 887             } catch (InvalidMidiDataException e) {
 888                 continue;
 889             }
 890         }
 891 
 892         if( sequence==null ) {
 893             throw new InvalidMidiDataException("could not get sequence from file");
 894         } else {
 895             return sequence;
 896         }
 897     }
 898 
 899 
 900     /**
 901      * Obtains the set of MIDI file types for which file writing support is
 902      * provided by the system.
 903      * @return array of unique file types.  If no file types are supported,
 904      * an array of length 0 is returned.
 905      */
 906     public static int[] getMidiFileTypes() {
 907 
 908         List providers = getMidiFileWriters();
 909         Set allTypes = new HashSet();
 910 
 911         // gather from all the providers
 912 
 913         for (int i = 0; i < providers.size(); i++ ) {
 914             MidiFileWriter writer = (MidiFileWriter) providers.get(i);
 915             int[] types = writer.getMidiFileTypes();
 916             for (int j = 0; j < types.length; j++ ) {
 917                 allTypes.add(new Integer(types[j]));
 918             }
 919         }
 920         int resultTypes[] = new int[allTypes.size()];
 921         int index = 0;
 922         Iterator iterator = allTypes.iterator();
 923         while (iterator.hasNext()) {
 924             Integer integer = (Integer) iterator.next();
 925             resultTypes[index++] = integer.intValue();
 926         }
 927         return resultTypes;
 928     }
 929 
 930 
 931     /**
 932      * Indicates whether file writing support for the specified MIDI file type
 933      * is provided by the system.
 934      * @param fileType the file type for which write capabilities are queried
 935      * @return <code>true</code> if the file type is supported,
 936      * otherwise <code>false</code>
 937      */
 938     public static boolean isFileTypeSupported(int fileType) {
 939 
 940         List providers = getMidiFileWriters();
 941 
 942         for (int i = 0; i < providers.size(); i++ ) {
 943             MidiFileWriter writer = (MidiFileWriter) providers.get(i);
 944             if( writer.isFileTypeSupported(fileType)) {
 945                 return true;
 946             }
 947         }
 948         return false;
 949     }
 950 
 951 
 952     /**
 953      * Obtains the set of MIDI file types that the system can write from the
 954      * sequence specified.
 955      * @param sequence the sequence for which MIDI file type support
 956      * is queried
 957      * @return the set of unique supported file types.  If no file types are supported,
 958      * returns an array of length 0.
 959      */
 960     public static int[] getMidiFileTypes(Sequence sequence) {
 961 
 962         List providers = getMidiFileWriters();
 963         Set allTypes = new HashSet();
 964 
 965         // gather from all the providers
 966 
 967         for (int i = 0; i < providers.size(); i++ ) {
 968             MidiFileWriter writer = (MidiFileWriter) providers.get(i);
 969             int[] types = writer.getMidiFileTypes(sequence);
 970             for (int j = 0; j < types.length; j++ ) {
 971                 allTypes.add(new Integer(types[j]));
 972             }
 973         }
 974         int resultTypes[] = new int[allTypes.size()];
 975         int index = 0;
 976         Iterator iterator = allTypes.iterator();
 977         while (iterator.hasNext()) {
 978             Integer integer = (Integer) iterator.next();
 979             resultTypes[index++] = integer.intValue();
 980         }
 981         return resultTypes;
 982     }
 983 
 984 
 985     /**
 986      * Indicates whether a MIDI file of the file type specified can be written
 987      * from the sequence indicated.
 988      * @param fileType the file type for which write capabilities
 989      * are queried
 990      * @param sequence the sequence for which file writing support is queried
 991      * @return <code>true</code> if the file type is supported for this
 992      * sequence, otherwise <code>false</code>
 993      */
 994     public static boolean isFileTypeSupported(int fileType, Sequence sequence) {
 995 
 996         List providers = getMidiFileWriters();
 997 
 998         for (int i = 0; i < providers.size(); i++ ) {
 999             MidiFileWriter writer = (MidiFileWriter) providers.get(i);
1000             if( writer.isFileTypeSupported(fileType,sequence)) {
1001                 return true;
1002             }
1003         }
1004         return false;
1005     }
1006 
1007 
1008     /**
1009      * Writes a stream of bytes representing a file of the MIDI file type
1010      * indicated to the output stream provided.
1011      * @param in sequence containing MIDI data to be written to the file
1012      * @param fileType the file type of the file to be written to the output stream
1013      * @param out stream to which the file data should be written
1014      * @return the number of bytes written to the output stream
1015      * @throws IOException if an I/O exception occurs
1016      * @throws IllegalArgumentException if the file format is not supported by
1017      * the system
1018      * @see #isFileTypeSupported(int, Sequence)
1019      * @see     #getMidiFileTypes(Sequence)
1020      */
1021     public static int write(Sequence in, int fileType, OutputStream out) throws IOException {
1022 
1023         List providers = getMidiFileWriters();
1024         //$$fb 2002-04-17: Fix for 4635287: Standard MidiFileWriter cannot write empty Sequences
1025         int bytesWritten = -2;
1026 
1027         for (int i = 0; i < providers.size(); i++ ) {
1028             MidiFileWriter writer = (MidiFileWriter) providers.get(i);
1029             if( writer.isFileTypeSupported( fileType, in ) ) {
1030 
1031                 bytesWritten = writer.write(in, fileType, out);
1032                 break;
1033             }
1034         }
1035         if (bytesWritten == -2) {
1036             throw new IllegalArgumentException("MIDI file type is not supported");
1037         }
1038         return bytesWritten;
1039     }
1040 
1041 
1042     /**
1043      * Writes a stream of bytes representing a file of the MIDI file type
1044      * indicated to the external file provided.
1045      * @param in sequence containing MIDI data to be written to the file
1046      * @param type the file type of the file to be written to the output stream
1047      * @param out external file to which the file data should be written
1048      * @return the number of bytes written to the file
1049      * @throws IOException if an I/O exception occurs
1050      * @throws IllegalArgumentException if the file type is not supported by
1051      * the system
1052      * @see #isFileTypeSupported(int, Sequence)
1053      * @see     #getMidiFileTypes(Sequence)
1054      */
1055     public static int write(Sequence in, int type, File out) throws IOException {
1056 
1057         List providers = getMidiFileWriters();
1058         //$$fb 2002-04-17: Fix for 4635287: Standard MidiFileWriter cannot write empty Sequences
1059         int bytesWritten = -2;
1060 
1061         for (int i = 0; i < providers.size(); i++ ) {
1062             MidiFileWriter writer = (MidiFileWriter) providers.get(i);
1063             if( writer.isFileTypeSupported( type, in ) ) {
1064 
1065                 bytesWritten = writer.write(in, type, out);
1066                 break;
1067             }
1068         }
1069         if (bytesWritten == -2) {
1070             throw new IllegalArgumentException("MIDI file type is not supported");
1071         }
1072         return bytesWritten;
1073     }
1074 
1075 
1076 
1077     // HELPER METHODS
1078 
1079     private static List getMidiDeviceProviders() {
1080         return getProviders(MidiDeviceProvider.class);
1081     }
1082 
1083 
1084     private static List getSoundbankReaders() {
1085         return getProviders(SoundbankReader.class);
1086     }
1087 
1088 
1089     private static List getMidiFileWriters() {
1090         return getProviders(MidiFileWriter.class);
1091     }
1092 
1093 
1094     private static List getMidiFileReaders() {
1095         return getProviders(MidiFileReader.class);
1096     }
1097 
1098 
1099     /** Attempts to locate and return a default MidiDevice of the specified
1100      * type.
1101      *
1102      * This method wraps {@link #getDefaultDevice}. It catches the
1103      * <code>IllegalArgumentException</code> thrown by
1104      * <code>getDefaultDevice</code> and instead throws a
1105      * <code>MidiUnavailableException</code>, with the catched
1106      * exception chained.
1107      *
1108      * @param deviceClass The requested device type, one of Synthesizer.class,
1109      * Sequencer.class, Receiver.class or Transmitter.class.
1110      * @throws  MidiUnavalableException on failure.
1111      */
1112     private static MidiDevice getDefaultDeviceWrapper(Class deviceClass)
1113         throws MidiUnavailableException{
1114         try {
1115             return getDefaultDevice(deviceClass);
1116         } catch (IllegalArgumentException iae) {
1117             MidiUnavailableException mae = new MidiUnavailableException();
1118             mae.initCause(iae);
1119             throw mae;
1120         }
1121     }
1122 
1123 
1124     /** Attempts to locate and return a default MidiDevice of the specified
1125      * type.
1126      *
1127      * @param deviceClass The requested device type, one of Synthesizer.class,
1128      * Sequencer.class, Receiver.class or Transmitter.class.
1129      * @throws  IllegalArgumentException on failure.
1130      */
1131     private static MidiDevice getDefaultDevice(Class deviceClass) {
1132         List providers = getMidiDeviceProviders();
1133         String providerClassName = JDK13Services.getDefaultProviderClassName(deviceClass);
1134         String instanceName = JDK13Services.getDefaultInstanceName(deviceClass);
1135         MidiDevice device;
1136 
1137         if (providerClassName != null) {
1138             MidiDeviceProvider defaultProvider = getNamedProvider(providerClassName, providers);
1139             if (defaultProvider != null) {
1140                 if (instanceName != null) {
1141                     device = getNamedDevice(instanceName, defaultProvider, deviceClass);
1142                     if (device != null) {
1143                         return device;
1144                     }
1145                 }
1146                 device = getFirstDevice(defaultProvider, deviceClass);
1147                 if (device != null) {
1148                     return device;
1149                 }
1150             }
1151         }
1152 


1162 
1163         /* No default are specified, or if something is specified, everything
1164            failed. */
1165         device = getFirstDevice(providers, deviceClass);
1166         if (device != null) {
1167             return device;
1168         }
1169         throw new IllegalArgumentException("Requested device not installed");
1170     }
1171 
1172 
1173 
1174     /** Return a MidiDeviceProcider of a given class from the list of
1175         MidiDeviceProviders.
1176 
1177         @param providerClassName The class name of the provider to be returned.
1178         @param provider The list of MidiDeviceProviders that is searched.
1179         @return A MidiDeviceProvider of the requested class, or null if none
1180         is found.
1181     */
1182     private static MidiDeviceProvider getNamedProvider(String providerClassName, List providers) {

1183         for(int i = 0; i < providers.size(); i++) {
1184             MidiDeviceProvider provider = (MidiDeviceProvider) providers.get(i);
1185             if (provider.getClass().getName().equals(providerClassName)) {
1186                 return provider;
1187             }
1188         }
1189         return null;
1190     }
1191 
1192 
1193     /** Return a MidiDevice with a given name from a given MidiDeviceProvider.
1194         @param deviceName The name of the MidiDevice to be returned.
1195         @param provider The MidiDeviceProvider to check for MidiDevices.
1196         @param deviceClass The requested device type, one of Synthesizer.class,
1197         Sequencer.class, Receiver.class or Transmitter.class.
1198 
1199         @return A MidiDevice matching the requirements, or null if none is found.
1200     */
1201     private static MidiDevice getNamedDevice(String deviceName,
1202                                              MidiDeviceProvider provider,
1203                                              Class deviceClass) {
1204         MidiDevice device;
1205         // try to get MIDI port
1206         device = getNamedDevice(deviceName, provider, deviceClass,
1207                                  false, false);
1208         if (device != null) {
1209             return device;
1210         }
1211 
1212         if (deviceClass == Receiver.class) {
1213             // try to get Synthesizer
1214             device = getNamedDevice(deviceName, provider, deviceClass,
1215                                      true, false);
1216             if (device != null) {
1217                 return device;
1218             }
1219         }
1220 
1221         return null;
1222     }
1223 
1224 
1225     /** Return a MidiDevice with a given name from a given MidiDeviceProvider.
1226       @param deviceName The name of the MidiDevice to be returned.
1227       @param provider The MidiDeviceProvider to check for MidiDevices.
1228       @param deviceClass The requested device type, one of Synthesizer.class,
1229       Sequencer.class, Receiver.class or Transmitter.class.
1230 
1231       @return A MidiDevice matching the requirements, or null if none is found.
1232      */
1233     private static MidiDevice getNamedDevice(String deviceName,
1234                                              MidiDeviceProvider provider,
1235                                              Class deviceClass,
1236                                              boolean allowSynthesizer,
1237                                              boolean allowSequencer) {
1238         MidiDevice.Info[] infos = provider.getDeviceInfo();
1239         for (int i = 0; i < infos.length; i++) {
1240             if (infos[i].getName().equals(deviceName)) {
1241                 MidiDevice device = provider.getDevice(infos[i]);
1242                 if (isAppropriateDevice(device, deviceClass,
1243                                         allowSynthesizer, allowSequencer)) {
1244                     return device;
1245                 }
1246             }
1247         }
1248         return null;
1249     }
1250 
1251 
1252     /** Return a MidiDevice with a given name from a list of
1253         MidiDeviceProviders.
1254         @param deviceName The name of the MidiDevice to be returned.
1255         @param providers The List of MidiDeviceProviders to check for
1256         MidiDevices.
1257         @param deviceClass The requested device type, one of Synthesizer.class,
1258         Sequencer.class, Receiver.class or Transmitter.class.
1259         @return A Mixer matching the requirements, or null if none is found.
1260     */
1261     private static MidiDevice getNamedDevice(String deviceName,
1262                                              List providers,
1263                                              Class deviceClass) {
1264         MidiDevice device;
1265         // try to get MIDI port
1266         device = getNamedDevice(deviceName, providers, deviceClass,
1267                                  false, false);
1268         if (device != null) {
1269             return device;
1270         }
1271 
1272         if (deviceClass == Receiver.class) {
1273             // try to get Synthesizer
1274             device = getNamedDevice(deviceName, providers, deviceClass,
1275                                      true, false);
1276             if (device != null) {
1277                 return device;
1278             }
1279         }
1280 
1281         return null;
1282     }
1283 
1284 
1285     /** Return a MidiDevice with a given name from a list of
1286         MidiDeviceProviders.
1287         @param deviceName The name of the MidiDevice to be returned.
1288         @param providers The List of MidiDeviceProviders to check for
1289         MidiDevices.
1290         @param deviceClass The requested device type, one of Synthesizer.class,
1291         Sequencer.class, Receiver.class or Transmitter.class.
1292         @return A Mixer matching the requirements, or null if none is found.
1293      */
1294     private static MidiDevice getNamedDevice(String deviceName,
1295                                              List providers,
1296                                              Class deviceClass,
1297                                              boolean allowSynthesizer,
1298                                              boolean allowSequencer) {
1299         for(int i = 0; i < providers.size(); i++) {
1300             MidiDeviceProvider provider = (MidiDeviceProvider) providers.get(i);
1301             MidiDevice device = getNamedDevice(deviceName, provider,
1302                                                deviceClass,
1303                                                allowSynthesizer,
1304                                                allowSequencer);
1305             if (device != null) {
1306                 return device;
1307             }
1308         }
1309         return null;
1310     }
1311 
1312 
1313     /** From a given MidiDeviceProvider, return the first appropriate device.
1314         @param provider The MidiDeviceProvider to check for MidiDevices.
1315         @param deviceClass The requested device type, one of Synthesizer.class,
1316         Sequencer.class, Receiver.class or Transmitter.class.
1317         @return A MidiDevice is considered appropriate, or null if no
1318         appropriate device is found.
1319     */
1320     private static MidiDevice getFirstDevice(MidiDeviceProvider provider,
1321                                              Class deviceClass) {
1322         MidiDevice device;
1323         // try to get MIDI port
1324         device = getFirstDevice(provider, deviceClass,
1325                                 false, false);
1326         if (device != null) {
1327             return device;
1328         }
1329 
1330         if (deviceClass == Receiver.class) {
1331             // try to get Synthesizer
1332             device = getFirstDevice(provider, deviceClass,
1333                                     true, false);
1334             if (device != null) {
1335                 return device;
1336             }
1337         }
1338 
1339         return null;
1340     }
1341 
1342 
1343     /** From a given MidiDeviceProvider, return the first appropriate device.
1344         @param provider The MidiDeviceProvider to check for MidiDevices.
1345         @param deviceClass The requested device type, one of Synthesizer.class,
1346         Sequencer.class, Receiver.class or Transmitter.class.
1347         @return A MidiDevice is considered appropriate, or null if no
1348         appropriate device is found.
1349      */
1350     private static MidiDevice getFirstDevice(MidiDeviceProvider provider,
1351                                              Class deviceClass,
1352                                              boolean allowSynthesizer,
1353                                              boolean allowSequencer) {
1354         MidiDevice.Info[] infos = provider.getDeviceInfo();
1355         for (int j = 0; j < infos.length; j++) {
1356             MidiDevice device = provider.getDevice(infos[j]);
1357             if (isAppropriateDevice(device, deviceClass,
1358                                     allowSynthesizer, allowSequencer)) {
1359                 return device;
1360             }
1361         }
1362         return null;
1363     }
1364 
1365 
1366     /** From a List of MidiDeviceProviders, return the first appropriate
1367         MidiDevice.
1368         @param providers The List of MidiDeviceProviders to search.
1369         @param deviceClass The requested device type, one of Synthesizer.class,
1370         Sequencer.class, Receiver.class or Transmitter.class.
1371         @return A MidiDevice that is considered appropriate, or null
1372         if none is found.
1373     */
1374     private static MidiDevice getFirstDevice(List providers,
1375                                              Class deviceClass) {
1376         MidiDevice device;
1377         // try to get MIDI port
1378         device = getFirstDevice(providers, deviceClass,
1379                                 false, false);
1380         if (device != null) {
1381             return device;
1382         }
1383 
1384         if (deviceClass == Receiver.class) {
1385             // try to get Synthesizer
1386             device = getFirstDevice(providers, deviceClass,
1387                                     true, false);
1388             if (device != null) {
1389                 return device;
1390             }
1391         }
1392 
1393         return null;
1394     }
1395 
1396 
1397     /** From a List of MidiDeviceProviders, return the first appropriate
1398         MidiDevice.
1399         @param providers The List of MidiDeviceProviders to search.
1400         @param deviceClass The requested device type, one of Synthesizer.class,
1401         Sequencer.class, Receiver.class or Transmitter.class.
1402         @return A MidiDevice that is considered appropriate, or null
1403         if none is found.
1404      */
1405     private static MidiDevice getFirstDevice(List providers,
1406                                              Class deviceClass,
1407                                              boolean allowSynthesizer,
1408                                              boolean allowSequencer) {
1409         for(int i = 0; i < providers.size(); i++) {
1410             MidiDeviceProvider provider = (MidiDeviceProvider) providers.get(i);
1411             MidiDevice device = getFirstDevice(provider, deviceClass,
1412                                                allowSynthesizer,
1413                                                allowSequencer);
1414             if (device != null) {
1415                 return device;
1416             }
1417         }
1418         return null;
1419     }
1420 
1421 
1422     /** Checks if a MidiDevice is appropriate.
1423         If deviceClass is Synthesizer or Sequencer, a device implementing
1424         the respective interface is considered appropriate. If deviceClass
1425         is Receiver or Transmitter, a device is considered appropriate if
1426         it implements neither Synthesizer nor Transmitter, and if it can
1427         provide at least one Receiver or Transmitter, respectively.
1428 
1429         @param device the MidiDevice to test
1430         @param allowSynthesizer if true, Synthesizers are considered
1431         appropriate. Otherwise only pure MidiDevices are considered
1432         appropriate (unless allowSequencer 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         @param allowSequencer if true, Sequencers are considered
1436         appropriate. Otherwise only pure MidiDevices are considered
1437         appropriate (unless allowSynthesizer is true). This flag only has an
1438         effect for deviceClass Receiver and Transmitter. For other device
1439         classes (Sequencer and Synthesizer), this flag has no effect.
1440         @return true if the device is considered appropriate according to the
1441         rules given above, false otherwise.
1442     */
1443     private static boolean isAppropriateDevice(MidiDevice device,
1444                                                Class deviceClass,
1445                                                boolean allowSynthesizer,
1446                                                boolean allowSequencer) {
1447         if (deviceClass.isInstance(device)) {
1448             // This clause is for deviceClass being either Synthesizer
1449             // or Sequencer.
1450             return true;
1451         } else {
1452             // Now the case that deviceClass is Transmitter or
1453             // Receiver. If neither allowSynthesizer nor allowSequencer is
1454             // true, we require device instances to be
1455             // neither Synthesizer nor Sequencer, since we only want
1456             // devices representing MIDI ports.
1457             // Otherwise, the respective type is accepted, too
1458             if ( (! (device instanceof Sequencer) &&
1459                   ! (device instanceof Synthesizer) ) ||
1460                  ((device instanceof Sequencer) && allowSequencer) ||
1461                  ((device instanceof Synthesizer) && allowSynthesizer)) {
1462                 // And of cource, the device has to be able to provide
1463                 // Receivers or Transmitters.
1464                 if ((deviceClass == Receiver.class &&
1465                      device.getMaxReceivers() != 0) ||
1466                     (deviceClass == Transmitter.class &&
1467                      device.getMaxTransmitters() != 0)) {
1468                     return true;
1469                 }
1470             }
1471         }
1472         return false;
1473     }
1474 
1475 
1476     /**
1477      * Obtains the set of services currently installed on the system
1478      * using the SPI mechanism in 1.3.
1479      * @return a List of instances of providers for the requested service.
1480      * If no providers are available, a List of length 0 will be returned.
1481      */
1482     private static List getProviders(Class providerClass) {
1483         return JDK13Services.getProviders(providerClass);
1484     }
1485 }


 170 
 171     /**
 172      * Private no-args constructor for ensuring against instantiation.
 173      */
 174     private MidiSystem() {
 175     }
 176 
 177 
 178     /**
 179      * Obtains an array of information objects representing
 180      * the set of all MIDI devices available on the system.
 181      * A returned information object can then be used to obtain the
 182      * corresponding device object, by invoking
 183      * {@link #getMidiDevice(MidiDevice.Info) getMidiDevice}.
 184      *
 185      * @return an array of <code>MidiDevice.Info</code> objects, one
 186      * for each installed MIDI device.  If no such devices are installed,
 187      * an array of length 0 is returned.
 188      */
 189     public static MidiDevice.Info[] getMidiDeviceInfo() {
 190         List<MidiDevice.Info> allInfos = new ArrayList<>();
 191         List<MidiDeviceProvider> providers = getMidiDeviceProviders();
 192 
 193         for(int i = 0; i < providers.size(); i++) {
 194             MidiDeviceProvider provider = providers.get(i);
 195             MidiDevice.Info[] tmpinfo = provider.getDeviceInfo();
 196             for (int j = 0; j < tmpinfo.length; j++) {
 197                 allInfos.add( tmpinfo[j] );
 198             }
 199         }
 200         MidiDevice.Info[] infosArray = allInfos.toArray(new MidiDevice.Info[0]);
 201         return infosArray;
 202     }
 203 
 204 
 205     /**
 206      * Obtains the requested MIDI device.
 207      *
 208      * @param info a device information object representing the desired device.
 209      * @return the requested device
 210      * @throws MidiUnavailableException if the requested device is not available
 211      * due to resource restrictions
 212      * @throws IllegalArgumentException if the info object does not represent
 213      * a MIDI device installed on the system
 214      * @see #getMidiDeviceInfo
 215      */
 216     public static MidiDevice getMidiDevice(MidiDevice.Info info) throws MidiUnavailableException {
 217         List<MidiDeviceProvider> providers = getMidiDeviceProviders();
 218 
 219         for(int i = 0; i < providers.size(); i++) {
 220             MidiDeviceProvider provider = providers.get(i);
 221             if (provider.isDeviceSupported(info)) {
 222                 MidiDevice device = provider.getDevice(info);
 223                 return device;
 224             }
 225         }
 226         throw new IllegalArgumentException("Requested device not installed: " + info);
 227     }
 228 
 229 
 230     /**
 231      * Obtains a MIDI receiver from an external MIDI port
 232      * or other default device.
 233      * The returned receiver always implements
 234      * the {@code MidiDeviceReceiver} interface.
 235      *
 236      * <p>If the system property
 237      * <code>javax.sound.midi.Receiver</code>
 238      * is defined or it is defined in the file &quot;sound.properties&quot;,
 239      * it is used to identify the device that provides the default receiver.
 240      * For details, refer to the {@link MidiSystem class description}.


 511      * need to read some data from the stream before determining whether they
 512      * support it.  These parsers must
 513      * be able to mark the stream, read enough data to determine whether they
 514      * support the stream, and, if not, reset the stream's read pointer to
 515      * its original position.  If the input stream does not support this,
 516      * this method may fail with an IOException.
 517      * @param stream the source of the sound bank data.
 518      * @return the sound bank
 519      * @throws InvalidMidiDataException if the stream does not point to
 520      * valid MIDI soundbank data recognized by the system
 521      * @throws IOException if an I/O error occurred when loading the soundbank
 522      * @see InputStream#markSupported
 523      * @see InputStream#mark
 524      */
 525     public static Soundbank getSoundbank(InputStream stream)
 526         throws InvalidMidiDataException, IOException {
 527 
 528         SoundbankReader sp = null;
 529         Soundbank s = null;
 530 
 531         List<SoundbankReader> providers = getSoundbankReaders();
 532 
 533         for(int i = 0; i < providers.size(); i++) {
 534             sp = providers.get(i);
 535             s = sp.getSoundbank(stream);
 536 
 537             if( s!= null) {
 538                 return s;
 539             }
 540         }
 541         throw new InvalidMidiDataException("cannot get soundbank from stream");
 542 
 543     }
 544 
 545 
 546     /**
 547      * Constructs a <code>Soundbank</code> by reading it from the specified URL.
 548      * The URL must point to a valid MIDI soundbank file.
 549      *
 550      * @param url the source of the sound bank data
 551      * @return the sound bank
 552      * @throws InvalidMidiDataException if the URL does not point to valid MIDI
 553      * soundbank data recognized by the system
 554      * @throws IOException if an I/O error occurred when loading the soundbank
 555      */
 556     public static Soundbank getSoundbank(URL url)
 557         throws InvalidMidiDataException, IOException {
 558 
 559         SoundbankReader sp = null;
 560         Soundbank s = null;
 561 
 562         List<SoundbankReader> providers = getSoundbankReaders();
 563 
 564         for(int i = 0; i < providers.size(); i++) {
 565             sp = providers.get(i);
 566             s = sp.getSoundbank(url);
 567 
 568             if( s!= null) {
 569                 return s;
 570             }
 571         }
 572         throw new InvalidMidiDataException("cannot get soundbank from stream");
 573 
 574     }
 575 
 576 
 577     /**
 578      * Constructs a <code>Soundbank</code> by reading it from the specified
 579      * <code>File</code>.
 580      * The <code>File</code> must point to a valid MIDI soundbank file.
 581      *
 582      * @param file the source of the sound bank data
 583      * @return the sound bank
 584      * @throws InvalidMidiDataException if the <code>File</code> does not
 585      * point to valid MIDI soundbank data recognized by the system
 586      * @throws IOException if an I/O error occurred when loading the soundbank
 587      */
 588     public static Soundbank getSoundbank(File file)
 589         throws InvalidMidiDataException, IOException {
 590 
 591         SoundbankReader sp = null;
 592         Soundbank s = null;
 593 
 594         List<SoundbankReader> providers = getSoundbankReaders();
 595 
 596         for(int i = 0; i < providers.size(); i++) {
 597             sp = providers.get(i);
 598             s = sp.getSoundbank(file);
 599 
 600             if( s!= null) {
 601                 return s;
 602             }
 603         }
 604         throw new InvalidMidiDataException("cannot get soundbank from stream");
 605     }
 606 
 607 
 608 
 609     /**
 610      * Obtains the MIDI file format of the data in the specified input stream.
 611      * The stream must point to valid MIDI file data for a file type recognized
 612      * by the system.
 613      * <p>
 614      * This method and/or the code it invokes may need to read some data from
 615      * the stream to determine whether its data format is supported.  The
 616      * implementation may therefore
 617      * need to mark the stream, read enough data to determine whether it is in


 624      * even for valid files if no compatible file reader is installed.  It
 625      * will also fail with an InvalidMidiDataException if a compatible file reader
 626      * is installed, but encounters errors while determining the file format.
 627      *
 628      * @param stream the input stream from which file format information
 629      * should be extracted
 630      * @return an <code>MidiFileFormat</code> object describing the MIDI file
 631      * format
 632      * @throws InvalidMidiDataException if the stream does not point to valid
 633      * MIDI file data recognized by the system
 634      * @throws IOException if an I/O exception occurs while accessing the
 635      * stream
 636      * @see #getMidiFileFormat(URL)
 637      * @see #getMidiFileFormat(File)
 638      * @see InputStream#markSupported
 639      * @see InputStream#mark
 640      */
 641     public static MidiFileFormat getMidiFileFormat(InputStream stream)
 642         throws InvalidMidiDataException, IOException {
 643 
 644         List<MidiFileReader> providers = getMidiFileReaders();
 645         MidiFileFormat format = null;
 646 
 647         for(int i = 0; i < providers.size(); i++) {
 648             MidiFileReader reader =  providers.get(i);
 649             try {
 650                 format = reader.getMidiFileFormat( stream ); // throws IOException
 651                 break;
 652             } catch (InvalidMidiDataException e) {
 653                 continue;
 654             }
 655         }
 656 
 657         if( format==null ) {
 658             throw new InvalidMidiDataException("input stream is not a supported file type");
 659         } else {
 660             return format;
 661         }
 662     }
 663 
 664 
 665     /**
 666      * Obtains the MIDI file format of the data in the specified URL.  The URL
 667      * must point to valid MIDI file data for a file type recognized
 668      * by the system.


 670      * This operation can only succeed for files of a type which can be parsed
 671      * by an installed file reader.  It may fail with an InvalidMidiDataException
 672      * even for valid files if no compatible file reader is installed.  It
 673      * will also fail with an InvalidMidiDataException if a compatible file reader
 674      * is installed, but encounters errors while determining the file format.
 675      *
 676      * @param url the URL from which file format information should be
 677      * extracted
 678      * @return a <code>MidiFileFormat</code> object describing the MIDI file
 679      * format
 680      * @throws InvalidMidiDataException if the URL does not point to valid MIDI
 681      * file data recognized by the system
 682      * @throws IOException if an I/O exception occurs while accessing the URL
 683      *
 684      * @see #getMidiFileFormat(InputStream)
 685      * @see #getMidiFileFormat(File)
 686      */
 687     public static MidiFileFormat getMidiFileFormat(URL url)
 688         throws InvalidMidiDataException, IOException {
 689 
 690         List<MidiFileReader> providers = getMidiFileReaders();
 691         MidiFileFormat format = null;
 692 
 693         for(int i = 0; i < providers.size(); i++) {
 694             MidiFileReader reader = providers.get(i);
 695             try {
 696                 format = reader.getMidiFileFormat( url ); // throws IOException
 697                 break;
 698             } catch (InvalidMidiDataException e) {
 699                 continue;
 700             }
 701         }
 702 
 703         if( format==null ) {
 704             throw new InvalidMidiDataException("url is not a supported file type");
 705         } else {
 706             return format;
 707         }
 708     }
 709 
 710 
 711     /**
 712      * Obtains the MIDI file format of the specified <code>File</code>.  The
 713      * <code>File</code> must point to valid MIDI file data for a file type
 714      * recognized by the system.


 716      * This operation can only succeed for files of a type which can be parsed
 717      * by an installed file reader.  It may fail with an InvalidMidiDataException
 718      * even for valid files if no compatible file reader is installed.  It
 719      * will also fail with an InvalidMidiDataException if a compatible file reader
 720      * is installed, but encounters errors while determining the file format.
 721      *
 722      * @param file the <code>File</code> from which file format information
 723      * should be extracted
 724      * @return a <code>MidiFileFormat</code> object describing the MIDI file
 725      * format
 726      * @throws InvalidMidiDataException if the <code>File</code> does not point
 727      *  to valid MIDI file data recognized by the system
 728      * @throws IOException if an I/O exception occurs while accessing the file
 729      *
 730      * @see #getMidiFileFormat(InputStream)
 731      * @see #getMidiFileFormat(URL)
 732      */
 733     public static MidiFileFormat getMidiFileFormat(File file)
 734         throws InvalidMidiDataException, IOException {
 735 
 736         List<MidiFileReader> providers = getMidiFileReaders();
 737         MidiFileFormat format = null;
 738 
 739         for(int i = 0; i < providers.size(); i++) {
 740             MidiFileReader reader = providers.get(i);
 741             try {
 742                 format = reader.getMidiFileFormat( file ); // throws IOException
 743                 break;
 744             } catch (InvalidMidiDataException e) {
 745                 continue;
 746             }
 747         }
 748 
 749         if( format==null ) {
 750             throw new InvalidMidiDataException("file is not a supported file type");
 751         } else {
 752             return format;
 753         }
 754     }
 755 
 756 
 757     /**
 758      * Obtains a MIDI sequence from the specified input stream.  The stream must
 759      * point to valid MIDI file data for a file type recognized
 760      * by the system.


 771      * by an installed file reader.  It may fail with an InvalidMidiDataException
 772      * even for valid files if no compatible file reader is installed.  It
 773      * will also fail with an InvalidMidiDataException if a compatible file reader
 774      * is installed, but encounters errors while constructing the <code>Sequence</code>
 775      * object from the file data.
 776      *
 777      * @param stream the input stream from which the <code>Sequence</code>
 778      * should be constructed
 779      * @return a <code>Sequence</code> object based on the MIDI file data
 780      * contained in the input stream
 781      * @throws InvalidMidiDataException if the stream does not point to
 782      * valid MIDI file data recognized by the system
 783      * @throws IOException if an I/O exception occurs while accessing the
 784      * stream
 785      * @see InputStream#markSupported
 786      * @see InputStream#mark
 787      */
 788     public static Sequence getSequence(InputStream stream)
 789         throws InvalidMidiDataException, IOException {
 790 
 791         List<MidiFileReader> providers = getMidiFileReaders();
 792         Sequence sequence = null;
 793 
 794         for(int i = 0; i < providers.size(); i++) {
 795             MidiFileReader reader = providers.get(i);
 796             try {
 797                 sequence = reader.getSequence( stream ); // throws IOException
 798                 break;
 799             } catch (InvalidMidiDataException e) {
 800                 continue;
 801             }
 802         }
 803 
 804         if( sequence==null ) {
 805             throw new InvalidMidiDataException("could not get sequence from input stream");
 806         } else {
 807             return sequence;
 808         }
 809     }
 810 
 811 
 812     /**
 813      * Obtains a MIDI sequence from the specified URL.  The URL must
 814      * point to valid MIDI file data for a file type recognized
 815      * by the system.
 816      * <p>
 817      * This operation can only succeed for files of a type which can be parsed
 818      * by an installed file reader.  It may fail with an InvalidMidiDataException
 819      * even for valid files if no compatible file reader is installed.  It
 820      * will also fail with an InvalidMidiDataException if a compatible file reader
 821      * is installed, but encounters errors while constructing the <code>Sequence</code>
 822      * object from the file data.
 823      *
 824      * @param url the URL from which the <code>Sequence</code> should be
 825      * constructed
 826      * @return a <code>Sequence</code> object based on the MIDI file data
 827      * pointed to by the URL
 828      * @throws InvalidMidiDataException if the URL does not point to valid MIDI
 829      * file data recognized by the system
 830      * @throws IOException if an I/O exception occurs while accessing the URL
 831      */
 832     public static Sequence getSequence(URL url)
 833         throws InvalidMidiDataException, IOException {
 834 
 835         List<MidiFileReader> providers = getMidiFileReaders();
 836         Sequence sequence = null;
 837 
 838         for(int i = 0; i < providers.size(); i++) {
 839             MidiFileReader reader = providers.get(i);
 840             try {
 841                 sequence = reader.getSequence( url ); // throws IOException
 842                 break;
 843             } catch (InvalidMidiDataException e) {
 844                 continue;
 845             }
 846         }
 847 
 848         if( sequence==null ) {
 849             throw new InvalidMidiDataException("could not get sequence from URL");
 850         } else {
 851             return sequence;
 852         }
 853     }
 854 
 855 
 856     /**
 857      * Obtains a MIDI sequence from the specified <code>File</code>.
 858      * The <code>File</code> must point to valid MIDI file data
 859      * for a file type recognized by the system.
 860      * <p>
 861      * This operation can only succeed for files of a type which can be parsed
 862      * by an installed file reader.  It may fail with an InvalidMidiDataException
 863      * even for valid files if no compatible file reader is installed.  It
 864      * will also fail with an InvalidMidiDataException if a compatible file reader
 865      * is installed, but encounters errors while constructing the <code>Sequence</code>
 866      * object from the file data.
 867      *
 868      * @param file the <code>File</code> from which the <code>Sequence</code>
 869      * should be constructed
 870      * @return a <code>Sequence</code> object based on the MIDI file data
 871      * pointed to by the File
 872      * @throws InvalidMidiDataException if the File does not point to valid MIDI
 873      * file data recognized by the system
 874      * @throws IOException if an I/O exception occurs
 875      */
 876     public static Sequence getSequence(File file)
 877         throws InvalidMidiDataException, IOException {
 878 
 879         List<MidiFileReader> providers = getMidiFileReaders();
 880         Sequence sequence = null;
 881 
 882         for(int i = 0; i < providers.size(); i++) {
 883             MidiFileReader reader = providers.get(i);
 884             try {
 885                 sequence = reader.getSequence( file ); // throws IOException
 886                 break;
 887             } catch (InvalidMidiDataException e) {
 888                 continue;
 889             }
 890         }
 891 
 892         if( sequence==null ) {
 893             throw new InvalidMidiDataException("could not get sequence from file");
 894         } else {
 895             return sequence;
 896         }
 897     }
 898 
 899 
 900     /**
 901      * Obtains the set of MIDI file types for which file writing support is
 902      * provided by the system.
 903      * @return array of unique file types.  If no file types are supported,
 904      * an array of length 0 is returned.
 905      */
 906     public static int[] getMidiFileTypes() {
 907 
 908         List<MidiFileWriter> providers = getMidiFileWriters();
 909         Set<Integer> allTypes = new HashSet<>();
 910 
 911         // gather from all the providers
 912 
 913         for (int i = 0; i < providers.size(); i++ ) {
 914             MidiFileWriter writer = providers.get(i);
 915             int[] types = writer.getMidiFileTypes();
 916             for (int j = 0; j < types.length; j++ ) {
 917                 allTypes.add(new Integer(types[j]));
 918             }
 919         }
 920         int resultTypes[] = new int[allTypes.size()];
 921         int index = 0;
 922         Iterator<Integer> iterator = allTypes.iterator();
 923         while (iterator.hasNext()) {
 924             Integer integer = iterator.next();
 925             resultTypes[index++] = integer.intValue();
 926         }
 927         return resultTypes;
 928     }
 929 
 930 
 931     /**
 932      * Indicates whether file writing support for the specified MIDI file type
 933      * is provided by the system.
 934      * @param fileType the file type for which write capabilities are queried
 935      * @return <code>true</code> if the file type is supported,
 936      * otherwise <code>false</code>
 937      */
 938     public static boolean isFileTypeSupported(int fileType) {
 939 
 940         List<MidiFileWriter> providers = getMidiFileWriters();
 941 
 942         for (int i = 0; i < providers.size(); i++ ) {
 943             MidiFileWriter writer = providers.get(i);
 944             if( writer.isFileTypeSupported(fileType)) {
 945                 return true;
 946             }
 947         }
 948         return false;
 949     }
 950 
 951 
 952     /**
 953      * Obtains the set of MIDI file types that the system can write from the
 954      * sequence specified.
 955      * @param sequence the sequence for which MIDI file type support
 956      * is queried
 957      * @return the set of unique supported file types.  If no file types are supported,
 958      * returns an array of length 0.
 959      */
 960     public static int[] getMidiFileTypes(Sequence sequence) {
 961 
 962         List<MidiFileWriter> providers = getMidiFileWriters();
 963         Set<Integer> allTypes = new HashSet<>();
 964 
 965         // gather from all the providers
 966 
 967         for (int i = 0; i < providers.size(); i++ ) {
 968             MidiFileWriter writer = providers.get(i);
 969             int[] types = writer.getMidiFileTypes(sequence);
 970             for (int j = 0; j < types.length; j++ ) {
 971                 allTypes.add(new Integer(types[j]));
 972             }
 973         }
 974         int resultTypes[] = new int[allTypes.size()];
 975         int index = 0;
 976         Iterator<Integer> iterator = allTypes.iterator();
 977         while (iterator.hasNext()) {
 978             Integer integer = iterator.next();
 979             resultTypes[index++] = integer.intValue();
 980         }
 981         return resultTypes;
 982     }
 983 
 984 
 985     /**
 986      * Indicates whether a MIDI file of the file type specified can be written
 987      * from the sequence indicated.
 988      * @param fileType the file type for which write capabilities
 989      * are queried
 990      * @param sequence the sequence for which file writing support is queried
 991      * @return <code>true</code> if the file type is supported for this
 992      * sequence, otherwise <code>false</code>
 993      */
 994     public static boolean isFileTypeSupported(int fileType, Sequence sequence) {
 995 
 996         List<MidiFileWriter> providers = getMidiFileWriters();
 997 
 998         for (int i = 0; i < providers.size(); i++ ) {
 999             MidiFileWriter writer = providers.get(i);
1000             if( writer.isFileTypeSupported(fileType,sequence)) {
1001                 return true;
1002             }
1003         }
1004         return false;
1005     }
1006 
1007 
1008     /**
1009      * Writes a stream of bytes representing a file of the MIDI file type
1010      * indicated to the output stream provided.
1011      * @param in sequence containing MIDI data to be written to the file
1012      * @param fileType the file type of the file to be written to the output stream
1013      * @param out stream to which the file data should be written
1014      * @return the number of bytes written to the output stream
1015      * @throws IOException if an I/O exception occurs
1016      * @throws IllegalArgumentException if the file format is not supported by
1017      * the system
1018      * @see #isFileTypeSupported(int, Sequence)
1019      * @see     #getMidiFileTypes(Sequence)
1020      */
1021     public static int write(Sequence in, int fileType, OutputStream out) throws IOException {
1022 
1023         List<MidiFileWriter> providers = getMidiFileWriters();
1024         //$$fb 2002-04-17: Fix for 4635287: Standard MidiFileWriter cannot write empty Sequences
1025         int bytesWritten = -2;
1026 
1027         for (int i = 0; i < providers.size(); i++ ) {
1028             MidiFileWriter writer = providers.get(i);
1029             if( writer.isFileTypeSupported( fileType, in ) ) {
1030 
1031                 bytesWritten = writer.write(in, fileType, out);
1032                 break;
1033             }
1034         }
1035         if (bytesWritten == -2) {
1036             throw new IllegalArgumentException("MIDI file type is not supported");
1037         }
1038         return bytesWritten;
1039     }
1040 
1041 
1042     /**
1043      * Writes a stream of bytes representing a file of the MIDI file type
1044      * indicated to the external file provided.
1045      * @param in sequence containing MIDI data to be written to the file
1046      * @param type the file type of the file to be written to the output stream
1047      * @param out external file to which the file data should be written
1048      * @return the number of bytes written to the file
1049      * @throws IOException if an I/O exception occurs
1050      * @throws IllegalArgumentException if the file type is not supported by
1051      * the system
1052      * @see #isFileTypeSupported(int, Sequence)
1053      * @see     #getMidiFileTypes(Sequence)
1054      */
1055     public static int write(Sequence in, int type, File out) throws IOException {
1056 
1057         List<MidiFileWriter> providers = getMidiFileWriters();
1058         //$$fb 2002-04-17: Fix for 4635287: Standard MidiFileWriter cannot write empty Sequences
1059         int bytesWritten = -2;
1060 
1061         for (int i = 0; i < providers.size(); i++ ) {
1062             MidiFileWriter writer = providers.get(i);
1063             if( writer.isFileTypeSupported( type, in ) ) {
1064 
1065                 bytesWritten = writer.write(in, type, out);
1066                 break;
1067             }
1068         }
1069         if (bytesWritten == -2) {
1070             throw new IllegalArgumentException("MIDI file type is not supported");
1071         }
1072         return bytesWritten;
1073     }
1074 
1075 
1076 
1077     // HELPER METHODS
1078     @SuppressWarnings("unchecked")
1079     private static List<MidiDeviceProvider> getMidiDeviceProviders() {
1080         return (List<MidiDeviceProvider>) getProviders(MidiDeviceProvider.class);
1081     }
1082 
1083     @SuppressWarnings("unchecked")
1084     private static List<SoundbankReader> getSoundbankReaders() {
1085         return (List<SoundbankReader>) getProviders(SoundbankReader.class);
1086     }
1087 
1088     @SuppressWarnings("unchecked")
1089     private static List<MidiFileWriter> getMidiFileWriters() {
1090         return (List<MidiFileWriter>) getProviders(MidiFileWriter.class);
1091     }
1092 
1093     @SuppressWarnings("unchecked")
1094     private static List<MidiFileReader> getMidiFileReaders() {
1095         return (List<MidiFileReader>) getProviders(MidiFileReader.class);
1096     }
1097 
1098 
1099     /** Attempts to locate and return a default MidiDevice of the specified
1100      * type.
1101      *
1102      * This method wraps {@link #getDefaultDevice}. It catches the
1103      * <code>IllegalArgumentException</code> thrown by
1104      * <code>getDefaultDevice</code> and instead throws a
1105      * <code>MidiUnavailableException</code>, with the catched
1106      * exception chained.
1107      *
1108      * @param deviceClass The requested device type, one of Synthesizer.class,
1109      * Sequencer.class, Receiver.class or Transmitter.class.
1110      * @throws  MidiUnavalableException on failure.
1111      */
1112     private static MidiDevice getDefaultDeviceWrapper(Class<?> deviceClass)
1113         throws MidiUnavailableException{
1114         try {
1115             return getDefaultDevice(deviceClass);
1116         } catch (IllegalArgumentException iae) {
1117             MidiUnavailableException mae = new MidiUnavailableException();
1118             mae.initCause(iae);
1119             throw mae;
1120         }
1121     }
1122 
1123 
1124     /** Attempts to locate and return a default MidiDevice of the specified
1125      * type.
1126      *
1127      * @param deviceClass The requested device type, one of Synthesizer.class,
1128      * Sequencer.class, Receiver.class or Transmitter.class.
1129      * @throws  IllegalArgumentException on failure.
1130      */
1131     private static MidiDevice getDefaultDevice(Class<?> deviceClass) {
1132         List<MidiDeviceProvider> providers = getMidiDeviceProviders();
1133         String providerClassName = JDK13Services.getDefaultProviderClassName(deviceClass);
1134         String instanceName = JDK13Services.getDefaultInstanceName(deviceClass);
1135         MidiDevice device;
1136 
1137         if (providerClassName != null) {
1138             MidiDeviceProvider defaultProvider = getNamedProvider(providerClassName, providers);
1139             if (defaultProvider != null) {
1140                 if (instanceName != null) {
1141                     device = getNamedDevice(instanceName, defaultProvider, deviceClass);
1142                     if (device != null) {
1143                         return device;
1144                     }
1145                 }
1146                 device = getFirstDevice(defaultProvider, deviceClass);
1147                 if (device != null) {
1148                     return device;
1149                 }
1150             }
1151         }
1152 


1162 
1163         /* No default are specified, or if something is specified, everything
1164            failed. */
1165         device = getFirstDevice(providers, deviceClass);
1166         if (device != null) {
1167             return device;
1168         }
1169         throw new IllegalArgumentException("Requested device not installed");
1170     }
1171 
1172 
1173 
1174     /** Return a MidiDeviceProcider of a given class from the list of
1175         MidiDeviceProviders.
1176 
1177         @param providerClassName The class name of the provider to be returned.
1178         @param provider The list of MidiDeviceProviders that is searched.
1179         @return A MidiDeviceProvider of the requested class, or null if none
1180         is found.
1181     */
1182     private static MidiDeviceProvider getNamedProvider(String providerClassName,
1183                                                        List<MidiDeviceProvider> providers) {
1184         for(int i = 0; i < providers.size(); i++) {
1185             MidiDeviceProvider provider = providers.get(i);
1186             if (provider.getClass().getName().equals(providerClassName)) {
1187                 return provider;
1188             }
1189         }
1190         return null;
1191     }
1192 
1193 
1194     /** Return a MidiDevice with a given name from a given MidiDeviceProvider.
1195         @param deviceName The name of the MidiDevice to be returned.
1196         @param provider The MidiDeviceProvider to check for MidiDevices.
1197         @param deviceClass The requested device type, one of Synthesizer.class,
1198         Sequencer.class, Receiver.class or Transmitter.class.
1199 
1200         @return A MidiDevice matching the requirements, or null if none is found.
1201     */
1202     private static MidiDevice getNamedDevice(String deviceName,
1203                                              MidiDeviceProvider provider,
1204                                              Class<?> deviceClass) {
1205         MidiDevice device;
1206         // try to get MIDI port
1207         device = getNamedDevice(deviceName, provider, deviceClass,
1208                                  false, false);
1209         if (device != null) {
1210             return device;
1211         }
1212 
1213         if (deviceClass == Receiver.class) {
1214             // try to get Synthesizer
1215             device = getNamedDevice(deviceName, provider, deviceClass,
1216                                      true, false);
1217             if (device != null) {
1218                 return device;
1219             }
1220         }
1221 
1222         return null;
1223     }
1224 
1225 
1226     /** Return a MidiDevice with a given name from a given MidiDeviceProvider.
1227       @param deviceName The name of the MidiDevice to be returned.
1228       @param provider The MidiDeviceProvider to check for MidiDevices.
1229       @param deviceClass The requested device type, one of Synthesizer.class,
1230       Sequencer.class, Receiver.class or Transmitter.class.
1231 
1232       @return A MidiDevice matching the requirements, or null if none is found.
1233      */
1234     private static MidiDevice getNamedDevice(String deviceName,
1235                                              MidiDeviceProvider provider,
1236                                              Class<?> deviceClass,
1237                                              boolean allowSynthesizer,
1238                                              boolean allowSequencer) {
1239         MidiDevice.Info[] infos = provider.getDeviceInfo();
1240         for (int i = 0; i < infos.length; i++) {
1241             if (infos[i].getName().equals(deviceName)) {
1242                 MidiDevice device = provider.getDevice(infos[i]);
1243                 if (isAppropriateDevice(device, deviceClass,
1244                                         allowSynthesizer, allowSequencer)) {
1245                     return device;
1246                 }
1247             }
1248         }
1249         return null;
1250     }
1251 
1252 
1253     /** Return a MidiDevice with a given name from a list of
1254         MidiDeviceProviders.
1255         @param deviceName The name of the MidiDevice to be returned.
1256         @param providers The List of MidiDeviceProviders to check for
1257         MidiDevices.
1258         @param deviceClass The requested device type, one of Synthesizer.class,
1259         Sequencer.class, Receiver.class or Transmitter.class.
1260         @return A Mixer matching the requirements, or null if none is found.
1261     */
1262     private static MidiDevice getNamedDevice(String deviceName,
1263                                              List<MidiDeviceProvider> providers,
1264                                              Class<?> deviceClass) {
1265         MidiDevice device;
1266         // try to get MIDI port
1267         device = getNamedDevice(deviceName, providers, deviceClass,
1268                                  false, false);
1269         if (device != null) {
1270             return device;
1271         }
1272 
1273         if (deviceClass == Receiver.class) {
1274             // try to get Synthesizer
1275             device = getNamedDevice(deviceName, providers, deviceClass,
1276                                      true, false);
1277             if (device != null) {
1278                 return device;
1279             }
1280         }
1281 
1282         return null;
1283     }
1284 
1285 
1286     /** Return a MidiDevice with a given name from a list of
1287         MidiDeviceProviders.
1288         @param deviceName The name of the MidiDevice to be returned.
1289         @param providers The List of MidiDeviceProviders to check for
1290         MidiDevices.
1291         @param deviceClass The requested device type, one of Synthesizer.class,
1292         Sequencer.class, Receiver.class or Transmitter.class.
1293         @return A Mixer matching the requirements, or null if none is found.
1294      */
1295     private static MidiDevice getNamedDevice(String deviceName,
1296                                              List<MidiDeviceProvider> providers,
1297                                              Class<?> deviceClass,
1298                                              boolean allowSynthesizer,
1299                                              boolean allowSequencer) {
1300         for(int i = 0; i < providers.size(); i++) {
1301             MidiDeviceProvider provider = providers.get(i);
1302             MidiDevice device = getNamedDevice(deviceName, provider,
1303                                                deviceClass,
1304                                                allowSynthesizer,
1305                                                allowSequencer);
1306             if (device != null) {
1307                 return device;
1308             }
1309         }
1310         return null;
1311     }
1312 
1313 
1314     /** From a given MidiDeviceProvider, return the first appropriate device.
1315         @param provider The MidiDeviceProvider to check for MidiDevices.
1316         @param deviceClass The requested device type, one of Synthesizer.class,
1317         Sequencer.class, Receiver.class or Transmitter.class.
1318         @return A MidiDevice is considered appropriate, or null if no
1319         appropriate device is found.
1320     */
1321     private static MidiDevice getFirstDevice(MidiDeviceProvider provider,
1322                                              Class<?> deviceClass) {
1323         MidiDevice device;
1324         // try to get MIDI port
1325         device = getFirstDevice(provider, deviceClass,
1326                                 false, false);
1327         if (device != null) {
1328             return device;
1329         }
1330 
1331         if (deviceClass == Receiver.class) {
1332             // try to get Synthesizer
1333             device = getFirstDevice(provider, deviceClass,
1334                                     true, false);
1335             if (device != null) {
1336                 return device;
1337             }
1338         }
1339 
1340         return null;
1341     }
1342 
1343 
1344     /** From a given MidiDeviceProvider, return the first appropriate device.
1345         @param provider The MidiDeviceProvider to check for MidiDevices.
1346         @param deviceClass The requested device type, one of Synthesizer.class,
1347         Sequencer.class, Receiver.class or Transmitter.class.
1348         @return A MidiDevice is considered appropriate, or null if no
1349         appropriate device is found.
1350      */
1351     private static MidiDevice getFirstDevice(MidiDeviceProvider provider,
1352                                              Class<?> deviceClass,
1353                                              boolean allowSynthesizer,
1354                                              boolean allowSequencer) {
1355         MidiDevice.Info[] infos = provider.getDeviceInfo();
1356         for (int j = 0; j < infos.length; j++) {
1357             MidiDevice device = provider.getDevice(infos[j]);
1358             if (isAppropriateDevice(device, deviceClass,
1359                                     allowSynthesizer, allowSequencer)) {
1360                 return device;
1361             }
1362         }
1363         return null;
1364     }
1365 
1366 
1367     /** From a List of MidiDeviceProviders, return the first appropriate
1368         MidiDevice.
1369         @param providers The List of MidiDeviceProviders to search.
1370         @param deviceClass The requested device type, one of Synthesizer.class,
1371         Sequencer.class, Receiver.class or Transmitter.class.
1372         @return A MidiDevice that is considered appropriate, or null
1373         if none is found.
1374     */
1375     private static MidiDevice getFirstDevice(List<MidiDeviceProvider> providers,
1376                                              Class<?> deviceClass) {
1377         MidiDevice device;
1378         // try to get MIDI port
1379         device = getFirstDevice(providers, deviceClass,
1380                                 false, false);
1381         if (device != null) {
1382             return device;
1383         }
1384 
1385         if (deviceClass == Receiver.class) {
1386             // try to get Synthesizer
1387             device = getFirstDevice(providers, deviceClass,
1388                                     true, false);
1389             if (device != null) {
1390                 return device;
1391             }
1392         }
1393 
1394         return null;
1395     }
1396 
1397 
1398     /** From a List of MidiDeviceProviders, return the first appropriate
1399         MidiDevice.
1400         @param providers The List of MidiDeviceProviders to search.
1401         @param deviceClass The requested device type, one of Synthesizer.class,
1402         Sequencer.class, Receiver.class or Transmitter.class.
1403         @return A MidiDevice that is considered appropriate, or null
1404         if none is found.
1405      */
1406     private static MidiDevice getFirstDevice(List<MidiDeviceProvider> providers,
1407                                              Class<?> deviceClass,
1408                                              boolean allowSynthesizer,
1409                                              boolean allowSequencer) {
1410         for(int i = 0; i < providers.size(); i++) {
1411             MidiDeviceProvider provider = providers.get(i);
1412             MidiDevice device = getFirstDevice(provider, deviceClass,
1413                                                allowSynthesizer,
1414                                                allowSequencer);
1415             if (device != null) {
1416                 return device;
1417             }
1418         }
1419         return null;
1420     }
1421 
1422 
1423     /** Checks if a MidiDevice is appropriate.
1424         If deviceClass is Synthesizer or Sequencer, a device implementing
1425         the respective interface is considered appropriate. If deviceClass
1426         is Receiver or Transmitter, a device is considered appropriate if
1427         it implements neither Synthesizer nor Transmitter, and if it can
1428         provide at least one Receiver or Transmitter, respectively.
1429 
1430         @param device the MidiDevice to test
1431         @param allowSynthesizer if true, Synthesizers are considered
1432         appropriate. Otherwise only pure MidiDevices are considered
1433         appropriate (unless allowSequencer is true). This flag only has an
1434         effect for deviceClass Receiver and Transmitter. For other device
1435         classes (Sequencer and Synthesizer), this flag has no effect.
1436         @param allowSequencer if true, Sequencers are considered
1437         appropriate. Otherwise only pure MidiDevices are considered
1438         appropriate (unless allowSynthesizer is true). This flag only has an
1439         effect for deviceClass Receiver and Transmitter. For other device
1440         classes (Sequencer and Synthesizer), this flag has no effect.
1441         @return true if the device is considered appropriate according to the
1442         rules given above, false otherwise.
1443     */
1444     private static boolean isAppropriateDevice(MidiDevice device,
1445                                                Class<?> deviceClass,
1446                                                boolean allowSynthesizer,
1447                                                boolean allowSequencer) {
1448         if (deviceClass.isInstance(device)) {
1449            // This clause is for deviceClass being either Synthesizer
1450             // or Sequencer.
1451             return true;
1452         } else {
1453             // Now the case that deviceClass is Transmitter or
1454             // Receiver. If neither allowSynthesizer nor allowSequencer is
1455             // true, we require device instances to be
1456             // neither Synthesizer nor Sequencer, since we only want
1457             // devices representing MIDI ports.
1458             // Otherwise, the respective type is accepted, too
1459             if ( (! (device instanceof Sequencer) &&
1460                   ! (device instanceof Synthesizer) ) ||
1461                  ((device instanceof Sequencer) && allowSequencer) ||
1462                  ((device instanceof Synthesizer) && allowSynthesizer)) {
1463                 // And of cource, the device has to be able to provide
1464                 // Receivers or Transmitters.
1465                 if ((deviceClass == Receiver.class &&
1466                      device.getMaxReceivers() != 0) ||
1467                     (deviceClass == Transmitter.class &&
1468                      device.getMaxTransmitters() != 0)) {
1469                     return true;
1470                 }
1471             }
1472         }
1473         return false;
1474     }
1475 
1476 
1477     /**
1478      * Obtains the set of services currently installed on the system
1479      * using the SPI mechanism in 1.3.
1480      * @return a List of instances of providers for the requested service.
1481      * If no providers are available, a List of length 0 will be returned.
1482      */
1483      private static List<?> getProviders(Class<?> providerClass) {
1484          return JDK13Services.getProviders(providerClass);
1485     }
1486 }