mirror of
https://github.com/2003scape/deep-c-rsc.git
synced 2024-03-22 05:49:51 -04:00
1125 lines
39 KiB
Java
1125 lines
39 KiB
Java
![]() |
/*
|
||
|
* This file is modified by Ivan Maidanski <ivmai@ivmaisoft.com>
|
||
|
* Project name: JCGO-SUNAWT (http://www.ivmaisoft.com/jcgo/)
|
||
|
**
|
||
|
* Comment: not really modified but is a part of JSound "front-end".
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
* @(#)MidiSystem.java 1.49 03/01/27
|
||
|
*
|
||
|
* Copyright 2003 Sun Microsystems, Inc. All rights reserved.
|
||
|
* SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
||
|
*/
|
||
|
|
||
|
package javax.sound.midi;
|
||
|
|
||
|
import java.io.FileInputStream;
|
||
|
import java.io.File;
|
||
|
import java.io.InputStream;
|
||
|
import java.io.OutputStream;
|
||
|
import java.io.IOException;
|
||
|
import java.util.Vector;
|
||
|
|
||
|
import java.lang.reflect.Method;
|
||
|
import java.lang.reflect.InvocationTargetException;
|
||
|
|
||
|
import java.net.URL;
|
||
|
|
||
|
import javax.sound.midi.spi.MidiFileWriter;
|
||
|
import javax.sound.midi.spi.MidiFileReader;
|
||
|
import javax.sound.midi.spi.SoundbankReader;
|
||
|
import javax.sound.midi.spi.MidiDeviceProvider;
|
||
|
|
||
|
/**
|
||
|
* The <code>MidiSystem</code> class provides access to the installed MIDI
|
||
|
* system resources, including devices such as synthesizers, sequencers, and
|
||
|
* MIDI input and output ports. A typical simple MIDI application might
|
||
|
* begin by invoking one or more <code>MidiSystem</code> methods to learn
|
||
|
* what devices are installed and to obtain the ones needed in that
|
||
|
* application.
|
||
|
* <p>
|
||
|
* The class also has methods for reading files, streams, and URLs that
|
||
|
* contain standard MIDI file data or soundbanks. You can query the
|
||
|
* <code>MidiSystem</code> for the format of a specified MIDI file.
|
||
|
* <p>
|
||
|
* You cannot instantiate a <code>MidiSystem</code>; all the methods are
|
||
|
* static.
|
||
|
*
|
||
|
* @version 1.49, 03/01/27
|
||
|
* @author Kara Kytle
|
||
|
*/
|
||
|
public class MidiSystem {
|
||
|
|
||
|
/**
|
||
|
* Private strings for default services class and method
|
||
|
*/
|
||
|
private static final String defaultServicesClassName =
|
||
|
"com.sun.media.sound.DefaultServices";
|
||
|
private static final String jdk13ServicesClassName =
|
||
|
"com.sun.media.sound.JDK13Services";
|
||
|
|
||
|
private static final String servicesMethodName =
|
||
|
"getProviders";
|
||
|
private static final Class[] servicesParamTypes =
|
||
|
new Class[] { String.class };
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Private no-args constructor for ensuring against instantiation.
|
||
|
*/
|
||
|
private MidiSystem() {
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Obtains an array of information objects representing
|
||
|
* the set of all MIDI devices available on the system.
|
||
|
* A returned information object can then be used to obtain the
|
||
|
* corresponding device object, by invoking
|
||
|
* {@link #getMidiDevice(MidiDevice.Info) getMidiDevice}.
|
||
|
*
|
||
|
* @return an array of <code>MidiDevice.Info</code> objects, one
|
||
|
* for each installed MIDI device. If no such devices are installed,
|
||
|
* an array of length 0 is returned.
|
||
|
*/
|
||
|
public static MidiDevice.Info[] getMidiDeviceInfo() {
|
||
|
return getGenericDeviceInfo( MidiDevice.class );
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Obtains the requested MIDI device.
|
||
|
*
|
||
|
* @param info a device information object representing the desired device.
|
||
|
* @return the requested device
|
||
|
* @throws MidiUnavailableException if the requested device is not available
|
||
|
* due to resource restrictions
|
||
|
* @throws IllegalArgumentException if the info object does not represent
|
||
|
* a MIDI device installed on the system
|
||
|
* @see #getMidiDeviceInfo
|
||
|
*/
|
||
|
public static MidiDevice getMidiDevice(MidiDevice.Info info) throws MidiUnavailableException {
|
||
|
return (MidiDevice)getGenericDevice( null, info );
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* re-deleted
|
||
|
*/
|
||
|
/*
|
||
|
* un-deleted, AbstractPlayer.addPlatformSynth() conflict
|
||
|
*/
|
||
|
/**
|
||
|
* Obtains an array of information objects representing
|
||
|
* the set of MIDI devices available on the system that support
|
||
|
* one or more receivers.
|
||
|
* A returned information object can then be used to obtain a
|
||
|
* receiver from the corresponding device object, by invoking
|
||
|
* {@link #getReceiver(MidiDevice.Info) getReceiver}.
|
||
|
*
|
||
|
* @return an array of <code>MidiDevice.Info</code> objects, one
|
||
|
* for each installed device that supports one or more
|
||
|
* {@link Receiver Receivers}.
|
||
|
* If no such devices are installed, an array of length
|
||
|
* 0 is returned.
|
||
|
*/
|
||
|
/*
|
||
|
public static MidiDevice.Info[] getReceiverInfo() {
|
||
|
return getGenericDeviceInfo( Receiver.class );
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
|
||
|
/*
|
||
|
* re-changed
|
||
|
*/
|
||
|
/*
|
||
|
* un-changed, AbstractPlayer.addPlatformSynth() conflict
|
||
|
*/
|
||
|
/**
|
||
|
* Obtains a MIDI receiver from an external MIDI port
|
||
|
* or other default source.
|
||
|
* @return the default MIDI receiver
|
||
|
* @throws MidiUnavailableException if the default receiver is not
|
||
|
* available due to resource restrictions
|
||
|
*/
|
||
|
public static Receiver getReceiver() throws MidiUnavailableException {
|
||
|
return ( ((MidiDevice)getGenericDevice(Receiver.class, null)).getReceiver() );
|
||
|
}
|
||
|
/*
|
||
|
public static Receiver getReceiver(MidiDevice.Info info) throws MidiUnavailableException {
|
||
|
return ( ((MidiDevice)getGenericDevice(Receiver.class, info)).getReceiver() );
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
* deleted
|
||
|
*/
|
||
|
/**
|
||
|
* Obtains an array of information objects representing
|
||
|
* the set of MIDI devices available on the system that support
|
||
|
* one or more transmitters.
|
||
|
* A returned information object can then be used to obtain a
|
||
|
* transmitter from the corresponding device object, by invoking
|
||
|
* {@link #getTransmitter(MidiDevice.Info) getTransmitter}.
|
||
|
*
|
||
|
* @return an array of <code>MidiDevice.Info</code> objects, one
|
||
|
* for each installed device that supports one or more
|
||
|
* {@link Transmitter Transmitters}.
|
||
|
* If no such devices are installed, an array of length
|
||
|
* 0 is returned.
|
||
|
*/
|
||
|
/* public static MidiDevice.Info[] getTransmitterInfo() {
|
||
|
return getGenericDeviceInfo( Transmitter.class );
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Obtains a MIDI transmitter from an external MIDI port
|
||
|
* or other default source.
|
||
|
* @return the default MIDI transmitter
|
||
|
* @throws MidiUnavailableException if the default transmitter is not
|
||
|
* available due to resource restrictions
|
||
|
*/
|
||
|
public static Transmitter getTransmitter() throws MidiUnavailableException {
|
||
|
return ( ((MidiDevice)getGenericDevice(Transmitter.class, null)).getTransmitter() );
|
||
|
}
|
||
|
/* public static Transmitter getTransmitter(MidiDevice.Info info) throws MidiUnavailableException {
|
||
|
return ( ((MidiDevice)getGenericDevice(Transmitter.class, info)).getTransmitter() );
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
* deleted
|
||
|
*/
|
||
|
/**
|
||
|
* Obtains an array of information objects representing
|
||
|
* the set of synthesizers available on the system. A
|
||
|
* returned information object can then be used to obtain the corresponding
|
||
|
* synthesizer, by invoking
|
||
|
* {@link #getSynthesizer(MidiDevice.Info) getSynthesizer}.
|
||
|
*
|
||
|
* @return an array of <code>MidiDevice.Info</code> objects, one
|
||
|
* for each installed device that is a {@link Synthesizer}.
|
||
|
* If no synthesizers are installed, an array of length
|
||
|
* 0 is returned.
|
||
|
*/
|
||
|
/* public static MidiDevice.Info[] getSynthesizerInfo() {
|
||
|
return getGenericDeviceInfo( Synthesizer.class );
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Obtains the default synthesizer.
|
||
|
* @return the default synthesizer
|
||
|
* @throws MidiUnavailableException if the synthesizer is not
|
||
|
* available due to resource restrictions
|
||
|
*/
|
||
|
public static Synthesizer getSynthesizer() throws MidiUnavailableException {
|
||
|
return (Synthesizer) getGenericDevice( Synthesizer.class, null );
|
||
|
}
|
||
|
/* public static Synthesizer getSynthesizer(MidiDevice.Info info) {
|
||
|
return (Synthesizer) getGenericDevice( Synthesizer.class, info );
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
* deleted
|
||
|
*/
|
||
|
/**
|
||
|
* Obtains an array of information objects representing
|
||
|
* the set of sequencers available on the system. A
|
||
|
* returned information object can then be used to obtain the corresponding
|
||
|
* sequencer, by invoking
|
||
|
* {@link #getSequencer(MidiDevice.Info) getSequencer}.
|
||
|
*
|
||
|
* @return an array of <code>MidiDevice.Info</code> objects, one
|
||
|
* for each installed device that is a {@link Sequencer}.
|
||
|
* If no sequencers are installed, an array of length
|
||
|
* 0 is returned.
|
||
|
*/
|
||
|
/* public static MidiDevice.Info[] getSequencerInfo() {
|
||
|
return getGenericDeviceInfo( Sequencer.class );
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Obtains the default sequencer.
|
||
|
* @return the default sequencer
|
||
|
* @throws MidiUnavailableException if the sequencer is not
|
||
|
* available due to resource restrictions
|
||
|
*/
|
||
|
public static Sequencer getSequencer() throws MidiUnavailableException {
|
||
|
return (Sequencer) getGenericDevice( Sequencer.class, null );
|
||
|
}
|
||
|
/* public static Sequencer getSequencer(MidiDevice.Info info) {
|
||
|
return (Sequencer) getGenericDevice( Sequencer.class, info );
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Constructs a MIDI sound bank by reading it from the specified stream.
|
||
|
* The stream must point to
|
||
|
* a valid MIDI soundbank file. In general, MIDI soundbank providers may
|
||
|
* need to read some data from the stream before determining whether they
|
||
|
* support it. These parsers must
|
||
|
* be able to mark the stream, read enough data to determine whether they
|
||
|
* support the stream, and, if not, reset the stream's read pointer to
|
||
|
* its original position. If the input stream does not support this,
|
||
|
* this method may fail with an IOException.
|
||
|
* @param stream the source of the sound bank data.
|
||
|
* @return the sound bank
|
||
|
* @throws InvalidMidiDataException if the stream does not point to
|
||
|
* valid MIDI soundbank data recognized by the system
|
||
|
* @throws IOException if an I/O error occurred when loading the soundbank
|
||
|
* @see InputStream#markSupported
|
||
|
* @see InputStream#mark
|
||
|
*/
|
||
|
public static Soundbank getSoundbank(InputStream stream)
|
||
|
throws InvalidMidiDataException, IOException {
|
||
|
|
||
|
SoundbankReader sp = null;
|
||
|
Soundbank s = null;
|
||
|
|
||
|
Vector providers = getSoundbankReaders();
|
||
|
|
||
|
//$$fb 2001-08-03: reverse this loop to give external providers more priority (Bug #4487550)
|
||
|
for(int i = providers.size()-1; i >= 0; i-- ) {
|
||
|
sp = (SoundbankReader)providers.elementAt(i);
|
||
|
s = sp.getSoundbank(stream);
|
||
|
|
||
|
if( s!= null) {
|
||
|
return s;
|
||
|
}
|
||
|
}
|
||
|
throw new InvalidMidiDataException("cannot get soundbank from stream");
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Constructs a <code>Soundbank</code> by reading it from the specified URL.
|
||
|
* The URL must point to a valid MIDI soundbank file.
|
||
|
*
|
||
|
* @param url the source of the sound bank data
|
||
|
* @return the sound bank
|
||
|
* @throws InvalidMidiDataException if the URL does not point to valid MIDI
|
||
|
* soundbank data recognized by the system
|
||
|
* @throws IOException if an I/O error occurred when loading the soundbank
|
||
|
*/
|
||
|
public static Soundbank getSoundbank(URL url)
|
||
|
throws InvalidMidiDataException, IOException {
|
||
|
|
||
|
SoundbankReader sp = null;
|
||
|
Soundbank s = null;
|
||
|
|
||
|
Vector providers = getSoundbankReaders();
|
||
|
|
||
|
//$$fb 2001-08-03: reverse this loop to give external providers more priority (Bug #4487550)
|
||
|
for(int i = providers.size()-1; i >= 0; i-- ) {
|
||
|
sp = (SoundbankReader)providers.elementAt(i);
|
||
|
s = sp.getSoundbank(url);
|
||
|
|
||
|
if( s!= null) {
|
||
|
return s;
|
||
|
}
|
||
|
}
|
||
|
throw new InvalidMidiDataException("cannot get soundbank from stream");
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Constructs a <code>Soundbank</code> by reading it from the specified
|
||
|
* <code>File</code>.
|
||
|
* The <code>File</code> must point to a valid MIDI soundbank file.
|
||
|
*
|
||
|
* @param file the source of the sound bank data
|
||
|
* @return the sound bank
|
||
|
* @throws InvalidMidiDataException if the <code>File</code> does not
|
||
|
* point to valid MIDI soundbank data recognized by the system
|
||
|
* @throws IOException if an I/O error occurred when loading the soundbank
|
||
|
*/
|
||
|
public static Soundbank getSoundbank(File file)
|
||
|
throws InvalidMidiDataException, IOException {
|
||
|
|
||
|
|
||
|
FileInputStream fis = new FileInputStream( file );
|
||
|
return getSoundbank( fis );
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Obtains the MIDI file format of the data in the specified input stream.
|
||
|
* The stream must point to valid MIDI file data for a file type recognized
|
||
|
* by the system.
|
||
|
* <p>
|
||
|
* This method and/or the code it invokes may need to read some data from
|
||
|
* the stream to determine whether its data format is supported. The
|
||
|
* implementation may therefore
|
||
|
* need to mark the stream, read enough data to determine whether it is in
|
||
|
* a supported format, and reset the stream's read pointer to its original
|
||
|
* position. If the input stream does not permit this set of operations,
|
||
|
* this method may fail with an <code>IOException</code>.
|
||
|
* <p>
|
||
|
* This operation can only succeed for files of a type which can be parsed
|
||
|
* by an installed file reader. It may fail with an InvalidMidiDataException
|
||
|
* even for valid files if no compatible file reader is installed. It
|
||
|
* will also fail with an InvalidMidiDataException if a compatible file reader
|
||
|
* is installed, but encounters errors while determining the file format.
|
||
|
*
|
||
|
* @param stream the input stream from which file format information
|
||
|
* should be extracted
|
||
|
* @return an <code>MidiFileFormat</code> object describing the MIDI file
|
||
|
* format
|
||
|
* @throws InvalidMidiDataException if the stream does not point to valid
|
||
|
* MIDI file data recognized by the system
|
||
|
* @throws IOException if an I/O exception occurs while accessing the
|
||
|
* stream
|
||
|
* @see #getMidiFileFormat(URL)
|
||
|
* @see #getMidiFileFormat(File)
|
||
|
* @see InputStream#markSupported
|
||
|
* @see InputStream#mark
|
||
|
*/
|
||
|
public static MidiFileFormat getMidiFileFormat(InputStream stream)
|
||
|
throws InvalidMidiDataException, IOException {
|
||
|
|
||
|
MidiFileReader providers[] = getMidiFileReaders();
|
||
|
MidiFileFormat format = null;
|
||
|
|
||
|
//$$fb 2001-08-03: reverse this loop to give external providers more priority (Bug #4487550)
|
||
|
for(int i = providers.length-1; i >= 0; i-- ) {
|
||
|
try {
|
||
|
format = providers[i].getMidiFileFormat( stream ); // throws IOException
|
||
|
break;
|
||
|
} catch (InvalidMidiDataException e) {
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if( format==null ) {
|
||
|
throw new InvalidMidiDataException("input stream is not a supported file type");
|
||
|
} else {
|
||
|
return format;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Obtains the MIDI file format of the data in the specified URL. The URL
|
||
|
* must point to valid MIDI file data for a file type recognized
|
||
|
* by the system.
|
||
|
* <p>
|
||
|
* This operation can only succeed for files of a type which can be parsed
|
||
|
* by an installed file reader. It may fail with an InvalidMidiDataException
|
||
|
* even for valid files if no compatible file reader is installed. It
|
||
|
* will also fail with an InvalidMidiDataException if a compatible file reader
|
||
|
* is installed, but encounters errors while determining the file format.
|
||
|
*
|
||
|
* @param url the URL from which file format information should be
|
||
|
* extracted
|
||
|
* @return a <code>MidiFileFormat</code> object describing the MIDI file
|
||
|
* format
|
||
|
* @throws InvalidMidiDataException if the URL does not point to valid MIDI
|
||
|
* file data recognized by the system
|
||
|
* @throws IOException if an I/O exception occurs while accessing the URL
|
||
|
*
|
||
|
* @see #getMidiFileFormat(InputStream)
|
||
|
* @see #getMidiFileFormat(File)
|
||
|
*/
|
||
|
public static MidiFileFormat getMidiFileFormat(URL url)
|
||
|
throws InvalidMidiDataException, IOException {
|
||
|
|
||
|
MidiFileReader providers[] = getMidiFileReaders();
|
||
|
MidiFileFormat format = null;
|
||
|
|
||
|
|
||
|
//$$fb 2001-08-03: reverse this loop to give external providers more priority (Bug #4487550)
|
||
|
for(int i = providers.length-1; i >= 0; i-- ) {
|
||
|
try {
|
||
|
format = providers[i].getMidiFileFormat( url ); // throws IOException
|
||
|
break;
|
||
|
} catch (InvalidMidiDataException e) {
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if( format==null ) {
|
||
|
throw new InvalidMidiDataException("url is not a supported file type");
|
||
|
} else {
|
||
|
return format;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Obtains the MIDI file format of the specified <code>File</code>. The
|
||
|
* <code>File</code> must point to valid MIDI file data for a file type
|
||
|
* recognized by the system.
|
||
|
* <p>
|
||
|
* This operation can only succeed for files of a type which can be parsed
|
||
|
* by an installed file reader. It may fail with an InvalidMidiDataException
|
||
|
* even for valid files if no compatible file reader is installed. It
|
||
|
* will also fail with an InvalidMidiDataException if a compatible file reader
|
||
|
* is installed, but encounters errors while determining the file format.
|
||
|
*
|
||
|
* @param file the <code>File</code> from which file format information
|
||
|
* should be extracted
|
||
|
* @return a <code>MidiFileFormat</code> object describing the MIDI file
|
||
|
* format
|
||
|
* @throws InvalidMidiDataException if the <code>File</code> does not point
|
||
|
* to valid MIDI file data recognized by the system
|
||
|
* @throws IOException if an I/O exception occurs while accessing the file
|
||
|
*
|
||
|
* @see #getMidiFileFormat(InputStream)
|
||
|
* @see #getMidiFileFormat(URL)
|
||
|
*/
|
||
|
public static MidiFileFormat getMidiFileFormat(File file)
|
||
|
throws InvalidMidiDataException, IOException {
|
||
|
|
||
|
MidiFileReader providers[] = getMidiFileReaders();
|
||
|
MidiFileFormat format = null;
|
||
|
|
||
|
//$$fb 2001-08-03: reverse this loop to give external providers more priority (Bug #4487550)
|
||
|
for(int i = providers.length-1; i >= 0; i-- ) {
|
||
|
try {
|
||
|
format = providers[i].getMidiFileFormat( file ); // throws IOException
|
||
|
break;
|
||
|
} catch (InvalidMidiDataException e) {
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if( format==null ) {
|
||
|
throw new InvalidMidiDataException("file is not a supported file type");
|
||
|
} else {
|
||
|
return format;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Obtains a MIDI sequence from the specified input stream. The stream must
|
||
|
* point to valid MIDI file data for a file type recognized
|
||
|
* by the system.
|
||
|
* <p>
|
||
|
* This method and/or the code it invokes may need to read some data
|
||
|
* from the stream to determine whether
|
||
|
* its data format is supported. The implementation may therefore
|
||
|
* need to mark the stream, read enough data to determine whether it is in
|
||
|
* a supported format, and reset the stream's read pointer to its original
|
||
|
* position. If the input stream does not permit this set of operations,
|
||
|
* this method may fail with an <code>IOException</code>.
|
||
|
* <p>
|
||
|
* This operation can only succeed for files of a type which can be parsed
|
||
|
* by an installed file reader. It may fail with an InvalidMidiDataException
|
||
|
* even for valid files if no compatible file reader is installed. It
|
||
|
* will also fail with an InvalidMidiDataException if a compatible file reader
|
||
|
* is installed, but encounters errors while constructing the <code>Sequence</code>
|
||
|
* object from the file data.
|
||
|
*
|
||
|
* @param stream the input stream from which the <code>Sequence</code>
|
||
|
* should be constructed
|
||
|
* @return a <code>Sequence</code> object based on the MIDI file data
|
||
|
* contained in the input stream
|
||
|
* @throws InvalidMidiDataException if the stream does not point to
|
||
|
* valid MIDI file data recognized by the system
|
||
|
* @throws IOException if an I/O exception occurs while accessing the
|
||
|
* stream
|
||
|
* @see InputStream#markSupported
|
||
|
* @see InputStream#mark
|
||
|
*/
|
||
|
public static Sequence getSequence(InputStream stream)
|
||
|
throws InvalidMidiDataException, IOException {
|
||
|
|
||
|
MidiFileReader providers[] = getMidiFileReaders();
|
||
|
Sequence sequence = null;
|
||
|
|
||
|
//$$fb 2001-08-03: reverse this loop to give external providers more priority (Bug #4487550)
|
||
|
for(int i = providers.length-1; i >= 0; i-- ) {
|
||
|
try {
|
||
|
sequence = providers[i].getSequence( stream ); // throws IOException
|
||
|
break;
|
||
|
} catch (InvalidMidiDataException e) {
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if( sequence==null ) {
|
||
|
throw new InvalidMidiDataException("could not get sequence from input stream");
|
||
|
} else {
|
||
|
return sequence;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Obtains a MIDI sequence from the specified URL. The URL must
|
||
|
* point to valid MIDI file data for a file type recognized
|
||
|
* by the system.
|
||
|
* <p>
|
||
|
* This operation can only succeed for files of a type which can be parsed
|
||
|
* by an installed file reader. It may fail with an InvalidMidiDataException
|
||
|
* even for valid files if no compatible file reader is installed. It
|
||
|
* will also fail with an InvalidMidiDataException if a compatible file reader
|
||
|
* is installed, but encounters errors while constructing the <code>Sequence</code>
|
||
|
* object from the file data.
|
||
|
*
|
||
|
* @param url the URL from which the <code>Sequence</code> should be
|
||
|
* constructed
|
||
|
* @return a <code>Sequence</code> object based on the MIDI file data
|
||
|
* pointed to by the URL
|
||
|
* @throws InvalidMidiDataException if the URL does not point to valid MIDI
|
||
|
* file data recognized by the system
|
||
|
* @throws IOException if an I/O exception occurs while accessing the URL
|
||
|
*/
|
||
|
public static Sequence getSequence(URL url)
|
||
|
throws InvalidMidiDataException, IOException {
|
||
|
|
||
|
MidiFileReader providers[] = getMidiFileReaders();
|
||
|
Sequence sequence = null;
|
||
|
|
||
|
//$$fb 2001-08-03: reverse this loop to give external providers more priority (Bug #4487550)
|
||
|
for(int i = providers.length-1; i >= 0; i-- ) {
|
||
|
try {
|
||
|
sequence = providers[i].getSequence( url ); // throws IOException
|
||
|
break;
|
||
|
} catch (InvalidMidiDataException e) {
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if( sequence==null ) {
|
||
|
throw new InvalidMidiDataException("could not get sequence from URL");
|
||
|
} else {
|
||
|
return sequence;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Obtains a MIDI sequence from the specified <code>File</code>.
|
||
|
* The <code>File</code> must point to valid MIDI file data
|
||
|
* for a file type recognized by the system.
|
||
|
* <p>
|
||
|
* This operation can only succeed for files of a type which can be parsed
|
||
|
* by an installed file reader. It may fail with an InvalidMidiDataException
|
||
|
* even for valid files if no compatible file reader is installed. It
|
||
|
* will also fail with an InvalidMidiDataException if a compatible file reader
|
||
|
* is installed, but encounters errors while constructing the <code>Sequence</code>
|
||
|
* object from the file data.
|
||
|
*
|
||
|
* @param file the <code>File</code> from which the <code>Sequence</code>
|
||
|
* should be constructed
|
||
|
* @return a <code>Sequence</code> object based on the MIDI file data
|
||
|
* pointed to by the File
|
||
|
* @throws InvalidMidiDataException if the File does not point to valid MIDI
|
||
|
* file data recognized by the system
|
||
|
* @throws IOException if an I/O exception occurs
|
||
|
*/
|
||
|
public static Sequence getSequence(File file)
|
||
|
throws InvalidMidiDataException, IOException {
|
||
|
|
||
|
MidiFileReader providers[] = getMidiFileReaders();
|
||
|
Sequence sequence = null;
|
||
|
|
||
|
//$$fb 2001-08-03: reverse this loop to give external providers more priority (Bug #4487550)
|
||
|
for(int i = providers.length-1; i >= 0; i-- ) {
|
||
|
try {
|
||
|
sequence = providers[i].getSequence( file ); // throws IOException
|
||
|
break;
|
||
|
} catch (InvalidMidiDataException e) {
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if( sequence==null ) {
|
||
|
throw new InvalidMidiDataException("could not get sequence from file");
|
||
|
} else {
|
||
|
return sequence;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Obtains the set of MIDI file types for which file writing support is
|
||
|
* provided by the system.
|
||
|
* @return array of file types. If no file types are supported,
|
||
|
* an array of length 0 is returned.
|
||
|
*/
|
||
|
public static int[] getMidiFileTypes() {
|
||
|
|
||
|
MidiFileWriter providers[] = getMidiFileWriters();
|
||
|
Vector allTypes = new Vector();
|
||
|
|
||
|
int size = 0;
|
||
|
int index = 0;
|
||
|
int types[] = null;
|
||
|
|
||
|
// gather from all the providers
|
||
|
|
||
|
for(int i=0; i<providers.length; i++ ) {
|
||
|
types = providers[i].getMidiFileTypes();
|
||
|
size += types.length;
|
||
|
allTypes.addElement( types );
|
||
|
}
|
||
|
|
||
|
// now build a new array
|
||
|
|
||
|
int types2[] = new int[size];
|
||
|
for(int i=0; i<allTypes.size(); i++ ) {
|
||
|
types = (int [])(allTypes.elementAt(i));
|
||
|
for(int j=0; j<types.length; j++ ) {
|
||
|
types2[index++] = types[j];
|
||
|
}
|
||
|
}
|
||
|
return types2;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Indicates whether file writing support for the specified MIDI file type
|
||
|
* is provided by the system.
|
||
|
* @param fileType the file type for which write capabilities are queried
|
||
|
* @return <code>true</code> if the file type is supported,
|
||
|
* otherwise <code>false</code>
|
||
|
*/
|
||
|
public static boolean isFileTypeSupported(int fileType) {
|
||
|
|
||
|
MidiFileWriter providers[] = getMidiFileWriters();
|
||
|
|
||
|
for(int i=0; i<providers.length; i++) {
|
||
|
if( providers[i].isFileTypeSupported(fileType) == true ) {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Obtains the set of MIDI file types that the system can write from the
|
||
|
* sequence specified.
|
||
|
* @param sequence the sequence for which MIDI file type support
|
||
|
* is queried
|
||
|
* @return the set of supported file types. If no file types are supported,
|
||
|
* returns an array of length 0.
|
||
|
*/
|
||
|
public static int[] getMidiFileTypes(Sequence sequence) {
|
||
|
|
||
|
MidiFileWriter providers[] = getMidiFileWriters();
|
||
|
int types[][] = new int[ providers.length ][];
|
||
|
int returnTypes[] = null;
|
||
|
int numTypes = 0;
|
||
|
int index = 0;
|
||
|
|
||
|
// Get all supported file types
|
||
|
for(int i=0; i < providers.length; i++) {
|
||
|
types[i] = providers[i].getMidiFileTypes(sequence);
|
||
|
numTypes += types[i].length;
|
||
|
}
|
||
|
// Now put them in a 1-D array
|
||
|
returnTypes = new int[ numTypes ];
|
||
|
for(int i=0; i < providers.length; i++) {
|
||
|
for(int j=0; j < types[i].length; j++) {
|
||
|
returnTypes[ index ] = types[i][j];
|
||
|
index++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return returnTypes;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Indicates whether a MIDI file of the file type specified can be written
|
||
|
* from the sequence indicated.
|
||
|
* @param fileType the file type for which write capabilities
|
||
|
* are queried
|
||
|
* @param sequence the sequence for which file writing support is queried
|
||
|
* @return <code>true</code> if the file type is supported for this
|
||
|
* sequence, otherwise <code>false</code>
|
||
|
*/
|
||
|
public static boolean isFileTypeSupported(int fileType, Sequence sequence) {
|
||
|
|
||
|
MidiFileWriter providers[] = getMidiFileWriters();
|
||
|
|
||
|
for(int i=0; i<providers.length; i++) {
|
||
|
if( providers[i].isFileTypeSupported(fileType,sequence) == true ) {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Writes a stream of bytes representing a file of the MIDI file type
|
||
|
* indicated to the output stream provided.
|
||
|
* @param in sequence containing MIDI data to be written to the file
|
||
|
* @param fileType the file type of the file to be written to the output stream
|
||
|
* @param out stream to which the file data should be written
|
||
|
* @return the number of bytes written to the output stream
|
||
|
* @throws IOException if an I/O exception occurs
|
||
|
* @throws IllegalArgumentException if the file format is not supported by
|
||
|
* the system
|
||
|
* @see #isFileTypeSupported(int, Sequence)
|
||
|
* @see #getMidiFileTypes(Sequence)
|
||
|
*/
|
||
|
public static int write(Sequence in, int fileType, OutputStream out) throws IOException {
|
||
|
|
||
|
MidiFileWriter providers[] = getMidiFileWriters();
|
||
|
//$$fb 2002-04-17: Fix for 4635287: Standard MidiFileWriter cannot write empty Sequences
|
||
|
int bytesWritten = -2;
|
||
|
|
||
|
//$$fb 2001-08-03: reverse this loop to give external providers more priority (Bug #4487550)
|
||
|
for(int i = providers.length-1; i >= 0; i-- ) {
|
||
|
if( providers[i].isFileTypeSupported( fileType, in ) == true ) {
|
||
|
|
||
|
bytesWritten = providers[i].write(in, fileType, out);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (bytesWritten == -2) {
|
||
|
throw new IllegalArgumentException("MIDI file type is not supported");
|
||
|
}
|
||
|
return bytesWritten;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Writes a stream of bytes representing a file of the MIDI file type
|
||
|
* indicated to the external file provided.
|
||
|
* @param in sequence containing MIDI data to be written to the file
|
||
|
* @param type the file type of the file to be written to the output stream
|
||
|
* @param out external file to which the file data should be written
|
||
|
* @return the number of bytes written to the file
|
||
|
* @throws IOException if an I/O exception occurs
|
||
|
* @throws IllegalArgumentException if the file type is not supported by
|
||
|
* the system
|
||
|
* @see #isFileTypeSupported(int, Sequence)
|
||
|
* @see #getMidiFileTypes(Sequence)
|
||
|
*/
|
||
|
public static int write(Sequence in, int type, File out) throws IOException {
|
||
|
|
||
|
MidiFileWriter providers[] = getMidiFileWriters();
|
||
|
//$$fb 2002-04-17: Fix for 4635287: Standard MidiFileWriter cannot write empty Sequences
|
||
|
int bytesWritten = -2;
|
||
|
|
||
|
//$$fb 2001-08-03: reverse this loop to give external providers more priority (Bug #4487550)
|
||
|
for(int i = providers.length-1; i >= 0; i-- ) {
|
||
|
if( providers[i].isFileTypeSupported( type, in ) == true ) {
|
||
|
|
||
|
bytesWritten = providers[i].write(in, type, out);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (bytesWritten == -2) {
|
||
|
throw new IllegalArgumentException("MIDI file type is not supported");
|
||
|
}
|
||
|
return bytesWritten;
|
||
|
}
|
||
|
|
||
|
|
||
|
// HELPER METHODS
|
||
|
|
||
|
private static synchronized boolean isA( Class testClass, Class targetClass ) {
|
||
|
|
||
|
return (targetClass.isAssignableFrom(testClass)) ? true : false;
|
||
|
}
|
||
|
|
||
|
|
||
|
private static Vector getMidiDeviceProviders() {
|
||
|
|
||
|
Vector providers = null;
|
||
|
|
||
|
try {
|
||
|
|
||
|
Class.forName( "sun.misc.Service" );
|
||
|
|
||
|
providers = getJDK13Services("javax.sound.midi.spi.MidiDeviceProvider");
|
||
|
|
||
|
} catch (Exception e) {
|
||
|
|
||
|
// we're not running with 1.3's SPI mechanism
|
||
|
|
||
|
providers = getDefaultServices("javax.sound.midi.spi.MidiDeviceProvider");
|
||
|
}
|
||
|
|
||
|
return providers;
|
||
|
}
|
||
|
|
||
|
private static Vector getSoundbankReaders() {
|
||
|
|
||
|
Vector providers = null;
|
||
|
|
||
|
try {
|
||
|
Class.forName( "sun.misc.Service" );
|
||
|
|
||
|
providers = getJDK13Services("javax.sound.midi.spi.SoundbankReader");
|
||
|
|
||
|
} catch (Exception e) {
|
||
|
|
||
|
// we're not running with 1.3's SPI mechanism
|
||
|
|
||
|
providers = getDefaultServices("javax.sound.midi.spi.SoundbankReader");
|
||
|
}
|
||
|
|
||
|
return providers;
|
||
|
|
||
|
}
|
||
|
|
||
|
private static MidiFileWriter[] getMidiFileWriters() {
|
||
|
|
||
|
Vector v = new Vector();
|
||
|
MidiFileWriter varray[];
|
||
|
|
||
|
try {
|
||
|
|
||
|
Class.forName( "sun.misc.Service" );
|
||
|
|
||
|
v = getJDK13Services("javax.sound.midi.spi.MidiFileWriter");
|
||
|
|
||
|
} catch (Exception e) {
|
||
|
|
||
|
// we're not running with 1.3's SPI mechanism
|
||
|
|
||
|
v = getDefaultServices("javax.sound.midi.spi.MidiFileWriter");
|
||
|
}
|
||
|
|
||
|
varray = new MidiFileWriter[ v.size() ];
|
||
|
for( int i=0; i < varray.length; i++ ) {
|
||
|
varray[i] = (MidiFileWriter)(v.elementAt(i));
|
||
|
}
|
||
|
return varray;
|
||
|
}
|
||
|
|
||
|
|
||
|
private static MidiFileReader[] getMidiFileReaders() {
|
||
|
|
||
|
Vector v = new Vector();
|
||
|
MidiFileReader varray[];
|
||
|
|
||
|
try {
|
||
|
|
||
|
Class.forName( "sun.misc.Service" );
|
||
|
|
||
|
v = getJDK13Services("javax.sound.midi.spi.MidiFileReader");
|
||
|
|
||
|
} catch (Exception e) {
|
||
|
|
||
|
// we're not running with 1.3's SPI mechanism
|
||
|
|
||
|
v = getDefaultServices("javax.sound.midi.spi.MidiFileReader");
|
||
|
}
|
||
|
|
||
|
varray = new MidiFileReader[ v.size() ];
|
||
|
for( int i=0; i < varray.length; i++ ) {
|
||
|
varray[i] = (MidiFileReader)(v.elementAt(i));
|
||
|
}
|
||
|
return varray;
|
||
|
}
|
||
|
|
||
|
|
||
|
private static MidiDevice.Info[] getGenericDeviceInfo( Class deviceClass ) {
|
||
|
|
||
|
int i;
|
||
|
int j;
|
||
|
Vector v = new Vector();
|
||
|
MidiDevice.Info[] tmpinfo;
|
||
|
MidiDevice.Info[] varray;
|
||
|
Vector v1;
|
||
|
|
||
|
v1 = getMidiDeviceProviders();
|
||
|
|
||
|
for(i = 0; i < v1.size(); i++) {
|
||
|
|
||
|
tmpinfo = ((MidiDeviceProvider) v1.elementAt(i)).getDeviceInfo();
|
||
|
|
||
|
for (j = 0; j < tmpinfo.length; j++) {
|
||
|
|
||
|
// $$kk: 10.12.99: ugh! i have wrecked this!!
|
||
|
//if( isA( tmpinfo[j].getDeviceClass(), deviceClass ) ) {
|
||
|
|
||
|
MidiDevice device = ((MidiDeviceProvider) v1.elementAt(i)).getDevice(tmpinfo[j]);
|
||
|
|
||
|
if (isA(deviceClass, Receiver.class)) {
|
||
|
if(device.getMaxReceivers() != 0) {
|
||
|
v.addElement( tmpinfo[j] );
|
||
|
}
|
||
|
} else if (isA(deviceClass, Transmitter.class)) {
|
||
|
if(device.getMaxTransmitters() != 0) {
|
||
|
v.addElement( tmpinfo[j] );
|
||
|
}
|
||
|
} else if (deviceClass.isInstance(device)) {
|
||
|
v.addElement( tmpinfo[j] );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
varray = new MidiDevice.Info[ v.size() ];
|
||
|
|
||
|
for(i = 0; i < varray.length; i++ ) {
|
||
|
varray[i] = (MidiDevice.Info)(v.elementAt(i));
|
||
|
}
|
||
|
|
||
|
return varray;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Attempts to locate and return the specified device
|
||
|
* @throws IllegalArgumentException on failure.
|
||
|
*/
|
||
|
private static Object getGenericDevice( Class deviceClass, MidiDevice.Info info) {
|
||
|
|
||
|
int i;
|
||
|
int j;
|
||
|
MidiDevice s = null;
|
||
|
MidiDevice.Info[] tmpinfo = null;
|
||
|
Vector v1 = new Vector();
|
||
|
|
||
|
v1 = getMidiDeviceProviders();
|
||
|
|
||
|
for(i = 0; i < v1.size(); i++) {
|
||
|
|
||
|
tmpinfo = ((MidiDeviceProvider) v1.elementAt(i)).getDeviceInfo();
|
||
|
|
||
|
if( info == null ) {
|
||
|
|
||
|
// $$jb: 06.04.99: Should we do more to guarantee which
|
||
|
// device is the default?
|
||
|
|
||
|
for (j = 0; j < tmpinfo.length; j++) {
|
||
|
|
||
|
// $$kk: 10.12.99: ugh! i have wrecked this!!
|
||
|
//if( isA(tmpinfo[j].getDeviceClass(), deviceClass ) ) {
|
||
|
// return ((MidiDeviceProvider) v1.elementAt(i)).getDevice(tmpinfo[j]);
|
||
|
//}
|
||
|
MidiDevice device = ((MidiDeviceProvider) v1.elementAt(i)).getDevice(tmpinfo[j]);
|
||
|
|
||
|
if (isA(deviceClass, Receiver.class)) {
|
||
|
if(device.getMaxReceivers() != 0) {
|
||
|
return device;
|
||
|
}
|
||
|
} else if (isA(deviceClass, Transmitter.class)) {
|
||
|
if(device.getMaxTransmitters() != 0) {
|
||
|
return device;
|
||
|
}
|
||
|
} else if (deviceClass.isInstance(device)) {
|
||
|
return device;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
|
||
|
for (j = 0; j < tmpinfo.length; j++) {
|
||
|
|
||
|
if( tmpinfo[j].equals( info ) ) {
|
||
|
|
||
|
// $$kk: 10.12.99: ugh! i have wrecked this!!
|
||
|
|
||
|
// $$kk: 10.12.99: shouldn't need this check?
|
||
|
//if( isA(tmpinfo[j].getDeviceClass(), deviceClass ) ) {
|
||
|
// return ((MidiDeviceProvider) v1.elementAt(i)).getDevice(tmpinfo[j]);
|
||
|
//}
|
||
|
|
||
|
MidiDevice device = ((MidiDeviceProvider) v1.elementAt(i)).getDevice(tmpinfo[j]);
|
||
|
|
||
|
if (deviceClass == null) {
|
||
|
return device;
|
||
|
}
|
||
|
|
||
|
if (isA(deviceClass, Receiver.class)) {
|
||
|
if(device.getMaxReceivers() != 0) {
|
||
|
return device;
|
||
|
}
|
||
|
} else if (isA(deviceClass, Transmitter.class)) {
|
||
|
if(device.getMaxTransmitters() != 0) {
|
||
|
return device;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
throw new IllegalArgumentException("Requested device not installed: " + info);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Obtains the set of services currently installed on the system
|
||
|
* using sun.misc.Service, the SPI mechanism in 1.3.
|
||
|
* @return a Vector of instances of providers for the requested service.
|
||
|
* If no providers are available, a vector of length 0 will be returned.
|
||
|
*/
|
||
|
|
||
|
private static Vector getJDK13Services( String serviceName ) {
|
||
|
|
||
|
Vector v = null;
|
||
|
|
||
|
try {
|
||
|
Class jdk13Services =
|
||
|
Class.forName( jdk13ServicesClassName );
|
||
|
|
||
|
Method m = jdk13Services.getMethod(
|
||
|
servicesMethodName,
|
||
|
servicesParamTypes);
|
||
|
|
||
|
Object[] arguments = new Object[] { serviceName };
|
||
|
|
||
|
v = (Vector) m.invoke(jdk13Services,arguments);
|
||
|
|
||
|
} catch(InvocationTargetException e1) {
|
||
|
v = new Vector();
|
||
|
} catch(ClassNotFoundException e2) {
|
||
|
v = new Vector();
|
||
|
} catch(IllegalAccessException e3) {
|
||
|
v = new Vector();
|
||
|
} catch(NoSuchMethodException e4) {
|
||
|
v = new Vector();
|
||
|
}
|
||
|
return v;
|
||
|
}
|
||
|
/**
|
||
|
* Obtains the default set of services currently installed on the system.
|
||
|
* This method is only invoked if sun.misc.Service is not available.
|
||
|
* @return a Vector of instances of providers for the requested service.
|
||
|
* If no providers are available, a vector of length 0 will be returned.
|
||
|
*/
|
||
|
|
||
|
private static Vector getDefaultServices( String serviceName ) {
|
||
|
|
||
|
Vector v = null;
|
||
|
|
||
|
try {
|
||
|
Class defaultServices =
|
||
|
Class.forName( defaultServicesClassName );
|
||
|
|
||
|
Method m = defaultServices.getMethod(
|
||
|
servicesMethodName,
|
||
|
servicesParamTypes);
|
||
|
|
||
|
Object[] arguments = new Object[] { serviceName };
|
||
|
|
||
|
v = (Vector) m.invoke(defaultServices,arguments);
|
||
|
|
||
|
} catch(InvocationTargetException e1) {
|
||
|
v = new Vector();
|
||
|
} catch(ClassNotFoundException e2) {
|
||
|
v = new Vector();
|
||
|
} catch(IllegalAccessException e3) {
|
||
|
v = new Vector();
|
||
|
} catch(NoSuchMethodException e4) {
|
||
|
v = new Vector();
|
||
|
}
|
||
|
return v;
|
||
|
}
|
||
|
}
|