1 /*
2 * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package javax.sound.midi;
27
28 import java.io.File;
29 import java.io.IOException;
30 import java.io.InputStream;
31 import java.io.OutputStream;
32 import java.net.URL;
33 import java.util.ArrayList;
34 import java.util.Collections;
35 import java.util.HashSet;
36 import java.util.Iterator;
37 import java.util.List;
38 import java.util.Properties;
39 import java.util.Set;
40
41 import javax.sound.midi.spi.MidiDeviceProvider;
42 import javax.sound.midi.spi.MidiFileReader;
43 import javax.sound.midi.spi.MidiFileWriter;
44 import javax.sound.midi.spi.SoundbankReader;
45
46 import com.sun.media.sound.AutoConnectSequencer;
47 import com.sun.media.sound.JDK13Services;
48 import com.sun.media.sound.MidiDeviceReceiverEnvelope;
49 import com.sun.media.sound.MidiDeviceTransmitterEnvelope;
50 import com.sun.media.sound.ReferenceCountingDevice;
51
52 /**
53 * The {@code MidiSystem} class provides access to the installed MIDI system
54 * resources, including devices such as synthesizers, sequencers, and MIDI input
55 * and output ports. A typical simple MIDI application might begin by invoking
56 * one or more {@code MidiSystem} methods to learn what devices are installed
57 * and to obtain the ones needed in that application.
162 * installed MIDI device. If no such devices are installed, an array
163 * of length 0 is returned.
164 */
165 public static MidiDevice.Info[] getMidiDeviceInfo() {
166 final List<MidiDevice.Info> allInfos = new ArrayList<>();
167 for (final MidiDeviceProvider provider : getMidiDeviceProviders()) {
168 Collections.addAll(allInfos, provider.getDeviceInfo());
169 }
170 return allInfos.toArray(new MidiDevice.Info[allInfos.size()]);
171 }
172
173 /**
174 * Obtains the requested MIDI device.
175 *
176 * @param info a device information object representing the desired device
177 * @return the requested device
178 * @throws MidiUnavailableException if the requested device is not available
179 * due to resource restrictions
180 * @throws IllegalArgumentException if the info object does not represent a
181 * MIDI device installed on the system
182 * @see #getMidiDeviceInfo
183 */
184 public static MidiDevice getMidiDevice(final MidiDevice.Info info)
185 throws MidiUnavailableException {
186 for (final MidiDeviceProvider provider : getMidiDeviceProviders()) {
187 if (provider.isDeviceSupported(info)) {
188 return provider.getDevice(info);
189 }
190 }
191 throw new IllegalArgumentException(String.format(
192 "Requested device not installed: %s", info));
193 }
194
195 /**
196 * Obtains a MIDI receiver from an external MIDI port or other default
197 * device. The returned receiver always implements the
198 * {@code MidiDeviceReceiver} interface.
199 * <p>
200 * If the system property {@code javax.sound.midi.Receiver} is defined or it
201 * is defined in the file "sound.properties", it is used to identify the
202 * device that provides the default receiver. For details, refer to the
203 * {@link MidiSystem class description}.
204 * <p>
205 * If a suitable MIDI port is not available, the Receiver is retrieved from
430 }
431 }
432 return seq;
433 }
434
435 /**
436 * Constructs a MIDI sound bank by reading it from the specified stream. The
437 * stream must point to a valid MIDI soundbank file. In general, MIDI
438 * soundbank providers may need to read some data from the stream before
439 * determining whether they support it. These parsers must be able to mark
440 * the stream, read enough data to determine whether they support the
441 * stream, and, if not, reset the stream's read pointer to its original
442 * position. If the input stream does not support this, this method may fail
443 * with an {@code IOException}.
444 *
445 * @param stream the source of the sound bank data
446 * @return the sound bank
447 * @throws InvalidMidiDataException if the stream does not point to valid
448 * MIDI soundbank data recognized by the system
449 * @throws IOException if an I/O error occurred when loading the soundbank
450 * @see InputStream#markSupported
451 * @see InputStream#mark
452 */
453 public static Soundbank getSoundbank(InputStream stream)
454 throws InvalidMidiDataException, IOException {
455
456 SoundbankReader sp = null;
457 Soundbank s = null;
458
459 List<SoundbankReader> providers = getSoundbankReaders();
460
461 for(int i = 0; i < providers.size(); i++) {
462 sp = providers.get(i);
463 s = sp.getSoundbank(stream);
464
465 if( s!= null) {
466 return s;
467 }
468 }
469 throw new InvalidMidiDataException("cannot get soundbank from stream");
470
471 }
472
473 /**
474 * Constructs a {@code Soundbank} by reading it from the specified URL. The
475 * URL must point to a valid MIDI soundbank file.
476 *
477 * @param url the source of the sound bank data
478 * @return the sound bank
479 * @throws InvalidMidiDataException if the URL does not point to valid MIDI
480 * soundbank data recognized by the system
481 * @throws IOException if an I/O error occurred when loading the soundbank
482 */
483 public static Soundbank getSoundbank(URL url)
484 throws InvalidMidiDataException, IOException {
485
486 SoundbankReader sp = null;
487 Soundbank s = null;
488
489 List<SoundbankReader> providers = getSoundbankReaders();
490
491 for(int i = 0; i < providers.size(); i++) {
492 sp = providers.get(i);
493 s = sp.getSoundbank(url);
494
495 if( s!= null) {
496 return s;
497 }
498 }
499 throw new InvalidMidiDataException("cannot get soundbank from stream");
500
501 }
502
503 /**
504 * Constructs a {@code Soundbank} by reading it from the specified
505 * {@code File}. The {@code File} must point to a valid MIDI soundbank file.
506 *
507 * @param file the source of the sound bank data
508 * @return the sound bank
509 * @throws InvalidMidiDataException if the {@code File} does not point to
510 * valid MIDI soundbank data recognized by the system
511 * @throws IOException if an I/O error occurred when loading the soundbank
512 */
513 public static Soundbank getSoundbank(File file)
514 throws InvalidMidiDataException, IOException {
515
516 SoundbankReader sp = null;
517 Soundbank s = null;
518
519 List<SoundbankReader> providers = getSoundbankReaders();
520
521 for(int i = 0; i < providers.size(); i++) {
522 sp = providers.get(i);
523 s = sp.getSoundbank(file);
524
525 if( s!= null) {
526 return s;
527 }
528 }
529 throw new InvalidMidiDataException("cannot get soundbank from stream");
530 }
531
532 /**
533 * Obtains the MIDI file format of the data in the specified input stream.
534 * The stream must point to valid MIDI file data for a file type recognized
539 * implementation may therefore need to mark the stream, read enough data to
540 * determine whether it is in a supported format, and reset the stream's
541 * read pointer to its original position. If the input stream does not
542 * permit this set of operations, this method may fail with an
543 * {@code IOException}.
544 * <p>
545 * This operation can only succeed for files of a type which can be parsed
546 * by an installed file reader. It may fail with an
547 * {@code InvalidMidiDataException} even for valid files if no compatible
548 * file reader is installed. It will also fail with an
549 * {@code InvalidMidiDataException} if a compatible file reader is
550 * installed, but encounters errors while determining the file format.
551 *
552 * @param stream the input stream from which file format information should
553 * be extracted
554 * @return an {@code MidiFileFormat} object describing the MIDI file format
555 * @throws InvalidMidiDataException if the stream does not point to valid
556 * MIDI file data recognized by the system
557 * @throws IOException if an I/O exception occurs while accessing the
558 * stream
559 * @see #getMidiFileFormat(URL)
560 * @see #getMidiFileFormat(File)
561 * @see InputStream#markSupported
562 * @see InputStream#mark
563 */
564 public static MidiFileFormat getMidiFileFormat(InputStream stream)
565 throws InvalidMidiDataException, IOException {
566
567 List<MidiFileReader> providers = getMidiFileReaders();
568 MidiFileFormat format = null;
569
570 for(int i = 0; i < providers.size(); i++) {
571 MidiFileReader reader = providers.get(i);
572 try {
573 format = reader.getMidiFileFormat( stream ); // throws IOException
574 break;
575 } catch (InvalidMidiDataException e) {
576 continue;
577 }
578 }
579
580 if( format==null ) {
581 throw new InvalidMidiDataException("input stream is not a supported file type");
582 } else {
583 return format;
584 }
585 }
586
587 /**
588 * Obtains the MIDI file format of the data in the specified URL. The URL
589 * must point to valid MIDI file data for a file type recognized by the
590 * system.
591 * <p>
592 * This operation can only succeed for files of a type which can be parsed
593 * by an installed file reader. It may fail with an
594 * {@code InvalidMidiDataException} even for valid files if no compatible
595 * file reader is installed. It will also fail with an
596 * {@code InvalidMidiDataException} if a compatible file reader is
597 * installed, but encounters errors while determining the file format.
598 *
599 * @param url the URL from which file format information should be
600 * extracted
601 * @return a {@code MidiFileFormat} object describing the MIDI file format
602 * @throws InvalidMidiDataException if the URL does not point to valid MIDI
603 * file data recognized by the system
604 * @throws IOException if an I/O exception occurs while accessing the URL
605 * @see #getMidiFileFormat(InputStream)
606 * @see #getMidiFileFormat(File)
607 */
608 public static MidiFileFormat getMidiFileFormat(URL url)
609 throws InvalidMidiDataException, IOException {
610
611 List<MidiFileReader> providers = getMidiFileReaders();
612 MidiFileFormat format = null;
613
614 for(int i = 0; i < providers.size(); i++) {
615 MidiFileReader reader = providers.get(i);
616 try {
617 format = reader.getMidiFileFormat( url ); // throws IOException
618 break;
619 } catch (InvalidMidiDataException e) {
620 continue;
621 }
622 }
623
624 if( format==null ) {
625 throw new InvalidMidiDataException("url is not a supported file type");
626 } else {
627 return format;
628 }
629 }
630
631 /**
632 * Obtains the MIDI file format of the specified {@code File}. The
633 * {@code File} must point to valid MIDI file data for a file type
634 * recognized by the system.
635 * <p>
636 * This operation can only succeed for files of a type which can be parsed
637 * by an installed file reader. It may fail with an
638 * {@code InvalidMidiDataException} even for valid files if no compatible
639 * file reader is installed. It will also fail with an
640 * {@code InvalidMidiDataException} if a compatible file reader is
641 * installed, but encounters errors while determining the file format.
642 *
643 * @param file the {@code File} from which file format information should
644 * be extracted
645 * @return a {@code MidiFileFormat} object describing the MIDI file format
646 * @throws InvalidMidiDataException if the {@code File} does not point to
647 * valid MIDI file data recognized by the system
648 * @throws IOException if an I/O exception occurs while accessing the file
649 * @see #getMidiFileFormat(InputStream)
650 * @see #getMidiFileFormat(URL)
651 */
652 public static MidiFileFormat getMidiFileFormat(File file)
653 throws InvalidMidiDataException, IOException {
654
655 List<MidiFileReader> providers = getMidiFileReaders();
656 MidiFileFormat format = null;
657
658 for(int i = 0; i < providers.size(); i++) {
659 MidiFileReader reader = providers.get(i);
660 try {
661 format = reader.getMidiFileFormat( file ); // throws IOException
662 break;
663 } catch (InvalidMidiDataException e) {
664 continue;
665 }
666 }
667
668 if( format==null ) {
669 throw new InvalidMidiDataException("file is not a supported file type");
670 } else {
671 return format;
672 }
673 }
682 * determine whether it is in a supported format, and reset the stream's
683 * read pointer to its original position. If the input stream does not
684 * permit this set of operations, this method may fail with an
685 * {@code IOException}.
686 * <p>
687 * This operation can only succeed for files of a type which can be parsed
688 * by an installed file reader. It may fail with an
689 * {@code InvalidMidiDataException} even for valid files if no compatible
690 * file reader is installed. It will also fail with an
691 * {@code InvalidMidiDataException} if a compatible file reader is
692 * installed, but encounters errors while constructing the {@code Sequence}
693 * object from the file data.
694 *
695 * @param stream the input stream from which the {@code Sequence} should be
696 * constructed
697 * @return a {@code Sequence} object based on the MIDI file data contained
698 * in the input stream
699 * @throws InvalidMidiDataException if the stream does not point to valid
700 * MIDI file data recognized by the system
701 * @throws IOException if an I/O exception occurs while accessing the stream
702 * @see InputStream#markSupported
703 * @see InputStream#mark
704 */
705 public static Sequence getSequence(InputStream stream)
706 throws InvalidMidiDataException, IOException {
707
708 List<MidiFileReader> providers = getMidiFileReaders();
709 Sequence sequence = null;
710
711 for(int i = 0; i < providers.size(); i++) {
712 MidiFileReader reader = providers.get(i);
713 try {
714 sequence = reader.getSequence( stream ); // throws IOException
715 break;
716 } catch (InvalidMidiDataException e) {
717 continue;
718 }
719 }
720
721 if( sequence==null ) {
722 throw new InvalidMidiDataException("could not get sequence from input stream");
723 } else {
724 return sequence;
725 }
726 }
727
728 /**
729 * Obtains a MIDI sequence from the specified URL. The URL must point to
730 * valid MIDI file data for a file type recognized by the system.
731 * <p>
732 * This operation can only succeed for files of a type which can be parsed
733 * by an installed file reader. It may fail with an
734 * {@code InvalidMidiDataException} even for valid files if no compatible
735 * file reader is installed. It will also fail with an
736 * {@code InvalidMidiDataException} if a compatible file reader is
737 * installed, but encounters errors while constructing the {@code Sequence}
738 * object from the file data.
739 *
740 * @param url the URL from which the {@code Sequence} should be constructed
741 * @return a {@code Sequence} object based on the MIDI file data pointed to
742 * by the URL
743 * @throws InvalidMidiDataException if the URL does not point to valid MIDI
744 * file data recognized by the system
745 * @throws IOException if an I/O exception occurs while accessing the URL
746 */
747 public static Sequence getSequence(URL url)
748 throws InvalidMidiDataException, IOException {
749
750 List<MidiFileReader> providers = getMidiFileReaders();
751 Sequence sequence = null;
752
753 for(int i = 0; i < providers.size(); i++) {
754 MidiFileReader reader = providers.get(i);
755 try {
756 sequence = reader.getSequence( url ); // throws IOException
757 break;
758 } catch (InvalidMidiDataException e) {
759 continue;
760 }
761 }
762
763 if( sequence==null ) {
764 throw new InvalidMidiDataException("could not get sequence from URL");
765 } else {
766 return sequence;
767 }
768 }
770 /**
771 * Obtains a MIDI sequence from the specified {@code File}. The {@code File}
772 * must point to valid MIDI file data for a file type recognized by the
773 * system.
774 * <p>
775 * This operation can only succeed for files of a type which can be parsed
776 * by an installed file reader. It may fail with an
777 * {@code InvalidMidiDataException} even for valid files if no compatible
778 * file reader is installed. It will also fail with an
779 * {@code InvalidMidiDataException} if a compatible file reader is
780 * installed, but encounters errors while constructing the {@code Sequence}
781 * object from the file data.
782 *
783 * @param file the {@code File} from which the {@code Sequence} should be
784 * constructed
785 * @return a {@code Sequence} object based on the MIDI file data pointed to
786 * by the File
787 * @throws InvalidMidiDataException if the File does not point to valid MIDI
788 * file data recognized by the system
789 * @throws IOException if an I/O exception occurs
790 */
791 public static Sequence getSequence(File file)
792 throws InvalidMidiDataException, IOException {
793
794 List<MidiFileReader> providers = getMidiFileReaders();
795 Sequence sequence = null;
796
797 for(int i = 0; i < providers.size(); i++) {
798 MidiFileReader reader = providers.get(i);
799 try {
800 sequence = reader.getSequence( file ); // throws IOException
801 break;
802 } catch (InvalidMidiDataException e) {
803 continue;
804 }
805 }
806
807 if( sequence==null ) {
808 throw new InvalidMidiDataException("could not get sequence from file");
809 } else {
810 return sequence;
811 }
812 }
853 public static boolean isFileTypeSupported(int fileType) {
854
855 List<MidiFileWriter> providers = getMidiFileWriters();
856
857 for (int i = 0; i < providers.size(); i++ ) {
858 MidiFileWriter writer = providers.get(i);
859 if( writer.isFileTypeSupported(fileType)) {
860 return true;
861 }
862 }
863 return false;
864 }
865
866 /**
867 * Obtains the set of MIDI file types that the system can write from the
868 * sequence specified.
869 *
870 * @param sequence the sequence for which MIDI file type support is queried
871 * @return the set of unique supported file types. If no file types are
872 * supported, returns an array of length 0.
873 */
874 public static int[] getMidiFileTypes(Sequence sequence) {
875
876 List<MidiFileWriter> providers = getMidiFileWriters();
877 Set<Integer> allTypes = new HashSet<>();
878
879 // gather from all the providers
880
881 for (int i = 0; i < providers.size(); i++ ) {
882 MidiFileWriter writer = providers.get(i);
883 int[] types = writer.getMidiFileTypes(sequence);
884 for (int j = 0; j < types.length; j++ ) {
885 allTypes.add(types[j]);
886 }
887 }
888 int resultTypes[] = new int[allTypes.size()];
889 int index = 0;
890 Iterator<Integer> iterator = allTypes.iterator();
891 while (iterator.hasNext()) {
892 Integer integer = iterator.next();
893 resultTypes[index++] = integer.intValue();
894 }
895 return resultTypes;
896 }
897
898 /**
899 * Indicates whether a MIDI file of the file type specified can be written
900 * from the sequence indicated.
901 *
902 * @param fileType the file type for which write capabilities are queried
903 * @param sequence the sequence for which file writing support is queried
904 * @return {@code true} if the file type is supported for this sequence,
905 * otherwise {@code false}
906 */
907 public static boolean isFileTypeSupported(int fileType, Sequence sequence) {
908
909 List<MidiFileWriter> providers = getMidiFileWriters();
910
911 for (int i = 0; i < providers.size(); i++ ) {
912 MidiFileWriter writer = providers.get(i);
913 if( writer.isFileTypeSupported(fileType,sequence)) {
914 return true;
915 }
916 }
917 return false;
918 }
919
920 /**
921 * Writes a stream of bytes representing a file of the MIDI file type
922 * indicated to the output stream provided.
923 *
924 * @param in sequence containing MIDI data to be written to the file
925 * @param fileType the file type of the file to be written to the output
926 * stream
927 * @param out stream to which the file data should be written
928 * @return the number of bytes written to the output stream
929 * @throws IOException if an I/O exception occurs
930 * @throws IllegalArgumentException if the file format is not supported by
931 * the system
932 * @see #isFileTypeSupported(int, Sequence)
933 * @see #getMidiFileTypes(Sequence)
934 */
935 public static int write(Sequence in, int fileType, OutputStream out) throws IOException {
936
937 List<MidiFileWriter> providers = getMidiFileWriters();
938 //$$fb 2002-04-17: Fix for 4635287: Standard MidiFileWriter cannot write empty Sequences
939 int bytesWritten = -2;
940
941 for (int i = 0; i < providers.size(); i++ ) {
942 MidiFileWriter writer = providers.get(i);
943 if( writer.isFileTypeSupported( fileType, in ) ) {
944
945 bytesWritten = writer.write(in, fileType, out);
946 break;
947 }
948 }
949 if (bytesWritten == -2) {
950 throw new IllegalArgumentException("MIDI file type is not supported");
951 }
952 return bytesWritten;
953 }
954
955 /**
956 * Writes a stream of bytes representing a file of the MIDI file type
957 * indicated to the external file provided.
958 *
959 * @param in sequence containing MIDI data to be written to the file
960 * @param type the file type of the file to be written to the output stream
961 * @param out external file to which the file data should be written
962 * @return the number of bytes written to the file
963 * @throws IOException if an I/O exception occurs
964 * @throws IllegalArgumentException if the file type is not supported by the
965 * system
966 * @see #isFileTypeSupported(int, Sequence)
967 * @see #getMidiFileTypes(Sequence)
968 */
969 public static int write(Sequence in, int type, File out) throws IOException {
970
971 List<MidiFileWriter> providers = getMidiFileWriters();
972 //$$fb 2002-04-17: Fix for 4635287: Standard MidiFileWriter cannot write empty Sequences
973 int bytesWritten = -2;
974
975 for (int i = 0; i < providers.size(); i++ ) {
976 MidiFileWriter writer = providers.get(i);
977 if( writer.isFileTypeSupported( type, in ) ) {
978
979 bytesWritten = writer.write(in, type, out);
980 break;
981 }
982 }
983 if (bytesWritten == -2) {
984 throw new IllegalArgumentException("MIDI file type is not supported");
985 }
986 return bytesWritten;
987 }
988
989 // HELPER METHODS
|
1 /*
2 * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package javax.sound.midi;
27
28 import java.io.File;
29 import java.io.IOException;
30 import java.io.InputStream;
31 import java.io.OutputStream;
32 import java.net.URL;
33 import java.util.ArrayList;
34 import java.util.Collections;
35 import java.util.HashSet;
36 import java.util.Iterator;
37 import java.util.List;
38 import java.util.Objects;
39 import java.util.Properties;
40 import java.util.Set;
41
42 import javax.sound.midi.spi.MidiDeviceProvider;
43 import javax.sound.midi.spi.MidiFileReader;
44 import javax.sound.midi.spi.MidiFileWriter;
45 import javax.sound.midi.spi.SoundbankReader;
46
47 import com.sun.media.sound.AutoConnectSequencer;
48 import com.sun.media.sound.JDK13Services;
49 import com.sun.media.sound.MidiDeviceReceiverEnvelope;
50 import com.sun.media.sound.MidiDeviceTransmitterEnvelope;
51 import com.sun.media.sound.ReferenceCountingDevice;
52
53 /**
54 * The {@code MidiSystem} class provides access to the installed MIDI system
55 * resources, including devices such as synthesizers, sequencers, and MIDI input
56 * and output ports. A typical simple MIDI application might begin by invoking
57 * one or more {@code MidiSystem} methods to learn what devices are installed
58 * and to obtain the ones needed in that application.
163 * installed MIDI device. If no such devices are installed, an array
164 * of length 0 is returned.
165 */
166 public static MidiDevice.Info[] getMidiDeviceInfo() {
167 final List<MidiDevice.Info> allInfos = new ArrayList<>();
168 for (final MidiDeviceProvider provider : getMidiDeviceProviders()) {
169 Collections.addAll(allInfos, provider.getDeviceInfo());
170 }
171 return allInfos.toArray(new MidiDevice.Info[allInfos.size()]);
172 }
173
174 /**
175 * Obtains the requested MIDI device.
176 *
177 * @param info a device information object representing the desired device
178 * @return the requested device
179 * @throws MidiUnavailableException if the requested device is not available
180 * due to resource restrictions
181 * @throws IllegalArgumentException if the info object does not represent a
182 * MIDI device installed on the system
183 * @throws NullPointerException if {@code info} is {@code null}
184 * @see #getMidiDeviceInfo
185 */
186 public static MidiDevice getMidiDevice(final MidiDevice.Info info)
187 throws MidiUnavailableException {
188 Objects.requireNonNull(info);
189 for (final MidiDeviceProvider provider : getMidiDeviceProviders()) {
190 if (provider.isDeviceSupported(info)) {
191 return provider.getDevice(info);
192 }
193 }
194 throw new IllegalArgumentException(String.format(
195 "Requested device not installed: %s", info));
196 }
197
198 /**
199 * Obtains a MIDI receiver from an external MIDI port or other default
200 * device. The returned receiver always implements the
201 * {@code MidiDeviceReceiver} interface.
202 * <p>
203 * If the system property {@code javax.sound.midi.Receiver} is defined or it
204 * is defined in the file "sound.properties", it is used to identify the
205 * device that provides the default receiver. For details, refer to the
206 * {@link MidiSystem class description}.
207 * <p>
208 * If a suitable MIDI port is not available, the Receiver is retrieved from
433 }
434 }
435 return seq;
436 }
437
438 /**
439 * Constructs a MIDI sound bank by reading it from the specified stream. The
440 * stream must point to a valid MIDI soundbank file. In general, MIDI
441 * soundbank providers may need to read some data from the stream before
442 * determining whether they support it. These parsers must be able to mark
443 * the stream, read enough data to determine whether they support the
444 * stream, and, if not, reset the stream's read pointer to its original
445 * position. If the input stream does not support this, this method may fail
446 * with an {@code IOException}.
447 *
448 * @param stream the source of the sound bank data
449 * @return the sound bank
450 * @throws InvalidMidiDataException if the stream does not point to valid
451 * MIDI soundbank data recognized by the system
452 * @throws IOException if an I/O error occurred when loading the soundbank
453 * @throws NullPointerException if {@code stream} is {@code null}
454 * @see InputStream#markSupported
455 * @see InputStream#mark
456 */
457 public static Soundbank getSoundbank(final InputStream stream)
458 throws InvalidMidiDataException, IOException {
459 Objects.requireNonNull(stream);
460
461 SoundbankReader sp = null;
462 Soundbank s = null;
463
464 List<SoundbankReader> providers = getSoundbankReaders();
465
466 for(int i = 0; i < providers.size(); i++) {
467 sp = providers.get(i);
468 s = sp.getSoundbank(stream);
469
470 if( s!= null) {
471 return s;
472 }
473 }
474 throw new InvalidMidiDataException("cannot get soundbank from stream");
475
476 }
477
478 /**
479 * Constructs a {@code Soundbank} by reading it from the specified URL. The
480 * URL must point to a valid MIDI soundbank file.
481 *
482 * @param url the source of the sound bank data
483 * @return the sound bank
484 * @throws InvalidMidiDataException if the URL does not point to valid MIDI
485 * soundbank data recognized by the system
486 * @throws IOException if an I/O error occurred when loading the soundbank
487 * @throws NullPointerException if {@code url} is {@code null}
488 */
489 public static Soundbank getSoundbank(final URL url)
490 throws InvalidMidiDataException, IOException {
491 Objects.requireNonNull(url);
492
493 SoundbankReader sp = null;
494 Soundbank s = null;
495
496 List<SoundbankReader> providers = getSoundbankReaders();
497
498 for(int i = 0; i < providers.size(); i++) {
499 sp = providers.get(i);
500 s = sp.getSoundbank(url);
501
502 if( s!= null) {
503 return s;
504 }
505 }
506 throw new InvalidMidiDataException("cannot get soundbank from stream");
507
508 }
509
510 /**
511 * Constructs a {@code Soundbank} by reading it from the specified
512 * {@code File}. The {@code File} must point to a valid MIDI soundbank file.
513 *
514 * @param file the source of the sound bank data
515 * @return the sound bank
516 * @throws InvalidMidiDataException if the {@code File} does not point to
517 * valid MIDI soundbank data recognized by the system
518 * @throws IOException if an I/O error occurred when loading the soundbank
519 * @throws NullPointerException if {@code file} is {@code null}
520 */
521 public static Soundbank getSoundbank(final File file)
522 throws InvalidMidiDataException, IOException {
523 Objects.requireNonNull(file);
524
525 SoundbankReader sp = null;
526 Soundbank s = null;
527
528 List<SoundbankReader> providers = getSoundbankReaders();
529
530 for(int i = 0; i < providers.size(); i++) {
531 sp = providers.get(i);
532 s = sp.getSoundbank(file);
533
534 if( s!= null) {
535 return s;
536 }
537 }
538 throw new InvalidMidiDataException("cannot get soundbank from stream");
539 }
540
541 /**
542 * Obtains the MIDI file format of the data in the specified input stream.
543 * The stream must point to valid MIDI file data for a file type recognized
548 * implementation may therefore need to mark the stream, read enough data to
549 * determine whether it is in a supported format, and reset the stream's
550 * read pointer to its original position. If the input stream does not
551 * permit this set of operations, this method may fail with an
552 * {@code IOException}.
553 * <p>
554 * This operation can only succeed for files of a type which can be parsed
555 * by an installed file reader. It may fail with an
556 * {@code InvalidMidiDataException} even for valid files if no compatible
557 * file reader is installed. It will also fail with an
558 * {@code InvalidMidiDataException} if a compatible file reader is
559 * installed, but encounters errors while determining the file format.
560 *
561 * @param stream the input stream from which file format information should
562 * be extracted
563 * @return an {@code MidiFileFormat} object describing the MIDI file format
564 * @throws InvalidMidiDataException if the stream does not point to valid
565 * MIDI file data recognized by the system
566 * @throws IOException if an I/O exception occurs while accessing the
567 * stream
568 * @throws NullPointerException if {@code stream} is {@code null}
569 * @see #getMidiFileFormat(URL)
570 * @see #getMidiFileFormat(File)
571 * @see InputStream#markSupported
572 * @see InputStream#mark
573 */
574 public static MidiFileFormat getMidiFileFormat(final InputStream stream)
575 throws InvalidMidiDataException, IOException {
576 Objects.requireNonNull(stream);
577
578 List<MidiFileReader> providers = getMidiFileReaders();
579 MidiFileFormat format = null;
580
581 for(int i = 0; i < providers.size(); i++) {
582 MidiFileReader reader = providers.get(i);
583 try {
584 format = reader.getMidiFileFormat( stream ); // throws IOException
585 break;
586 } catch (InvalidMidiDataException e) {
587 continue;
588 }
589 }
590
591 if( format==null ) {
592 throw new InvalidMidiDataException("input stream is not a supported file type");
593 } else {
594 return format;
595 }
596 }
597
598 /**
599 * Obtains the MIDI file format of the data in the specified URL. The URL
600 * must point to valid MIDI file data for a file type recognized by the
601 * system.
602 * <p>
603 * This operation can only succeed for files of a type which can be parsed
604 * by an installed file reader. It may fail with an
605 * {@code InvalidMidiDataException} even for valid files if no compatible
606 * file reader is installed. It will also fail with an
607 * {@code InvalidMidiDataException} if a compatible file reader is
608 * installed, but encounters errors while determining the file format.
609 *
610 * @param url the URL from which file format information should be
611 * extracted
612 * @return a {@code MidiFileFormat} object describing the MIDI file format
613 * @throws InvalidMidiDataException if the URL does not point to valid MIDI
614 * file data recognized by the system
615 * @throws IOException if an I/O exception occurs while accessing the URL
616 * @throws NullPointerException if {@code url} is {@code null}
617 * @see #getMidiFileFormat(InputStream)
618 * @see #getMidiFileFormat(File)
619 */
620 public static MidiFileFormat getMidiFileFormat(final URL url)
621 throws InvalidMidiDataException, IOException {
622 Objects.requireNonNull(url);
623
624 List<MidiFileReader> providers = getMidiFileReaders();
625 MidiFileFormat format = null;
626
627 for(int i = 0; i < providers.size(); i++) {
628 MidiFileReader reader = providers.get(i);
629 try {
630 format = reader.getMidiFileFormat( url ); // throws IOException
631 break;
632 } catch (InvalidMidiDataException e) {
633 continue;
634 }
635 }
636
637 if( format==null ) {
638 throw new InvalidMidiDataException("url is not a supported file type");
639 } else {
640 return format;
641 }
642 }
643
644 /**
645 * Obtains the MIDI file format of the specified {@code File}. The
646 * {@code File} must point to valid MIDI file data for a file type
647 * recognized by the system.
648 * <p>
649 * This operation can only succeed for files of a type which can be parsed
650 * by an installed file reader. It may fail with an
651 * {@code InvalidMidiDataException} even for valid files if no compatible
652 * file reader is installed. It will also fail with an
653 * {@code InvalidMidiDataException} if a compatible file reader is
654 * installed, but encounters errors while determining the file format.
655 *
656 * @param file the {@code File} from which file format information should
657 * be extracted
658 * @return a {@code MidiFileFormat} object describing the MIDI file format
659 * @throws InvalidMidiDataException if the {@code File} does not point to
660 * valid MIDI file data recognized by the system
661 * @throws IOException if an I/O exception occurs while accessing the file
662 * @throws NullPointerException if {@code file} is {@code null}
663 * @see #getMidiFileFormat(InputStream)
664 * @see #getMidiFileFormat(URL)
665 */
666 public static MidiFileFormat getMidiFileFormat(final File file)
667 throws InvalidMidiDataException, IOException {
668 Objects.requireNonNull(file);
669
670 List<MidiFileReader> providers = getMidiFileReaders();
671 MidiFileFormat format = null;
672
673 for(int i = 0; i < providers.size(); i++) {
674 MidiFileReader reader = providers.get(i);
675 try {
676 format = reader.getMidiFileFormat( file ); // throws IOException
677 break;
678 } catch (InvalidMidiDataException e) {
679 continue;
680 }
681 }
682
683 if( format==null ) {
684 throw new InvalidMidiDataException("file is not a supported file type");
685 } else {
686 return format;
687 }
688 }
697 * determine whether it is in a supported format, and reset the stream's
698 * read pointer to its original position. If the input stream does not
699 * permit this set of operations, this method may fail with an
700 * {@code IOException}.
701 * <p>
702 * This operation can only succeed for files of a type which can be parsed
703 * by an installed file reader. It may fail with an
704 * {@code InvalidMidiDataException} even for valid files if no compatible
705 * file reader is installed. It will also fail with an
706 * {@code InvalidMidiDataException} if a compatible file reader is
707 * installed, but encounters errors while constructing the {@code Sequence}
708 * object from the file data.
709 *
710 * @param stream the input stream from which the {@code Sequence} should be
711 * constructed
712 * @return a {@code Sequence} object based on the MIDI file data contained
713 * in the input stream
714 * @throws InvalidMidiDataException if the stream does not point to valid
715 * MIDI file data recognized by the system
716 * @throws IOException if an I/O exception occurs while accessing the stream
717 * @throws NullPointerException if {@code stream} is {@code null}
718 * @see InputStream#markSupported
719 * @see InputStream#mark
720 */
721 public static Sequence getSequence(final InputStream stream)
722 throws InvalidMidiDataException, IOException {
723 Objects.requireNonNull(stream);
724
725 List<MidiFileReader> providers = getMidiFileReaders();
726 Sequence sequence = null;
727
728 for(int i = 0; i < providers.size(); i++) {
729 MidiFileReader reader = providers.get(i);
730 try {
731 sequence = reader.getSequence( stream ); // throws IOException
732 break;
733 } catch (InvalidMidiDataException e) {
734 continue;
735 }
736 }
737
738 if( sequence==null ) {
739 throw new InvalidMidiDataException("could not get sequence from input stream");
740 } else {
741 return sequence;
742 }
743 }
744
745 /**
746 * Obtains a MIDI sequence from the specified URL. The URL must point to
747 * valid MIDI file data for a file type recognized by the system.
748 * <p>
749 * This operation can only succeed for files of a type which can be parsed
750 * by an installed file reader. It may fail with an
751 * {@code InvalidMidiDataException} even for valid files if no compatible
752 * file reader is installed. It will also fail with an
753 * {@code InvalidMidiDataException} if a compatible file reader is
754 * installed, but encounters errors while constructing the {@code Sequence}
755 * object from the file data.
756 *
757 * @param url the URL from which the {@code Sequence} should be constructed
758 * @return a {@code Sequence} object based on the MIDI file data pointed to
759 * by the URL
760 * @throws InvalidMidiDataException if the URL does not point to valid MIDI
761 * file data recognized by the system
762 * @throws IOException if an I/O exception occurs while accessing the URL
763 * @throws NullPointerException if {@code url} is {@code null}
764 */
765 public static Sequence getSequence(final URL url)
766 throws InvalidMidiDataException, IOException {
767 Objects.requireNonNull(url);
768
769 List<MidiFileReader> providers = getMidiFileReaders();
770 Sequence sequence = null;
771
772 for(int i = 0; i < providers.size(); i++) {
773 MidiFileReader reader = providers.get(i);
774 try {
775 sequence = reader.getSequence( url ); // throws IOException
776 break;
777 } catch (InvalidMidiDataException e) {
778 continue;
779 }
780 }
781
782 if( sequence==null ) {
783 throw new InvalidMidiDataException("could not get sequence from URL");
784 } else {
785 return sequence;
786 }
787 }
789 /**
790 * Obtains a MIDI sequence from the specified {@code File}. The {@code File}
791 * must point to valid MIDI file data for a file type recognized by the
792 * system.
793 * <p>
794 * This operation can only succeed for files of a type which can be parsed
795 * by an installed file reader. It may fail with an
796 * {@code InvalidMidiDataException} even for valid files if no compatible
797 * file reader is installed. It will also fail with an
798 * {@code InvalidMidiDataException} if a compatible file reader is
799 * installed, but encounters errors while constructing the {@code Sequence}
800 * object from the file data.
801 *
802 * @param file the {@code File} from which the {@code Sequence} should be
803 * constructed
804 * @return a {@code Sequence} object based on the MIDI file data pointed to
805 * by the File
806 * @throws InvalidMidiDataException if the File does not point to valid MIDI
807 * file data recognized by the system
808 * @throws IOException if an I/O exception occurs
809 * @throws NullPointerException if {@code file} is {@code null}
810 */
811 public static Sequence getSequence(final File file)
812 throws InvalidMidiDataException, IOException {
813 Objects.requireNonNull(file);
814
815 List<MidiFileReader> providers = getMidiFileReaders();
816 Sequence sequence = null;
817
818 for(int i = 0; i < providers.size(); i++) {
819 MidiFileReader reader = providers.get(i);
820 try {
821 sequence = reader.getSequence( file ); // throws IOException
822 break;
823 } catch (InvalidMidiDataException e) {
824 continue;
825 }
826 }
827
828 if( sequence==null ) {
829 throw new InvalidMidiDataException("could not get sequence from file");
830 } else {
831 return sequence;
832 }
833 }
874 public static boolean isFileTypeSupported(int fileType) {
875
876 List<MidiFileWriter> providers = getMidiFileWriters();
877
878 for (int i = 0; i < providers.size(); i++ ) {
879 MidiFileWriter writer = providers.get(i);
880 if( writer.isFileTypeSupported(fileType)) {
881 return true;
882 }
883 }
884 return false;
885 }
886
887 /**
888 * Obtains the set of MIDI file types that the system can write from the
889 * sequence specified.
890 *
891 * @param sequence the sequence for which MIDI file type support is queried
892 * @return the set of unique supported file types. If no file types are
893 * supported, returns an array of length 0.
894 * @throws NullPointerException if {@code sequence} is {@code null}
895 */
896 public static int[] getMidiFileTypes(final Sequence sequence) {
897 Objects.requireNonNull(sequence);
898
899 List<MidiFileWriter> providers = getMidiFileWriters();
900 Set<Integer> allTypes = new HashSet<>();
901
902 // gather from all the providers
903
904 for (int i = 0; i < providers.size(); i++ ) {
905 MidiFileWriter writer = providers.get(i);
906 int[] types = writer.getMidiFileTypes(sequence);
907 for (int j = 0; j < types.length; j++ ) {
908 allTypes.add(types[j]);
909 }
910 }
911 int resultTypes[] = new int[allTypes.size()];
912 int index = 0;
913 Iterator<Integer> iterator = allTypes.iterator();
914 while (iterator.hasNext()) {
915 Integer integer = iterator.next();
916 resultTypes[index++] = integer.intValue();
917 }
918 return resultTypes;
919 }
920
921 /**
922 * Indicates whether a MIDI file of the file type specified can be written
923 * from the sequence indicated.
924 *
925 * @param fileType the file type for which write capabilities are queried
926 * @param sequence the sequence for which file writing support is queried
927 * @return {@code true} if the file type is supported for this sequence,
928 * otherwise {@code false}
929 * @throws NullPointerException if {@code sequence} is {@code null}
930 */
931 public static boolean isFileTypeSupported(final int fileType,
932 final Sequence sequence) {
933 Objects.requireNonNull(sequence);
934
935 List<MidiFileWriter> providers = getMidiFileWriters();
936
937 for (int i = 0; i < providers.size(); i++ ) {
938 MidiFileWriter writer = providers.get(i);
939 if( writer.isFileTypeSupported(fileType,sequence)) {
940 return true;
941 }
942 }
943 return false;
944 }
945
946 /**
947 * Writes a stream of bytes representing a file of the MIDI file type
948 * indicated to the output stream provided.
949 *
950 * @param in sequence containing MIDI data to be written to the file
951 * @param fileType the file type of the file to be written to the output
952 * stream
953 * @param out stream to which the file data should be written
954 * @return the number of bytes written to the output stream
955 * @throws IOException if an I/O exception occurs
956 * @throws IllegalArgumentException if the file format is not supported by
957 * the system
958 * @throws NullPointerException if {@code in} or {@code out} are
959 * {@code null}
960 * @see #isFileTypeSupported(int, Sequence)
961 * @see #getMidiFileTypes(Sequence)
962 */
963 public static int write(final Sequence in, final int fileType,
964 final OutputStream out) throws IOException {
965 Objects.requireNonNull(in);
966 Objects.requireNonNull(out);
967
968 List<MidiFileWriter> providers = getMidiFileWriters();
969 //$$fb 2002-04-17: Fix for 4635287: Standard MidiFileWriter cannot write empty Sequences
970 int bytesWritten = -2;
971
972 for (int i = 0; i < providers.size(); i++ ) {
973 MidiFileWriter writer = providers.get(i);
974 if( writer.isFileTypeSupported( fileType, in ) ) {
975
976 bytesWritten = writer.write(in, fileType, out);
977 break;
978 }
979 }
980 if (bytesWritten == -2) {
981 throw new IllegalArgumentException("MIDI file type is not supported");
982 }
983 return bytesWritten;
984 }
985
986 /**
987 * Writes a stream of bytes representing a file of the MIDI file type
988 * indicated to the external file provided.
989 *
990 * @param in sequence containing MIDI data to be written to the file
991 * @param type the file type of the file to be written to the output stream
992 * @param out external file to which the file data should be written
993 * @return the number of bytes written to the file
994 * @throws IOException if an I/O exception occurs
995 * @throws IllegalArgumentException if the file type is not supported by the
996 * system
997 * @throws NullPointerException if {@code in} or {@code out} are
998 * {@code null}
999 * @see #isFileTypeSupported(int, Sequence)
1000 * @see #getMidiFileTypes(Sequence)
1001 */
1002 public static int write(final Sequence in, final int type, final File out)
1003 throws IOException {
1004 Objects.requireNonNull(in);
1005 Objects.requireNonNull(out);
1006
1007 List<MidiFileWriter> providers = getMidiFileWriters();
1008 //$$fb 2002-04-17: Fix for 4635287: Standard MidiFileWriter cannot write empty Sequences
1009 int bytesWritten = -2;
1010
1011 for (int i = 0; i < providers.size(); i++ ) {
1012 MidiFileWriter writer = providers.get(i);
1013 if( writer.isFileTypeSupported( type, in ) ) {
1014
1015 bytesWritten = writer.write(in, type, out);
1016 break;
1017 }
1018 }
1019 if (bytesWritten == -2) {
1020 throw new IllegalArgumentException("MIDI file type is not supported");
1021 }
1022 return bytesWritten;
1023 }
1024
1025 // HELPER METHODS
|