Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.desktop/share/classes/javax/sound/midi/MidiSystem.java
41159 views
1
/*
2
* Copyright (c) 1999, 2020, 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.
59
* <p>
60
* The class also has methods for reading files, streams, and URLs that contain
61
* standard MIDI file data or soundbanks. You can query the {@code MidiSystem}
62
* for the format of a specified MIDI file.
63
* <p>
64
* You cannot instantiate a {@code MidiSystem}; all the methods are static.
65
* <p>
66
* Properties can be used to specify default MIDI devices. Both system
67
* properties and a properties file are considered. The "sound.properties"
68
* properties file is read from an implementation-specific location (typically
69
* it is the {@code conf} directory in the Java installation directory).
70
* The optional "javax.sound.config.file" system property can be used to specify
71
* the properties file that will be read as the initial configuration. If a
72
* property exists both as a system property and in the properties file, the
73
* system property takes precedence. If none is specified, a suitable default is
74
* chosen among the available devices. The syntax of the properties file is
75
* specified in {@link Properties#load(InputStream) Properties.load}. The
76
* following table lists the available property keys and which methods consider
77
* them:
78
*
79
* <table class="striped">
80
* <caption>MIDI System Property Keys</caption>
81
* <thead>
82
* <tr>
83
* <th scope="col">Property Key
84
* <th scope="col">Interface
85
* <th scope="col">Affected Method
86
* </thead>
87
* <tbody>
88
* <tr>
89
* <th scope="row">{@code javax.sound.midi.Receiver}
90
* <td>{@link Receiver}
91
* <td>{@link #getReceiver}
92
* <tr>
93
* <th scope="row">{@code javax.sound.midi.Sequencer}
94
* <td>{@link Sequencer}
95
* <td>{@link #getSequencer}
96
* <tr>
97
* <th scope="row">{@code javax.sound.midi.Synthesizer}
98
* <td>{@link Synthesizer}
99
* <td>{@link #getSynthesizer}
100
* <tr>
101
* <th scope="row">{@code javax.sound.midi.Transmitter}
102
* <td>{@link Transmitter}
103
* <td>{@link #getTransmitter}
104
* </tbody>
105
* </table>
106
*
107
* The property value consists of the provider class name and the device name,
108
* separated by the hash mark ("#"). The provider class name is the
109
* fully-qualified name of a concrete
110
* {@link MidiDeviceProvider MIDI device provider} class. The device name is
111
* matched against the {@code String} returned by the {@code getName} method of
112
* {@code MidiDevice.Info}. Either the class name, or the device name may be
113
* omitted. If only the class name is specified, the trailing hash mark is
114
* optional.
115
* <p>
116
* If the provider class is specified, and it can be successfully retrieved from
117
* the installed providers, the list of {@code MidiDevice.Info} objects is
118
* retrieved from the provider. Otherwise, or when these devices do not provide
119
* a subsequent match, the list is retrieved from {@link #getMidiDeviceInfo} to
120
* contain all available {@code MidiDevice.Info} objects.
121
* <p>
122
* If a device name is specified, the resulting list of {@code MidiDevice.Info}
123
* objects is searched: the first one with a matching name, and whose
124
* {@code MidiDevice} implements the respective interface, will be returned. If
125
* no matching {@code MidiDevice.Info} object is found, or the device name is
126
* not specified, the first suitable device from the resulting list will be
127
* returned. For Sequencer and Synthesizer, a device is suitable if it
128
* implements the respective interface; whereas for Receiver and Transmitter, a
129
* device is suitable if it implements neither Sequencer nor Synthesizer and
130
* provides at least one Receiver or Transmitter, respectively.
131
* <p>
132
* For example, the property {@code javax.sound.midi.Receiver} with a value
133
* {@code "com.sun.media.sound.MidiProvider#SunMIDI1"} will have the following
134
* consequences when {@code getReceiver} is called: if the class
135
* {@code com.sun.media.sound.MidiProvider} exists in the list of installed MIDI
136
* device providers, the first {@code Receiver} device with name
137
* {@code "SunMIDI1"} will be returned. If it cannot be found, the first
138
* {@code Receiver} from that provider will be returned, regardless of name. If
139
* there is none, the first {@code Receiver} with name {@code "SunMIDI1"} in the
140
* list of all devices (as returned by {@code getMidiDeviceInfo}) will be
141
* returned, or, if not found, the first {@code Receiver} that can be found in
142
* the list of all devices is returned. If that fails, too, a
143
* {@code MidiUnavailableException} is thrown.
144
*
145
* @author Kara Kytle
146
* @author Florian Bomers
147
* @author Matthias Pfisterer
148
*/
149
public class MidiSystem {
150
151
/**
152
* Private no-args constructor for ensuring against instantiation.
153
*/
154
private MidiSystem() {
155
}
156
157
/**
158
* Obtains an array of information objects representing the set of all MIDI
159
* devices available on the system. A returned information object can then
160
* be used to obtain the corresponding device object, by invoking
161
* {@link #getMidiDevice(MidiDevice.Info) getMidiDevice}.
162
*
163
* @return an array of {@code MidiDevice.Info} objects, one for each
164
* installed MIDI device. If no such devices are installed, an array
165
* of length 0 is returned.
166
*/
167
public static MidiDevice.Info[] getMidiDeviceInfo() {
168
final List<MidiDevice.Info> allInfos = new ArrayList<>();
169
for (final MidiDeviceProvider provider : getMidiDeviceProviders()) {
170
Collections.addAll(allInfos, provider.getDeviceInfo());
171
}
172
return allInfos.toArray(new MidiDevice.Info[allInfos.size()]);
173
}
174
175
/**
176
* Obtains the requested MIDI device.
177
*
178
* @param info a device information object representing the desired device
179
* @return the requested device
180
* @throws MidiUnavailableException if the requested device is not available
181
* due to resource restrictions
182
* @throws IllegalArgumentException if the info object does not represent a
183
* MIDI device installed on the system
184
* @throws NullPointerException if {@code info} is {@code null}
185
* @see #getMidiDeviceInfo
186
*/
187
public static MidiDevice getMidiDevice(final MidiDevice.Info info)
188
throws MidiUnavailableException {
189
Objects.requireNonNull(info);
190
for (final MidiDeviceProvider provider : getMidiDeviceProviders()) {
191
if (provider.isDeviceSupported(info)) {
192
return provider.getDevice(info);
193
}
194
}
195
throw new IllegalArgumentException(String.format(
196
"Requested device not installed: %s", info));
197
}
198
199
/**
200
* Obtains a MIDI receiver from an external MIDI port or other default
201
* device. The returned receiver always implements the
202
* {@code MidiDeviceReceiver} interface.
203
* <p>
204
* If the system property {@code javax.sound.midi.Receiver} is defined or it
205
* is defined in the file "sound.properties", it is used to identify the
206
* device that provides the default receiver. For details, refer to the
207
* {@link MidiSystem class description}.
208
* <p>
209
* If a suitable MIDI port is not available, the Receiver is retrieved from
210
* an installed synthesizer.
211
* <p>
212
* If a native receiver provided by the default device does not implement
213
* the {@code MidiDeviceReceiver} interface, it will be wrapped in a wrapper
214
* class that implements the {@code MidiDeviceReceiver} interface. The
215
* corresponding {@code Receiver} method calls will be forwarded to the
216
* native receiver.
217
* <p>
218
* If this method returns successfully, the {@link MidiDevice MidiDevice}
219
* the {@code Receiver} belongs to is opened implicitly, if it is not
220
* already open. It is possible to close an implicitly opened device by
221
* calling {@link Receiver#close close} on the returned {@code Receiver}.
222
* All open {@code Receiver} instances have to be closed in order to release
223
* system resources hold by the {@code MidiDevice}. For a detailed
224
* description of open/close behaviour see the class description of
225
* {@link MidiDevice MidiDevice}.
226
*
227
* @return the default MIDI receiver
228
* @throws MidiUnavailableException if the default receiver is not available
229
* due to resource restrictions, or no device providing receivers is
230
* installed in the system
231
*/
232
public static Receiver getReceiver() throws MidiUnavailableException {
233
// may throw MidiUnavailableException
234
MidiDevice device = getDefaultDeviceWrapper(Receiver.class);
235
Receiver receiver;
236
if (device instanceof ReferenceCountingDevice) {
237
receiver = ((ReferenceCountingDevice) device).getReceiverReferenceCounting();
238
} else {
239
receiver = device.getReceiver();
240
}
241
if (!(receiver instanceof MidiDeviceReceiver)) {
242
receiver = new MidiDeviceReceiverEnvelope(device, receiver);
243
}
244
return receiver;
245
}
246
247
/**
248
* Obtains a MIDI transmitter from an external MIDI port or other default
249
* source. The returned transmitter always implements the
250
* {@code MidiDeviceTransmitter} interface.
251
* <p>
252
* If the system property {@code javax.sound.midi.Transmitter} is defined or
253
* it is defined in the file "sound.properties", it is used to identify the
254
* device that provides the default transmitter. For details, refer to the
255
* {@link MidiSystem class description}.
256
* <p>
257
* If a native transmitter provided by the default device does not implement
258
* the {@code MidiDeviceTransmitter} interface, it will be wrapped in a
259
* wrapper class that implements the {@code MidiDeviceTransmitter}
260
* interface. The corresponding {@code Transmitter} method calls will be
261
* forwarded to the native transmitter.
262
* <p>
263
* If this method returns successfully, the {@link MidiDevice MidiDevice}
264
* the {@code Transmitter} belongs to is opened implicitly, if it is not
265
* already open. It is possible to close an implicitly opened device by
266
* calling {@link Transmitter#close close} on the returned
267
* {@code Transmitter}. All open {@code Transmitter} instances have to be
268
* closed in order to release system resources hold by the
269
* {@code MidiDevice}. For a detailed description of open/close behaviour
270
* see the class description of {@link MidiDevice MidiDevice}.
271
*
272
* @return the default MIDI transmitter
273
* @throws MidiUnavailableException if the default transmitter is not
274
* available due to resource restrictions, or no device providing
275
* transmitters is installed in the system
276
*/
277
public static Transmitter getTransmitter() throws MidiUnavailableException {
278
// may throw MidiUnavailableException
279
MidiDevice device = getDefaultDeviceWrapper(Transmitter.class);
280
Transmitter transmitter;
281
if (device instanceof ReferenceCountingDevice) {
282
transmitter = ((ReferenceCountingDevice) device).getTransmitterReferenceCounting();
283
} else {
284
transmitter = device.getTransmitter();
285
}
286
if (!(transmitter instanceof MidiDeviceTransmitter)) {
287
transmitter = new MidiDeviceTransmitterEnvelope(device, transmitter);
288
}
289
return transmitter;
290
}
291
292
/**
293
* Obtains the default synthesizer.
294
* <p>
295
* If the system property {@code javax.sound.midi.Synthesizer} is defined or
296
* it is defined in the file "sound.properties", it is used to identify the
297
* default synthesizer. For details, refer to the
298
* {@link MidiSystem class description}.
299
*
300
* @return the default synthesizer
301
* @throws MidiUnavailableException if the synthesizer is not available due
302
* to resource restrictions, or no synthesizer is installed in the
303
* system
304
*/
305
public static Synthesizer getSynthesizer() throws MidiUnavailableException {
306
// may throw MidiUnavailableException
307
return (Synthesizer) getDefaultDeviceWrapper(Synthesizer.class);
308
}
309
310
/**
311
* Obtains the default {@code Sequencer}, connected to a default device. The
312
* returned {@code Sequencer} instance is connected to the default
313
* {@code Synthesizer}, as returned by {@link #getSynthesizer}. If there is
314
* no {@code Synthesizer} available, or the default {@code Synthesizer}
315
* cannot be opened, the {@code sequencer} is connected to the default
316
* {@code Receiver}, as returned by {@link #getReceiver}. The connection is
317
* made by retrieving a {@code Transmitter} instance from the
318
* {@code Sequencer} and setting its {@code Receiver}. Closing and
319
* re-opening the sequencer will restore the connection to the default
320
* device.
321
* <p>
322
* This method is equivalent to calling {@code getSequencer(true)}.
323
* <p>
324
* If the system property {@code javax.sound.midi.Sequencer} is defined or
325
* it is defined in the file "sound.properties", it is used to identify the
326
* default sequencer. For details, refer to the
327
* {@link MidiSystem class description}.
328
*
329
* @return the default sequencer, connected to a default Receiver
330
* @throws MidiUnavailableException if the sequencer is not available due to
331
* resource restrictions, or there is no {@code Receiver} available
332
* by any installed {@code MidiDevice}, or no sequencer is installed
333
* in the system
334
* @see #getSequencer(boolean)
335
* @see #getSynthesizer
336
* @see #getReceiver
337
*/
338
public static Sequencer getSequencer() throws MidiUnavailableException {
339
return getSequencer(true);
340
}
341
342
/**
343
* Obtains the default {@code Sequencer}, optionally connected to a default
344
* device.
345
* <p>
346
* If {@code connected} is true, the returned {@code Sequencer} instance is
347
* connected to the default {@code Synthesizer}, as returned by
348
* {@link #getSynthesizer}. If there is no {@code Synthesizer} available, or
349
* the default {@code Synthesizer} cannot be opened, the {@code sequencer}
350
* is connected to the default {@code Receiver}, as returned by
351
* {@link #getReceiver}. The connection is made by retrieving a
352
* {@code Transmitter} instance from the {@code Sequencer} and setting its
353
* {@code Receiver}. Closing and re-opening the sequencer will restore the
354
* connection to the default device.
355
* <p>
356
* If {@code connected} is false, the returned {@code Sequencer} instance is
357
* not connected, it has no open {@code Transmitters}. In order to play the
358
* sequencer on a MIDI device, or a {@code Synthesizer}, it is necessary to
359
* get a {@code Transmitter} and set its {@code Receiver}.
360
* <p>
361
* If the system property {@code javax.sound.midi.Sequencer} is defined or
362
* it is defined in the file "sound.properties", it is used to identify the
363
* default sequencer. For details, refer to the
364
* {@link MidiSystem class description}.
365
*
366
* @param connected whether or not the returned {@code Sequencer} is
367
* connected to the default {@code Synthesizer}
368
* @return the default sequencer
369
* @throws MidiUnavailableException if the sequencer is not available due to
370
* resource restrictions, or no sequencer is installed in the
371
* system, or if {@code connected} is true, and there is no
372
* {@code Receiver} available by any installed {@code MidiDevice}
373
* @see #getSynthesizer
374
* @see #getReceiver
375
* @since 1.5
376
*/
377
public static Sequencer getSequencer(boolean connected)
378
throws MidiUnavailableException {
379
Sequencer seq = (Sequencer) getDefaultDeviceWrapper(Sequencer.class);
380
381
if (connected) {
382
// IMPORTANT: this code needs to be synch'ed with
383
// all AutoConnectSequencer instances,
384
// (e.g. RealTimeSequencer) because the
385
// same algorithm for synth retrieval
386
// needs to be used!
387
388
Receiver rec = null;
389
MidiUnavailableException mue = null;
390
391
// first try to connect to the default synthesizer
392
try {
393
Synthesizer synth = getSynthesizer();
394
if (synth instanceof ReferenceCountingDevice) {
395
rec = ((ReferenceCountingDevice) synth).getReceiverReferenceCounting();
396
} else {
397
synth.open();
398
try {
399
rec = synth.getReceiver();
400
} finally {
401
// make sure that the synth is properly closed
402
if (rec == null) {
403
synth.close();
404
}
405
}
406
}
407
} catch (MidiUnavailableException e) {
408
// something went wrong with synth
409
if (e instanceof MidiUnavailableException) {
410
mue = e;
411
}
412
}
413
if (rec == null) {
414
// then try to connect to the default Receiver
415
try {
416
rec = MidiSystem.getReceiver();
417
} catch (Exception e) {
418
// something went wrong. Nothing to do then!
419
if (e instanceof MidiUnavailableException) {
420
mue = (MidiUnavailableException) e;
421
}
422
}
423
}
424
if (rec != null) {
425
seq.getTransmitter().setReceiver(rec);
426
if (seq instanceof AutoConnectSequencer) {
427
((AutoConnectSequencer) seq).setAutoConnect(rec);
428
}
429
} else {
430
if (mue != null) {
431
throw mue;
432
}
433
throw new MidiUnavailableException("no receiver available");
434
}
435
}
436
return seq;
437
}
438
439
/**
440
* Constructs a MIDI sound bank by reading it from the specified stream. The
441
* stream must point to a valid MIDI soundbank file. In general, MIDI
442
* soundbank providers may need to read some data from the stream before
443
* determining whether they support it. These parsers must be able to mark
444
* the stream, read enough data to determine whether they support the
445
* stream, and, if not, reset the stream's read pointer to its original
446
* position. If the input stream does not support this, this method may fail
447
* with an {@code IOException}.
448
*
449
* @param stream the source of the sound bank data
450
* @return the sound bank
451
* @throws InvalidMidiDataException if the stream does not point to valid
452
* MIDI soundbank data recognized by the system
453
* @throws IOException if an I/O error occurred when loading the soundbank
454
* @throws NullPointerException if {@code stream} is {@code null}
455
* @see InputStream#markSupported
456
* @see InputStream#mark
457
*/
458
public static Soundbank getSoundbank(final InputStream stream)
459
throws InvalidMidiDataException, IOException {
460
Objects.requireNonNull(stream);
461
462
SoundbankReader sp = null;
463
Soundbank s = null;
464
465
List<SoundbankReader> providers = getSoundbankReaders();
466
467
for(int i = 0; i < providers.size(); i++) {
468
sp = providers.get(i);
469
s = sp.getSoundbank(stream);
470
471
if( s!= null) {
472
return s;
473
}
474
}
475
throw new InvalidMidiDataException("cannot get soundbank from stream");
476
477
}
478
479
/**
480
* Constructs a {@code Soundbank} by reading it from the specified URL. The
481
* URL must point to a valid MIDI soundbank file.
482
*
483
* @param url the source of the sound bank data
484
* @return the sound bank
485
* @throws InvalidMidiDataException if the URL does not point to valid MIDI
486
* soundbank data recognized by the system
487
* @throws IOException if an I/O error occurred when loading the soundbank
488
* @throws NullPointerException if {@code url} is {@code null}
489
*/
490
public static Soundbank getSoundbank(final URL url)
491
throws InvalidMidiDataException, IOException {
492
Objects.requireNonNull(url);
493
494
SoundbankReader sp = null;
495
Soundbank s = null;
496
497
List<SoundbankReader> providers = getSoundbankReaders();
498
499
for(int i = 0; i < providers.size(); i++) {
500
sp = providers.get(i);
501
s = sp.getSoundbank(url);
502
503
if( s!= null) {
504
return s;
505
}
506
}
507
throw new InvalidMidiDataException("cannot get soundbank from stream");
508
509
}
510
511
/**
512
* Constructs a {@code Soundbank} by reading it from the specified
513
* {@code File}. The {@code File} must point to a valid MIDI soundbank file.
514
*
515
* @param file the source of the sound bank data
516
* @return the sound bank
517
* @throws InvalidMidiDataException if the {@code File} does not point to
518
* valid MIDI soundbank data recognized by the system
519
* @throws IOException if an I/O error occurred when loading the soundbank
520
* @throws NullPointerException if {@code file} is {@code null}
521
*/
522
public static Soundbank getSoundbank(final File file)
523
throws InvalidMidiDataException, IOException {
524
Objects.requireNonNull(file);
525
526
SoundbankReader sp = null;
527
Soundbank s = null;
528
529
List<SoundbankReader> providers = getSoundbankReaders();
530
531
for(int i = 0; i < providers.size(); i++) {
532
sp = providers.get(i);
533
s = sp.getSoundbank(file);
534
535
if( s!= null) {
536
return s;
537
}
538
}
539
throw new InvalidMidiDataException("cannot get soundbank from stream");
540
}
541
542
/**
543
* Obtains the MIDI file format of the data in the specified input stream.
544
* The stream must point to valid MIDI file data for a file type recognized
545
* by the system.
546
* <p>
547
* This method and/or the code it invokes may need to read some data from
548
* the stream to determine whether its data format is supported. The
549
* implementation may therefore need to mark the stream, read enough data to
550
* determine whether it is in a supported format, and reset the stream's
551
* read pointer to its original position. If the input stream does not
552
* permit this set of operations, this method may fail with an
553
* {@code IOException}.
554
* <p>
555
* This operation can only succeed for files of a type which can be parsed
556
* by an installed file reader. It may fail with an
557
* {@code InvalidMidiDataException} even for valid files if no compatible
558
* file reader is installed. It will also fail with an
559
* {@code InvalidMidiDataException} if a compatible file reader is
560
* installed, but encounters errors while determining the file format.
561
*
562
* @param stream the input stream from which file format information should
563
* be extracted
564
* @return an {@code MidiFileFormat} object describing the MIDI file format
565
* @throws InvalidMidiDataException if the stream does not point to valid
566
* MIDI file data recognized by the system
567
* @throws IOException if an I/O exception occurs while accessing the 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
}
689
690
/**
691
* Obtains a MIDI sequence from the specified input stream. The stream must
692
* point to valid MIDI file data for a file type recognized by the system.
693
* <p>
694
* This method and/or the code it invokes may need to read some data from
695
* the stream to determine whether its data format is supported. The
696
* implementation may therefore need to mark the stream, read enough data to
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
}
788
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
}
834
835
/**
836
* Obtains the set of MIDI file types for which file writing support is
837
* provided by the system.
838
*
839
* @return array of unique file types. If no file types are supported, an
840
* array of length 0 is returned.
841
*/
842
public static int[] getMidiFileTypes() {
843
844
List<MidiFileWriter> providers = getMidiFileWriters();
845
Set<Integer> allTypes = new HashSet<>();
846
847
// gather from all the providers
848
849
for (int i = 0; i < providers.size(); i++ ) {
850
MidiFileWriter writer = providers.get(i);
851
int[] types = writer.getMidiFileTypes();
852
for (int j = 0; j < types.length; j++ ) {
853
allTypes.add(types[j]);
854
}
855
}
856
int[] resultTypes = new int[allTypes.size()];
857
int index = 0;
858
for (Integer integer : allTypes) {
859
resultTypes[index++] = integer.intValue();
860
}
861
return resultTypes;
862
}
863
864
/**
865
* Indicates whether file writing support for the specified MIDI file type
866
* is provided by the system.
867
*
868
* @param fileType the file type for which write capabilities are queried
869
* @return {@code true} if the file type is supported, otherwise
870
* {@code false}
871
*/
872
public static boolean isFileTypeSupported(int fileType) {
873
874
List<MidiFileWriter> providers = getMidiFileWriters();
875
876
for (int i = 0; i < providers.size(); i++ ) {
877
MidiFileWriter writer = providers.get(i);
878
if( writer.isFileTypeSupported(fileType)) {
879
return true;
880
}
881
}
882
return false;
883
}
884
885
/**
886
* Obtains the set of MIDI file types that the system can write from the
887
* sequence specified.
888
*
889
* @param sequence the sequence for which MIDI file type support is queried
890
* @return the set of unique supported file types. If no file types are
891
* supported, returns an array of length 0.
892
* @throws NullPointerException if {@code sequence} is {@code null}
893
*/
894
public static int[] getMidiFileTypes(final Sequence sequence) {
895
Objects.requireNonNull(sequence);
896
897
List<MidiFileWriter> providers = getMidiFileWriters();
898
Set<Integer> allTypes = new HashSet<>();
899
900
// gather from all the providers
901
902
for (int i = 0; i < providers.size(); i++ ) {
903
MidiFileWriter writer = providers.get(i);
904
int[] types = writer.getMidiFileTypes(sequence);
905
for (int j = 0; j < types.length; j++ ) {
906
allTypes.add(types[j]);
907
}
908
}
909
int[] resultTypes = new int[allTypes.size()];
910
int index = 0;
911
for (Integer integer : allTypes) {
912
resultTypes[index++] = integer.intValue();
913
}
914
return resultTypes;
915
}
916
917
/**
918
* Indicates whether a MIDI file of the file type specified can be written
919
* from the sequence indicated.
920
*
921
* @param fileType the file type for which write capabilities are queried
922
* @param sequence the sequence for which file writing support is queried
923
* @return {@code true} if the file type is supported for this sequence,
924
* otherwise {@code false}
925
* @throws NullPointerException if {@code sequence} is {@code null}
926
*/
927
public static boolean isFileTypeSupported(final int fileType,
928
final Sequence sequence) {
929
Objects.requireNonNull(sequence);
930
931
List<MidiFileWriter> providers = getMidiFileWriters();
932
933
for (int i = 0; i < providers.size(); i++ ) {
934
MidiFileWriter writer = providers.get(i);
935
if( writer.isFileTypeSupported(fileType,sequence)) {
936
return true;
937
}
938
}
939
return false;
940
}
941
942
/**
943
* Writes a stream of bytes representing a file of the MIDI file type
944
* indicated to the output stream provided.
945
*
946
* @param in sequence containing MIDI data to be written to the file
947
* @param fileType the file type of the file to be written to the output
948
* stream
949
* @param out stream to which the file data should be written
950
* @return the number of bytes written to the output stream
951
* @throws IOException if an I/O exception occurs
952
* @throws IllegalArgumentException if the file format is not supported by
953
* the system
954
* @throws NullPointerException if {@code in} or {@code out} are
955
* {@code null}
956
* @see #isFileTypeSupported(int, Sequence)
957
* @see #getMidiFileTypes(Sequence)
958
*/
959
public static int write(final Sequence in, final int fileType,
960
final OutputStream out) throws IOException {
961
Objects.requireNonNull(in);
962
Objects.requireNonNull(out);
963
964
List<MidiFileWriter> providers = getMidiFileWriters();
965
//$$fb 2002-04-17: Fix for 4635287: Standard MidiFileWriter cannot write empty Sequences
966
int bytesWritten = -2;
967
968
for (int i = 0; i < providers.size(); i++ ) {
969
MidiFileWriter writer = providers.get(i);
970
if( writer.isFileTypeSupported( fileType, in ) ) {
971
972
bytesWritten = writer.write(in, fileType, out);
973
break;
974
}
975
}
976
if (bytesWritten == -2) {
977
throw new IllegalArgumentException("MIDI file type is not supported");
978
}
979
return bytesWritten;
980
}
981
982
/**
983
* Writes a stream of bytes representing a file of the MIDI file type
984
* indicated to the external file provided.
985
*
986
* @param in sequence containing MIDI data to be written to the file
987
* @param type the file type of the file to be written to the output stream
988
* @param out external file to which the file data should be written
989
* @return the number of bytes written to the file
990
* @throws IOException if an I/O exception occurs
991
* @throws IllegalArgumentException if the file type is not supported by the
992
* system
993
* @throws NullPointerException if {@code in} or {@code out} are
994
* {@code null}
995
* @see #isFileTypeSupported(int, Sequence)
996
* @see #getMidiFileTypes(Sequence)
997
*/
998
public static int write(final Sequence in, final int type, final File out)
999
throws IOException {
1000
Objects.requireNonNull(in);
1001
Objects.requireNonNull(out);
1002
1003
List<MidiFileWriter> providers = getMidiFileWriters();
1004
//$$fb 2002-04-17: Fix for 4635287: Standard MidiFileWriter cannot write empty Sequences
1005
int bytesWritten = -2;
1006
1007
for (int i = 0; i < providers.size(); i++ ) {
1008
MidiFileWriter writer = providers.get(i);
1009
if( writer.isFileTypeSupported( type, in ) ) {
1010
1011
bytesWritten = writer.write(in, type, out);
1012
break;
1013
}
1014
}
1015
if (bytesWritten == -2) {
1016
throw new IllegalArgumentException("MIDI file type is not supported");
1017
}
1018
return bytesWritten;
1019
}
1020
1021
// HELPER METHODS
1022
1023
/**
1024
* Obtains the list of MidiDeviceProviders installed on the system.
1025
*
1026
* @return the list of MidiDeviceProviders installed on the system
1027
*/
1028
@SuppressWarnings("unchecked")
1029
private static List<MidiDeviceProvider> getMidiDeviceProviders() {
1030
return (List<MidiDeviceProvider>) getProviders(MidiDeviceProvider.class);
1031
}
1032
1033
/**
1034
* Obtains the list of SoundbankReaders installed on the system.
1035
*
1036
* @return the list of SoundbankReaders installed on the system
1037
*/
1038
@SuppressWarnings("unchecked")
1039
private static List<SoundbankReader> getSoundbankReaders() {
1040
return (List<SoundbankReader>) getProviders(SoundbankReader.class);
1041
}
1042
1043
/**
1044
* Obtains the list of MidiFileWriters installed on the system.
1045
*
1046
* @return the list of MidiFileWriters installed on the system
1047
*/
1048
@SuppressWarnings("unchecked")
1049
private static List<MidiFileWriter> getMidiFileWriters() {
1050
return (List<MidiFileWriter>) getProviders(MidiFileWriter.class);
1051
}
1052
1053
/**
1054
* Obtains the list of MidiFileReaders installed on the system.
1055
*
1056
* @return the list of MidiFileReaders installed on the system
1057
*/
1058
@SuppressWarnings("unchecked")
1059
private static List<MidiFileReader> getMidiFileReaders() {
1060
return (List<MidiFileReader>) getProviders(MidiFileReader.class);
1061
}
1062
1063
/**
1064
* Attempts to locate and return a default MidiDevice of the specified type.
1065
* This method wraps {@link #getDefaultDevice}. It catches the
1066
* {@code IllegalArgumentException} thrown by {@code getDefaultDevice} and
1067
* instead throws a {@code MidiUnavailableException}, with the catched
1068
* exception chained.
1069
*
1070
* @param deviceClass The requested device type, one of Synthesizer.class,
1071
* Sequencer.class, Receiver.class or Transmitter.class
1072
* @return default MidiDevice of the specified type
1073
* @throws MidiUnavailableException on failure
1074
*/
1075
private static MidiDevice getDefaultDeviceWrapper(Class<?> deviceClass)
1076
throws MidiUnavailableException{
1077
try {
1078
return getDefaultDevice(deviceClass);
1079
} catch (IllegalArgumentException iae) {
1080
MidiUnavailableException mae = new MidiUnavailableException();
1081
mae.initCause(iae);
1082
throw mae;
1083
}
1084
}
1085
1086
/**
1087
* Attempts to locate and return a default MidiDevice of the specified type.
1088
*
1089
* @param deviceClass The requested device type, one of Synthesizer.class,
1090
* Sequencer.class, Receiver.class or Transmitter.class
1091
* @return default MidiDevice of the specified type.
1092
* @throws IllegalArgumentException on failure
1093
*/
1094
private static MidiDevice getDefaultDevice(Class<?> deviceClass) {
1095
List<MidiDeviceProvider> providers = getMidiDeviceProviders();
1096
String providerClassName = JDK13Services.getDefaultProviderClassName(deviceClass);
1097
String instanceName = JDK13Services.getDefaultInstanceName(deviceClass);
1098
MidiDevice device;
1099
1100
if (providerClassName != null) {
1101
MidiDeviceProvider defaultProvider = getNamedProvider(providerClassName, providers);
1102
if (defaultProvider != null) {
1103
if (instanceName != null) {
1104
device = getNamedDevice(instanceName, defaultProvider, deviceClass);
1105
if (device != null) {
1106
return device;
1107
}
1108
}
1109
device = getFirstDevice(defaultProvider, deviceClass);
1110
if (device != null) {
1111
return device;
1112
}
1113
}
1114
}
1115
1116
/*
1117
* - Provider class not specified or cannot be found, or
1118
* - provider class specified, and no appropriate device available, or
1119
* - provider class and instance specified and instance cannot be found
1120
* or is not appropriate
1121
*/
1122
if (instanceName != null) {
1123
device = getNamedDevice(instanceName, providers, deviceClass);
1124
if (device != null) {
1125
return device;
1126
}
1127
}
1128
1129
/*
1130
* No defaults are specified, or if something is specified, everything
1131
* failed
1132
*/
1133
device = getFirstDevice(providers, deviceClass);
1134
if (device != null) {
1135
return device;
1136
}
1137
throw new IllegalArgumentException("Requested device not installed");
1138
}
1139
1140
/**
1141
* Return a MidiDeviceProvider of a given class from the list of
1142
* MidiDeviceProviders.
1143
*
1144
* @param providerClassName The class name of the provider to be returned
1145
* @param providers The list of MidiDeviceProviders that is searched
1146
* @return A MidiDeviceProvider of the requested class, or null if none is
1147
* found
1148
*/
1149
private static MidiDeviceProvider getNamedProvider(String providerClassName,
1150
List<MidiDeviceProvider> providers) {
1151
for(int i = 0; i < providers.size(); i++) {
1152
MidiDeviceProvider provider = providers.get(i);
1153
if (provider.getClass().getName().equals(providerClassName)) {
1154
return provider;
1155
}
1156
}
1157
return null;
1158
}
1159
1160
/**
1161
* Return a MidiDevice with a given name from a given MidiDeviceProvider.
1162
*
1163
* @param deviceName The name of the MidiDevice to be returned
1164
* @param provider The MidiDeviceProvider to check for MidiDevices
1165
* @param deviceClass The requested device type, one of Synthesizer.class,
1166
* Sequencer.class, Receiver.class or Transmitter.class
1167
* @return A MidiDevice matching the requirements, or null if none is found
1168
*/
1169
private static MidiDevice getNamedDevice(String deviceName,
1170
MidiDeviceProvider provider,
1171
Class<?> deviceClass) {
1172
MidiDevice device;
1173
// try to get MIDI port
1174
device = getNamedDevice(deviceName, provider, deviceClass,
1175
false, false);
1176
if (device != null) {
1177
return device;
1178
}
1179
1180
if (deviceClass == Receiver.class) {
1181
// try to get Synthesizer
1182
device = getNamedDevice(deviceName, provider, deviceClass,
1183
true, false);
1184
if (device != null) {
1185
return device;
1186
}
1187
}
1188
1189
return null;
1190
}
1191
1192
/**
1193
* Return a MidiDevice with a given name from a given MidiDeviceProvider.
1194
*
1195
* @param deviceName The name of the MidiDevice to be returned
1196
* @param provider The MidiDeviceProvider to check for MidiDevices
1197
* @param deviceClass The requested device type, one of Synthesizer.class,
1198
* Sequencer.class, Receiver.class or Transmitter.class
1199
* @param allowSynthesizer if true, Synthesizers are considered
1200
* appropriate. Otherwise only pure MidiDevices are considered
1201
* appropriate (unless allowSequencer is true). This flag only has
1202
* an effect for deviceClass Receiver and Transmitter. For other
1203
* device classes (Sequencer and Synthesizer), this flag has no
1204
* effect.
1205
* @param allowSequencer if true, Sequencers are considered appropriate.
1206
* Otherwise only pure MidiDevices are considered appropriate
1207
* (unless allowSynthesizer is true). This flag only has an effect
1208
* for deviceClass Receiver and Transmitter. For other device
1209
* classes (Sequencer and Synthesizer), this flag has no effect.
1210
* @return A MidiDevice matching the requirements, or null if none is found
1211
*/
1212
private static MidiDevice getNamedDevice(String deviceName,
1213
MidiDeviceProvider provider,
1214
Class<?> deviceClass,
1215
boolean allowSynthesizer,
1216
boolean allowSequencer) {
1217
MidiDevice.Info[] infos = provider.getDeviceInfo();
1218
for (int i = 0; i < infos.length; i++) {
1219
if (infos[i].getName().equals(deviceName)) {
1220
MidiDevice device = provider.getDevice(infos[i]);
1221
if (isAppropriateDevice(device, deviceClass,
1222
allowSynthesizer, allowSequencer)) {
1223
return device;
1224
}
1225
}
1226
}
1227
return null;
1228
}
1229
1230
/**
1231
* Return a MidiDevice with a given name from a list of MidiDeviceProviders.
1232
*
1233
* @param deviceName The name of the MidiDevice to be returned
1234
* @param providers The List of MidiDeviceProviders to check for
1235
* MidiDevices
1236
* @param deviceClass The requested device type, one of Synthesizer.class,
1237
* Sequencer.class, Receiver.class or Transmitter.class
1238
* @return A Mixer matching the requirements, or null if none is found
1239
*/
1240
private static MidiDevice getNamedDevice(String deviceName,
1241
List<MidiDeviceProvider> providers,
1242
Class<?> deviceClass) {
1243
MidiDevice device;
1244
// try to get MIDI port
1245
device = getNamedDevice(deviceName, providers, deviceClass,
1246
false, false);
1247
if (device != null) {
1248
return device;
1249
}
1250
1251
if (deviceClass == Receiver.class) {
1252
// try to get Synthesizer
1253
device = getNamedDevice(deviceName, providers, deviceClass,
1254
true, false);
1255
if (device != null) {
1256
return device;
1257
}
1258
}
1259
1260
return null;
1261
}
1262
1263
/**
1264
* Return a MidiDevice with a given name from a list of MidiDeviceProviders.
1265
*
1266
* @param deviceName The name of the MidiDevice to be returned
1267
* @param providers The List of MidiDeviceProviders to check for
1268
* MidiDevices
1269
* @param deviceClass The requested device type, one of Synthesizer.class,
1270
* Sequencer.class, Receiver.class or Transmitter.class
1271
* @param allowSynthesizer if true, Synthesizers are considered
1272
* appropriate. Otherwise only pure MidiDevices are considered
1273
* appropriate (unless allowSequencer is true). This flag only has
1274
* an effect for deviceClass Receiver and Transmitter. For other
1275
* device classes (Sequencer and Synthesizer), this flag has no
1276
* effect.
1277
* @param allowSequencer if true, Sequencers are considered appropriate.
1278
* Otherwise only pure MidiDevices are considered appropriate
1279
* (unless allowSynthesizer is true). This flag only has an effect
1280
* for deviceClass Receiver and Transmitter. For other device
1281
* classes (Sequencer and Synthesizer), this flag has no effect.
1282
* @return A Mixer matching the requirements, or null if none is found
1283
*/
1284
private static MidiDevice getNamedDevice(String deviceName,
1285
List<MidiDeviceProvider> providers,
1286
Class<?> deviceClass,
1287
boolean allowSynthesizer,
1288
boolean allowSequencer) {
1289
for(int i = 0; i < providers.size(); i++) {
1290
MidiDeviceProvider provider = providers.get(i);
1291
MidiDevice device = getNamedDevice(deviceName, provider,
1292
deviceClass,
1293
allowSynthesizer,
1294
allowSequencer);
1295
if (device != null) {
1296
return device;
1297
}
1298
}
1299
return null;
1300
}
1301
1302
/**
1303
* From a given MidiDeviceProvider, return the first appropriate device.
1304
*
1305
* @param provider The MidiDeviceProvider to check for MidiDevices
1306
* @param deviceClass The requested device type, one of Synthesizer.class,
1307
* Sequencer.class, Receiver.class or Transmitter.class
1308
* @return A MidiDevice is considered appropriate, or null if no appropriate
1309
* device is found
1310
*/
1311
private static MidiDevice getFirstDevice(MidiDeviceProvider provider,
1312
Class<?> deviceClass) {
1313
MidiDevice device;
1314
// try to get MIDI port
1315
device = getFirstDevice(provider, deviceClass,
1316
false, false);
1317
if (device != null) {
1318
return device;
1319
}
1320
1321
if (deviceClass == Receiver.class) {
1322
// try to get Synthesizer
1323
device = getFirstDevice(provider, deviceClass,
1324
true, false);
1325
if (device != null) {
1326
return device;
1327
}
1328
}
1329
1330
return null;
1331
}
1332
1333
/**
1334
* From a given MidiDeviceProvider, return the first appropriate device.
1335
*
1336
* @param provider The MidiDeviceProvider to check for MidiDevices
1337
* @param deviceClass The requested device type, one of Synthesizer.class,
1338
* Sequencer.class, Receiver.class or Transmitter.class
1339
* @param allowSynthesizer if true, Synthesizers are considered
1340
* appropriate. Otherwise only pure MidiDevices are considered
1341
* appropriate (unless allowSequencer is true). This flag only has
1342
* an effect for deviceClass Receiver and Transmitter. For other
1343
* device classes (Sequencer and Synthesizer), this flag has no
1344
* effect.
1345
* @param allowSequencer if true, Sequencers are considered appropriate.
1346
* Otherwise only pure MidiDevices are considered appropriate
1347
* (unless allowSynthesizer is true). This flag only has an effect
1348
* for deviceClass Receiver and Transmitter. For other device
1349
* classes (Sequencer and Synthesizer), this flag has no effect.
1350
* @return A MidiDevice is considered appropriate, or null if no appropriate
1351
* device is found
1352
*/
1353
private static MidiDevice getFirstDevice(MidiDeviceProvider provider,
1354
Class<?> deviceClass,
1355
boolean allowSynthesizer,
1356
boolean allowSequencer) {
1357
MidiDevice.Info[] infos = provider.getDeviceInfo();
1358
for (int j = 0; j < infos.length; j++) {
1359
MidiDevice device = provider.getDevice(infos[j]);
1360
if (isAppropriateDevice(device, deviceClass,
1361
allowSynthesizer, allowSequencer)) {
1362
return device;
1363
}
1364
}
1365
return null;
1366
}
1367
1368
/**
1369
* From a List of MidiDeviceProviders, return the first appropriate
1370
* MidiDevice.
1371
*
1372
* @param providers The List of MidiDeviceProviders to search
1373
* @param deviceClass The requested device type, one of Synthesizer.class,
1374
* Sequencer.class, Receiver.class or Transmitter.class
1375
* @return A MidiDevice that is considered appropriate, or null if none is
1376
* found
1377
*/
1378
private static MidiDevice getFirstDevice(List<MidiDeviceProvider> providers,
1379
Class<?> deviceClass) {
1380
MidiDevice device;
1381
// try to get MIDI port
1382
device = getFirstDevice(providers, deviceClass,
1383
false, false);
1384
if (device != null) {
1385
return device;
1386
}
1387
1388
if (deviceClass == Receiver.class) {
1389
// try to get Synthesizer
1390
device = getFirstDevice(providers, deviceClass,
1391
true, false);
1392
if (device != null) {
1393
return device;
1394
}
1395
}
1396
1397
return null;
1398
}
1399
1400
/**
1401
* From a List of MidiDeviceProviders, return the first appropriate
1402
* MidiDevice.
1403
*
1404
* @param providers The List of MidiDeviceProviders to search
1405
* @param deviceClass The requested device type, one of Synthesizer.class,
1406
* Sequencer.class, Receiver.class or Transmitter.class
1407
* @param allowSynthesizer if true, Synthesizers are considered
1408
* appropriate. Otherwise only pure MidiDevices are considered
1409
* appropriate (unless allowSequencer is true). This flag only has
1410
* an effect for deviceClass Receiver and Transmitter. For other
1411
* device classes (Sequencer and Synthesizer), this flag has no
1412
* effect.
1413
* @param allowSequencer if true, Sequencers are considered appropriate.
1414
* Otherwise only pure MidiDevices are considered appropriate
1415
* (unless allowSynthesizer is true). This flag only has an effect
1416
* for deviceClass Receiver and Transmitter. For other device
1417
* classes (Sequencer and Synthesizer), this flag has no effect.
1418
* @return A MidiDevice that is considered appropriate, or null if none is
1419
* found
1420
*/
1421
private static MidiDevice getFirstDevice(List<MidiDeviceProvider> providers,
1422
Class<?> deviceClass,
1423
boolean allowSynthesizer,
1424
boolean allowSequencer) {
1425
for(int i = 0; i < providers.size(); i++) {
1426
MidiDeviceProvider provider = providers.get(i);
1427
MidiDevice device = getFirstDevice(provider, deviceClass,
1428
allowSynthesizer,
1429
allowSequencer);
1430
if (device != null) {
1431
return device;
1432
}
1433
}
1434
return null;
1435
}
1436
1437
/**
1438
* Checks if a MidiDevice is appropriate. If deviceClass is Synthesizer or
1439
* Sequencer, a device implementing the respective interface is considered
1440
* appropriate. If deviceClass is Receiver or Transmitter, a device is
1441
* considered appropriate if it implements neither Synthesizer nor
1442
* Transmitter, and if it can provide at least one Receiver or Transmitter,
1443
* respectively.
1444
*
1445
* @param device the MidiDevice to test
1446
* @param deviceClass The requested device type, one of Synthesizer.class,
1447
* Sequencer.class, Receiver.class or Transmitter.class
1448
* @param allowSynthesizer if true, Synthesizers are considered
1449
* appropriate. Otherwise only pure MidiDevices are considered
1450
* appropriate (unless allowSequencer is true). This flag only has
1451
* an effect for deviceClass Receiver and Transmitter. For other
1452
* device classes (Sequencer and Synthesizer), this flag has no
1453
* effect.
1454
* @param allowSequencer if true, Sequencers are considered appropriate.
1455
* Otherwise only pure MidiDevices are considered appropriate
1456
* (unless allowSynthesizer is true). This flag only has an effect
1457
* for deviceClass Receiver and Transmitter. For other device
1458
* classes (Sequencer and Synthesizer), this flag has no effect.
1459
* @return true if the device is considered appropriate according to the
1460
* rules given above, false otherwise
1461
*/
1462
private static boolean isAppropriateDevice(MidiDevice device,
1463
Class<?> deviceClass,
1464
boolean allowSynthesizer,
1465
boolean allowSequencer) {
1466
if (deviceClass.isInstance(device)) {
1467
// This clause is for deviceClass being either Synthesizer
1468
// or Sequencer.
1469
return true;
1470
} else {
1471
// Now the case that deviceClass is Transmitter or
1472
// Receiver. If neither allowSynthesizer nor allowSequencer is
1473
// true, we require device instances to be
1474
// neither Synthesizer nor Sequencer, since we only want
1475
// devices representing MIDI ports.
1476
// Otherwise, the respective type is accepted, too
1477
if ( (! (device instanceof Sequencer) &&
1478
! (device instanceof Synthesizer) ) ||
1479
((device instanceof Sequencer) && allowSequencer) ||
1480
((device instanceof Synthesizer) && allowSynthesizer)) {
1481
// And of cource, the device has to be able to provide
1482
// Receivers or Transmitters.
1483
if ((deviceClass == Receiver.class &&
1484
device.getMaxReceivers() != 0) ||
1485
(deviceClass == Transmitter.class &&
1486
device.getMaxTransmitters() != 0)) {
1487
return true;
1488
}
1489
}
1490
}
1491
return false;
1492
}
1493
1494
/**
1495
* Obtains the set of services currently installed on the system using the
1496
* SPI mechanism in 1.3.
1497
*
1498
* @param providerClass The type of providers requested. This should be one
1499
* of AudioFileReader.class, AudioFileWriter.class,
1500
* FormatConversionProvider.class, MixerProvider.class,
1501
* MidiDeviceProvider.class, MidiFileReader.class,
1502
* MidiFileWriter.class or SoundbankReader.class.
1503
* @return a List of instances of providers for the requested service. If no
1504
* providers are available, a List of length 0 will be returned.
1505
*/
1506
private static List<?> getProviders(Class<?> providerClass) {
1507
return JDK13Services.getProviders(providerClass);
1508
}
1509
}
1510
1511