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 "sound.properties", 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 "sound.properties", 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 } |