< prev index next >

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

Print this page


   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


< prev index next >