001 /* MidiSystem.java -- Access system MIDI resources
002 Copyright (C) 2005 Free Software Foundation, Inc.
003
004 This file is part of GNU Classpath.
005
006 GNU Classpath is free software; you can redistribute it and/or modify
007 it under the terms of the GNU General Public License as published by
008 the Free Software Foundation; either version 2, or (at your option)
009 any later version.
010
011 GNU Classpath is distributed in the hope that it will be useful, but
012 WITHOUT ANY WARRANTY; without even the implied warranty of
013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014 General Public License for more details.
015
016 You should have received a copy of the GNU General Public License
017 along with GNU Classpath; see the file COPYING. If not, write to the
018 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019 02110-1301 USA.
020
021 Linking this library statically or dynamically with other modules is
022 making a combined work based on this library. Thus, the terms and
023 conditions of the GNU General Public License cover the whole
024 combination.
025
026 As a special exception, the copyright holders of this library give you
027 permission to link this library with independent modules to produce an
028 executable, regardless of the license terms of these independent
029 modules, and to copy and distribute the resulting executable under
030 terms of your choice, provided that you also meet, for each linked
031 independent module, the terms and conditions of the license of that
032 module. An independent module is a module which is not derived from
033 or based on this library. If you modify this library, you may extend
034 this exception to your version of the library, but you are not
035 obligated to do so. If you do not wish to do so, delete this
036 exception statement from your version. */
037
038
039 package javax.sound.midi;
040
041 import gnu.classpath.ServiceFactory;
042
043 import java.io.File;
044 import java.io.IOException;
045 import java.io.InputStream;
046 import java.io.OutputStream;
047 import java.net.URL;
048 import java.util.ArrayList;
049 import java.util.List;
050 import java.util.Iterator;
051
052 import javax.sound.midi.spi.MidiDeviceProvider;
053 import javax.sound.midi.spi.MidiFileReader;
054 import javax.sound.midi.spi.MidiFileWriter;
055 import javax.sound.midi.spi.SoundbankReader;
056
057 /**
058 * MidiSystem provides access to the computer system's MIDI resources,
059 * as well as utility routines for reading MIDI files and more.
060 *
061 * @author Anthony Green (green@redhat.com)
062 * @since 1.3
063 *
064 */
065 public class MidiSystem
066 {
067 private MidiSystem()
068 {
069 // Not instantiable.
070 }
071
072 /**
073 * Get an array of all available MIDI devices.
074 *
075 * @return a possibly empty array of all available MIDI devices
076 */
077 public static MidiDevice.Info[] getMidiDeviceInfo()
078 {
079 Iterator deviceProviders =
080 ServiceFactory.lookupProviders(MidiDeviceProvider.class);
081 List infoList = new ArrayList();
082
083 while (deviceProviders.hasNext())
084 {
085 MidiDeviceProvider provider = (MidiDeviceProvider) deviceProviders.next();
086 MidiDevice.Info[] infos = provider.getDeviceInfo();
087 for (int i = infos.length; i > 0; )
088 infoList.add(infos[--i]);
089 }
090
091 return (MidiDevice.Info[])
092 infoList.toArray(new MidiDevice.Info[infoList.size()]);
093 }
094
095 /**
096 * Get the specified MIDI device.
097 *
098 * @param info a description of the device we're looking for
099 * @return the requested MIDI device
100 * @throws MidiUnavailableException if no MIDI devices are configured or found
101 * @throws IllegalArgumentException if the device described by info is not found
102 */
103 public static MidiDevice getMidiDevice(MidiDevice.Info info)
104 throws MidiUnavailableException
105 {
106 Iterator deviceProviders =
107 ServiceFactory.lookupProviders(MidiDeviceProvider.class);
108
109 if (! deviceProviders.hasNext())
110 throw new MidiUnavailableException("No MIDI device providers available.");
111
112 do
113 {
114 MidiDeviceProvider provider =
115 (MidiDeviceProvider) deviceProviders.next();
116 if (provider.isDeviceSupported(info))
117 return provider.getDevice(info);
118 } while (deviceProviders.hasNext());
119
120 throw new IllegalArgumentException("MIDI device "
121 + info + " not available.");
122 }
123
124 /**
125 * Get the default Receiver instance. This just picks the first one
126 * it finds for now.
127 *
128 * @return the default Receiver instance
129 * @throws MidiUnavailableException if no Receiver is found
130 */
131 public static Receiver getReceiver() throws MidiUnavailableException
132 {
133 // TODO: The 1.5 spec has a fancy mechanism to specify the default
134 // receiver device. For now, well just return the first one we find.
135 MidiDevice.Info[] infos = getMidiDeviceInfo();
136 for (int i = 0; i < infos.length; i++)
137 {
138 MidiDevice device = getMidiDevice(infos[i]);
139 if (device instanceof Receiver)
140 return (Receiver) device;
141 }
142 throw new MidiUnavailableException("No Receiver device available");
143 }
144
145 /**
146 * Get the default Transmitter instance. This just picks the first one
147 * it finds for now.
148 *
149 * @return the default Transmitter instance
150 * @throws MidiUnavailableException if no Transmitter is found
151 */
152 public static Transmitter getTransmitter() throws MidiUnavailableException
153 {
154 // TODO: The 1.5 spec has a fancy mechanism to specify the default
155 // Transmitter device. For now, well just return the first one we find.
156 MidiDevice.Info[] infos = getMidiDeviceInfo();
157 for (int i = 0; i < infos.length; i++)
158 {
159 MidiDevice device = getMidiDevice(infos[i]);
160 if (device instanceof Transmitter)
161 return (Transmitter) device;
162 }
163 throw new MidiUnavailableException("No Transmitter device available");
164 }
165
166 /**
167 * Get the default Synthesizer instance. This just picks the first one
168 * it finds for now.
169 *
170 * @return the default Synthesizer instance
171 * @throws MidiUnavailableException if no Synthesizer is found
172 */
173 public static Synthesizer getSynthesizer() throws MidiUnavailableException
174 {
175 // TODO: The 1.5 spec has a fancy mechanism to specify the default
176 // Synthesizer device. For now, well just return the first one we find.
177 MidiDevice.Info[] infos = getMidiDeviceInfo();
178 for (int i = 0; i < infos.length; i++)
179 {
180 MidiDevice device = getMidiDevice(infos[i]);
181 if (device instanceof Synthesizer)
182 return (Synthesizer) device;
183 }
184 throw new MidiUnavailableException("No Synthesizer device available");
185 }
186
187 /**
188 * Get the default Sequencer instance. This just picks the first one
189 * it finds for now.
190 *
191 * @return the default Sequencer instance
192 * @throws MidiUnavailableException if no Sequencer is found
193 */
194 public static Sequencer getSequencer() throws MidiUnavailableException
195 {
196 // TODO: The 1.5 spec has a fancy mechanism to specify the default
197 // Sequencer device. For now, well just return the first one we find.
198 MidiDevice.Info[] infos = getMidiDeviceInfo();
199 for (int i = 0; i < infos.length; i++)
200 {
201 MidiDevice device = getMidiDevice(infos[i]);
202 if (device instanceof Sequencer)
203 return (Sequencer) device;
204 }
205 throw new MidiUnavailableException("No Sequencer device available");
206 }
207
208 /**
209 * Read a Soundbank object from the given stream.
210 *
211 * @param stream the stream from which to read the Soundbank
212 * @return the Soundbank object
213 * @throws InvalidMidiDataException if we were unable to read the soundbank
214 * @throws IOException if an I/O error happened while reading
215 */
216 public static Soundbank getSoundbank(InputStream stream)
217 throws InvalidMidiDataException, IOException
218 {
219 Iterator readers = ServiceFactory.lookupProviders(SoundbankReader.class);
220 while (readers.hasNext())
221 {
222 SoundbankReader sr = (SoundbankReader) readers.next();
223 Soundbank sb = sr.getSoundbank(stream);
224 if (sb != null)
225 return sb;
226 }
227 throw new InvalidMidiDataException("Cannot read soundbank from stream");
228 }
229
230 /**
231 * Read a Soundbank object from the given url.
232 *
233 * @param url the url from which to read the Soundbank
234 * @return the Soundbank object
235 * @throws InvalidMidiDataException if we were unable to read the soundbank
236 * @throws IOException if an I/O error happened while reading
237 */
238 public static Soundbank getSoundbank(URL url)
239 throws InvalidMidiDataException, IOException
240 {
241 Iterator readers = ServiceFactory.lookupProviders(SoundbankReader.class);
242 while (readers.hasNext())
243 {
244 SoundbankReader sr = (SoundbankReader) readers.next();
245 Soundbank sb = sr.getSoundbank(url);
246 if (sb != null)
247 return sb;
248 }
249 throw new InvalidMidiDataException("Cannot read from url " + url);
250 }
251
252 /**
253 * Read a Soundbank object from the given file.
254 *
255 * @param file the file from which to read the Soundbank
256 * @return the Soundbank object
257 * @throws InvalidMidiDataException if we were unable to read the soundbank
258 * @throws IOException if an I/O error happened while reading
259 */
260 public static Soundbank getSoundbank(File file)
261 throws InvalidMidiDataException, IOException
262 {
263 Iterator readers = ServiceFactory.lookupProviders(SoundbankReader.class);
264 while (readers.hasNext())
265 {
266 SoundbankReader sr = (SoundbankReader) readers.next();
267 Soundbank sb = sr.getSoundbank(file);
268 if (sb != null)
269 return sb;
270 }
271 throw new InvalidMidiDataException("Cannot read soundbank from file "
272 + file);
273 }
274
275 /**
276 * Read a MidiFileFormat object from the given stream.
277 *
278 * @param stream the stream from which to read the MidiFileFormat
279 * @return the MidiFileFormat object
280 * @throws InvalidMidiDataException if we were unable to read the MidiFileFormat
281 * @throws IOException if an I/O error happened while reading
282 */
283 public static MidiFileFormat getMidiFileFormat(InputStream stream)
284 throws InvalidMidiDataException, IOException
285 {
286 Iterator readers = ServiceFactory.lookupProviders(MidiFileReader.class);
287 while (readers.hasNext())
288 {
289 MidiFileReader sr = (MidiFileReader) readers.next();
290 MidiFileFormat sb = sr.getMidiFileFormat(stream);
291 if (sb != null)
292 return sb;
293 }
294 throw new InvalidMidiDataException("Can't read MidiFileFormat from stream");
295 }
296
297 /**
298 * Read a MidiFileFormat object from the given url.
299 *
300 * @param url the url from which to read the MidiFileFormat
301 * @return the MidiFileFormat object
302 * @throws InvalidMidiDataException if we were unable to read the MidiFileFormat
303 * @throws IOException if an I/O error happened while reading
304 */
305 public static MidiFileFormat getMidiFileFormat(URL url)
306 throws InvalidMidiDataException, IOException
307 {
308 Iterator readers = ServiceFactory.lookupProviders(MidiFileReader.class);
309 while (readers.hasNext())
310 {
311 MidiFileReader sr = (MidiFileReader) readers.next();
312 MidiFileFormat sb = sr.getMidiFileFormat(url);
313 if (sb != null)
314 return sb;
315 }
316 throw new InvalidMidiDataException("Cannot read from url " + url);
317 }
318
319 /**
320 * Read a MidiFileFormat object from the given file.
321 *
322 * @param file the file from which to read the MidiFileFormat
323 * @return the MidiFileFormat object
324 * @throws InvalidMidiDataException if we were unable to read the MidiFileFormat
325 * @throws IOException if an I/O error happened while reading
326 */
327 public static MidiFileFormat getMidiFileFormat(File file)
328 throws InvalidMidiDataException, IOException
329 {
330 Iterator readers = ServiceFactory.lookupProviders(MidiFileReader.class);
331 while (readers.hasNext())
332 {
333 MidiFileReader sr = (MidiFileReader) readers.next();
334 MidiFileFormat sb = sr.getMidiFileFormat(file);
335 if (sb != null)
336 return sb;
337 }
338 throw new InvalidMidiDataException("Can't read MidiFileFormat from file "
339 + file);
340 }
341
342 /**
343 * Read a Sequence object from the given stream.
344 *
345 * @param stream the stream from which to read the Sequence
346 * @return the Sequence object
347 * @throws InvalidMidiDataException if we were unable to read the Sequence
348 * @throws IOException if an I/O error happened while reading
349 */
350 public static Sequence getSequence(InputStream stream)
351 throws InvalidMidiDataException, IOException
352 {
353 Iterator readers = ServiceFactory.lookupProviders(MidiFileReader.class);
354 while (readers.hasNext())
355 {
356 MidiFileReader sr = (MidiFileReader) readers.next();
357 Sequence sq = sr.getSequence(stream);
358 if (sq != null)
359 return sq;
360 }
361 throw new InvalidMidiDataException("Can't read Sequence from stream");
362 }
363
364 /**
365 * Read a Sequence object from the given url.
366 *
367 * @param url the url from which to read the Sequence
368 * @return the Sequence object
369 * @throws InvalidMidiDataException if we were unable to read the Sequence
370 * @throws IOException if an I/O error happened while reading
371 */
372 public static Sequence getSequence(URL url)
373 throws InvalidMidiDataException, IOException
374 {
375 Iterator readers = ServiceFactory.lookupProviders(MidiFileReader.class);
376 while (readers.hasNext())
377 {
378 MidiFileReader sr = (MidiFileReader) readers.next();
379 Sequence sq = sr.getSequence(url);
380 if (sq != null)
381 return sq;
382 }
383 throw new InvalidMidiDataException("Cannot read from url " + url);
384 }
385
386 /**
387 * Read a Sequence object from the given file.
388 *
389 * @param file the file from which to read the Sequence
390 * @return the Sequence object
391 * @throws InvalidMidiDataException if we were unable to read the Sequence
392 * @throws IOException if an I/O error happened while reading
393 */
394 public static Sequence getSequence(File file)
395 throws InvalidMidiDataException, IOException
396 {
397 Iterator readers = ServiceFactory.lookupProviders(MidiFileReader.class);
398 while (readers.hasNext())
399 {
400 MidiFileReader sr = (MidiFileReader) readers.next();
401 Sequence sq = sr.getSequence(file);
402 if (sq != null)
403 return sq;
404 }
405 throw new InvalidMidiDataException("Can't read Sequence from file "
406 + file);
407 }
408
409 /**
410 * Return an array of supported MIDI file types on this system.
411 *
412 * @return the array of supported MIDI file types
413 */
414 public static int[] getMidiFileTypes()
415 {
416 // We only support a max of 3 MIDI file types.
417 boolean supported[] = new boolean[3];
418 // The number of supported formats.
419 int count = 0;
420 Iterator writers = ServiceFactory.lookupProviders(MidiFileWriter.class);
421 while (writers.hasNext())
422 {
423 MidiFileWriter fw = (MidiFileWriter) writers.next();
424 int types[] = fw.getMidiFileTypes();
425 for (int i = types.length; i > 0;)
426 {
427 int type = types[--i];
428 if (supported[type] == false)
429 {
430 count++;
431 supported[type] = true;
432 }
433 }
434 }
435 int result[] = new int[count];
436 for (int i = supported.length; i > 0;)
437 {
438 if (supported[--i])
439 result[--count] = i;
440 }
441 return result;
442 }
443
444 /**
445 * Return true if the system supports writing files of type fileType.
446 *
447 * @param fileType the MIDI file type we want to write
448 * @return true if we can write fileType files, false otherwise
449 */
450 public static boolean isFileTypeSupported(int fileType)
451 {
452 Iterator writers = ServiceFactory.lookupProviders(MidiFileWriter.class);
453 while (writers.hasNext())
454 {
455 MidiFileWriter fw = (MidiFileWriter) writers.next();
456
457 if (fw.isFileTypeSupported(fileType))
458 return true;
459 }
460 return false;
461 }
462
463 /**
464 * Return an array of supported MIDI file types on this system
465 * for the given sequnce.
466 *
467 * @param sequence the sequnce to write
468 * @return the array of supported MIDI file types
469 */
470 public static int[] getMidiFileTypes(Sequence sequence)
471 {
472 // We only support a max of 3 MIDI file types.
473 boolean supported[] = new boolean[3];
474 // The number of supported formats.
475 int count = 0;
476 Iterator writers = ServiceFactory.lookupProviders(MidiFileWriter.class);
477 while (writers.hasNext())
478 {
479 MidiFileWriter fw = (MidiFileWriter) writers.next();
480 int types[] = fw.getMidiFileTypes(sequence);
481 for (int i = types.length; i > 0;)
482 {
483 int type = types[--i];
484 if (supported[type] == false)
485 {
486 count++;
487 supported[type] = true;
488 }
489 }
490 }
491 int result[] = new int[count];
492 for (int i = supported.length; i > 0;)
493 {
494 if (supported[--i])
495 result[--count] = i;
496 }
497 return result;
498 }
499
500 /**
501 * Return true if the system supports writing files of type fileType
502 * for the given sequence.
503 *
504 * @param fileType the MIDI file type we want to write
505 * @param sequence the Sequence we want to write
506 * @return true if we can write fileType files for sequence, false otherwise
507 */
508 public static boolean isFileTypeSupported(int fileType, Sequence sequence)
509 {
510 Iterator writers = ServiceFactory.lookupProviders(MidiFileWriter.class);
511 while (writers.hasNext())
512 {
513 MidiFileWriter fw = (MidiFileWriter) writers.next();
514
515 if (fw.isFileTypeSupported(fileType, sequence))
516 return true;
517 }
518 return false;
519 }
520
521 /**
522 * Write a sequence to an output stream using a specific MIDI file format.
523 *
524 * @param in the sequence to write
525 * @param fileType the MIDI file format to use
526 * @param out the output stream to write to
527 * @return the number of bytes written
528 * @throws IOException if an I/O exception happens
529 * @throws IllegalArgumentException if fileType is not supported for in
530 */
531 public static int write(Sequence in, int fileType, OutputStream out)
532 throws IOException
533 {
534 Iterator writers = ServiceFactory.lookupProviders(MidiFileWriter.class);
535 while (writers.hasNext())
536 {
537 MidiFileWriter fw = (MidiFileWriter) writers.next();
538
539 if (fw.isFileTypeSupported(fileType, in))
540 return fw.write(in, fileType, out);
541 }
542 throw new IllegalArgumentException("File type "
543 + fileType + " is not supported");
544 }
545
546 /**
547 * Write a sequence to a file using a specific MIDI file format.
548 *
549 * @param in the sequence to write
550 * @param fileType the MIDI file format to use
551 * @param out the file to write to
552 * @return the number of bytes written
553 * @throws IOException if an I/O exception happens
554 * @throws IllegalArgumentException if fileType is not supported for in
555 */
556 public static int write(Sequence in, int fileType, File out)
557 throws IOException
558 {
559 Iterator writers = ServiceFactory.lookupProviders(MidiFileWriter.class);
560 while (writers.hasNext())
561 {
562 MidiFileWriter fw = (MidiFileWriter) writers.next();
563
564 if (fw.isFileTypeSupported(fileType, in))
565 return fw.write(in, fileType, out);
566 }
567 throw new IllegalArgumentException("File type "
568 + fileType + " is not supported");
569 }
570 }