Source for javax.sound.midi.MidiSystem

   1: /* MidiSystem.java -- Access system MIDI resources
   2:    Copyright (C) 2005, 2012 Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: 
  39: package javax.sound.midi;
  40: 
  41: import gnu.classpath.ServiceFactory;
  42: 
  43: import java.io.File;
  44: import java.io.IOException;
  45: import java.io.InputStream;
  46: import java.io.OutputStream;
  47: import java.net.URL;
  48: import java.util.ArrayList;
  49: import java.util.List;
  50: import java.util.Iterator;
  51: 
  52: import javax.sound.midi.spi.MidiDeviceProvider;
  53: import javax.sound.midi.spi.MidiFileReader;
  54: import javax.sound.midi.spi.MidiFileWriter;
  55: import javax.sound.midi.spi.SoundbankReader;
  56: 
  57: /**
  58:  * MidiSystem provides access to the computer system's MIDI resources,
  59:  * as well as utility routines for reading MIDI files and more.
  60:  *
  61:  * @author Anthony Green (green@redhat.com)
  62:  * @since 1.3
  63:  *
  64:  */
  65: public class MidiSystem
  66: {
  67:   private MidiSystem()
  68:   {
  69:     // Not instantiable.
  70:   }
  71: 
  72:   /**
  73:    * Get an array of all available MIDI devices.
  74:    *
  75:    * @return a possibly empty array of all available MIDI devices
  76:    */
  77:   public static MidiDevice.Info[] getMidiDeviceInfo()
  78:   {
  79:     Iterator<MidiDeviceProvider> deviceProviders =
  80:         ServiceFactory.lookupProviders(MidiDeviceProvider.class);
  81:     List<MidiDevice.Info> infoList = new ArrayList<MidiDevice.Info>();
  82: 
  83:     while (deviceProviders.hasNext())
  84:     {
  85:       MidiDeviceProvider provider = (MidiDeviceProvider) deviceProviders.next();
  86:       MidiDevice.Info[] infos = provider.getDeviceInfo();
  87:       for (int i = infos.length; i > 0; )
  88:         infoList.add(infos[--i]);
  89:     }
  90: 
  91:     return infoList.toArray(new MidiDevice.Info[infoList.size()]);
  92:   }
  93: 
  94:   /**
  95:    * Get the specified MIDI device.
  96:    *
  97:    * @param info a description of the device we're looking for
  98:    * @return the requested MIDI device
  99:    * @throws MidiUnavailableException if no MIDI devices are configured or found
 100:    * @throws IllegalArgumentException if the device described by info is not found
 101:    */
 102:   public static MidiDevice getMidiDevice(MidiDevice.Info info)
 103:     throws MidiUnavailableException
 104:   {
 105:     Iterator<MidiDeviceProvider> deviceProviders =
 106:         ServiceFactory.lookupProviders(MidiDeviceProvider.class);
 107: 
 108:     if (! deviceProviders.hasNext())
 109:       throw new MidiUnavailableException("No MIDI device providers available.");
 110: 
 111:     do
 112:     {
 113:       MidiDeviceProvider provider =
 114:         (MidiDeviceProvider) deviceProviders.next();
 115:       if (provider.isDeviceSupported(info))
 116:         return provider.getDevice(info);
 117:     } while (deviceProviders.hasNext());
 118: 
 119:     throw new IllegalArgumentException("MIDI device "
 120:                                        + info + " not available.");
 121:   }
 122: 
 123:   /**
 124:    * Get the default Receiver instance.  This just picks the first one
 125:    * it finds for now.
 126:    *
 127:    * @return the default Receiver instance
 128:    * @throws MidiUnavailableException if no Receiver is found
 129:    */
 130:   public static Receiver getReceiver() throws MidiUnavailableException
 131:   {
 132:     // TODO: The 1.5 spec has a fancy mechanism to specify the default
 133:     // receiver device.  For now, well just return the first one we find.
 134:     MidiDevice.Info[] infos = getMidiDeviceInfo();
 135:     for (int i = 0; i < infos.length; i++)
 136:     {
 137:       MidiDevice device = getMidiDevice(infos[i]);
 138:       if (device instanceof Receiver)
 139:         return (Receiver) device;
 140:     }
 141:     throw new MidiUnavailableException("No Receiver device available");
 142:   }
 143: 
 144:   /**
 145:    * Get the default Transmitter instance.  This just picks the first one
 146:    * it finds for now.
 147:    *
 148:    * @return the default Transmitter instance
 149:    * @throws MidiUnavailableException if no Transmitter is found
 150:    */
 151:   public static Transmitter getTransmitter() throws MidiUnavailableException
 152:   {
 153:     // TODO: The 1.5 spec has a fancy mechanism to specify the default
 154:     // Transmitter device.  For now, well just return the first one we find.
 155:     MidiDevice.Info[] infos = getMidiDeviceInfo();
 156:     for (int i = 0; i < infos.length; i++)
 157:     {
 158:       MidiDevice device = getMidiDevice(infos[i]);
 159:       if (device instanceof Transmitter)
 160:         return (Transmitter) device;
 161:     }
 162:     throw new MidiUnavailableException("No Transmitter device available");
 163:   }
 164: 
 165:   /**
 166:    * Get the default Synthesizer instance.  This just picks the first one
 167:    * it finds for now.
 168:    *
 169:    * @return the default Synthesizer instance
 170:    * @throws MidiUnavailableException if no Synthesizer is found
 171:    */
 172:   public static Synthesizer getSynthesizer() throws MidiUnavailableException
 173:   {
 174:     // TODO: The 1.5 spec has a fancy mechanism to specify the default
 175:     // Synthesizer device.  For now, well just return the first one we find.
 176:     MidiDevice.Info[] infos = getMidiDeviceInfo();
 177:     for (int i = 0; i < infos.length; i++)
 178:     {
 179:       MidiDevice device = getMidiDevice(infos[i]);
 180:       if (device instanceof Synthesizer)
 181:         return (Synthesizer) device;
 182:     }
 183:     throw new MidiUnavailableException("No Synthesizer device available");
 184:   }
 185: 
 186:   /**
 187:    * Get the default Sequencer instance.  This just picks the first one
 188:    * it finds for now.
 189:    *
 190:    * @return the default Sequencer instance
 191:    * @throws MidiUnavailableException if no Sequencer is found
 192:    */
 193:   public static Sequencer getSequencer() throws MidiUnavailableException
 194:   {
 195:     // TODO: The 1.5 spec has a fancy mechanism to specify the default
 196:     // Sequencer device.  For now, well just return the first one we find.
 197:     MidiDevice.Info[] infos = getMidiDeviceInfo();
 198:     for (int i = 0; i < infos.length; i++)
 199:     {
 200:       MidiDevice device = getMidiDevice(infos[i]);
 201:       if (device instanceof Sequencer)
 202:         return (Sequencer) device;
 203:     }
 204:     throw new MidiUnavailableException("No Sequencer device available");
 205:   }
 206: 
 207:   /**
 208:    * Read a Soundbank object from the given stream.
 209:    *
 210:    * @param stream the stream from which to read the Soundbank
 211:    * @return the Soundbank object
 212:    * @throws InvalidMidiDataException if we were unable to read the soundbank
 213:    * @throws IOException if an I/O error happened while reading
 214:    */
 215:   public static Soundbank getSoundbank(InputStream stream)
 216:     throws InvalidMidiDataException, IOException
 217:   {
 218:     Iterator<SoundbankReader> readers =
 219:       ServiceFactory.lookupProviders(SoundbankReader.class);
 220:     while (readers.hasNext())
 221:     {
 222:       SoundbankReader sr = 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<SoundbankReader> readers =
 242:       ServiceFactory.lookupProviders(SoundbankReader.class);
 243:     while (readers.hasNext())
 244:     {
 245:       SoundbankReader sr = readers.next();
 246:       Soundbank sb = sr.getSoundbank(url);
 247:       if (sb != null)
 248:         return sb;
 249:     }
 250:     throw new InvalidMidiDataException("Cannot read from url " + url);
 251:   }
 252: 
 253:   /**
 254:    * Read a Soundbank object from the given file.
 255:    *
 256:    * @param file the file from which to read the Soundbank
 257:    * @return the Soundbank object
 258:    * @throws InvalidMidiDataException if we were unable to read the soundbank
 259:    * @throws IOException if an I/O error happened while reading
 260:    */
 261:   public static Soundbank getSoundbank(File file)
 262:     throws InvalidMidiDataException, IOException
 263:   {
 264:     Iterator<SoundbankReader> readers =
 265:       ServiceFactory.lookupProviders(SoundbankReader.class);
 266:     while (readers.hasNext())
 267:     {
 268:       SoundbankReader sr = (SoundbankReader) readers.next();
 269:       Soundbank sb = sr.getSoundbank(file);
 270:       if (sb != null)
 271:         return sb;
 272:     }
 273:     throw new InvalidMidiDataException("Cannot read soundbank from file "
 274:                                        + file);
 275:   }
 276: 
 277:   /**
 278:    * Read a MidiFileFormat object from the given stream.
 279:    *
 280:    * @param stream the stream from which to read the MidiFileFormat
 281:    * @return the MidiFileFormat object
 282:    * @throws InvalidMidiDataException if we were unable to read the MidiFileFormat
 283:    * @throws IOException if an I/O error happened while reading
 284:    */
 285:   public static MidiFileFormat getMidiFileFormat(InputStream stream)
 286:     throws InvalidMidiDataException, IOException
 287:   {
 288:     Iterator<MidiFileReader> readers =
 289:       ServiceFactory.lookupProviders(MidiFileReader.class);
 290:     while (readers.hasNext())
 291:     {
 292:       MidiFileReader sr = readers.next();
 293:       MidiFileFormat sb = sr.getMidiFileFormat(stream);
 294:       if (sb != null)
 295:         return sb;
 296:     }
 297:     throw new InvalidMidiDataException("Can't read MidiFileFormat from stream");
 298:   }
 299: 
 300:   /**
 301:    * Read a MidiFileFormat object from the given url.
 302:    *
 303:    * @param url the url from which to read the MidiFileFormat
 304:    * @return the MidiFileFormat object
 305:    * @throws InvalidMidiDataException if we were unable to read the MidiFileFormat
 306:    * @throws IOException if an I/O error happened while reading
 307:    */
 308:   public static MidiFileFormat getMidiFileFormat(URL url)
 309:     throws InvalidMidiDataException, IOException
 310:   {
 311:     Iterator<MidiFileReader> readers =
 312:       ServiceFactory.lookupProviders(MidiFileReader.class);
 313:     while (readers.hasNext())
 314:     {
 315:       MidiFileReader sr = readers.next();
 316:       MidiFileFormat sb = sr.getMidiFileFormat(url);
 317:       if (sb != null)
 318:         return sb;
 319:     }
 320:     throw new InvalidMidiDataException("Cannot read from url " + url);
 321:   }
 322: 
 323:   /**
 324:    * Read a MidiFileFormat object from the given file.
 325:    *
 326:    * @param file the file from which to read the MidiFileFormat
 327:    * @return the MidiFileFormat object
 328:    * @throws InvalidMidiDataException if we were unable to read the MidiFileFormat
 329:    * @throws IOException if an I/O error happened while reading
 330:    */
 331:   public static MidiFileFormat getMidiFileFormat(File file)
 332:     throws InvalidMidiDataException, IOException
 333:   {
 334:     Iterator<MidiFileReader> readers =
 335:       ServiceFactory.lookupProviders(MidiFileReader.class);
 336:     while (readers.hasNext())
 337:     {
 338:       MidiFileReader sr = readers.next();
 339:       MidiFileFormat sb = sr.getMidiFileFormat(file);
 340:       if (sb != null)
 341:         return sb;
 342:     }
 343:     throw new InvalidMidiDataException("Can't read MidiFileFormat from file "
 344:                                        + file);
 345:   }
 346: 
 347:   /**
 348:    * Read a Sequence object from the given stream.
 349:    *
 350:    * @param stream the stream from which to read the Sequence
 351:    * @return the Sequence object
 352:    * @throws InvalidMidiDataException if we were unable to read the Sequence
 353:    * @throws IOException if an I/O error happened while reading
 354:    */
 355:   public static Sequence getSequence(InputStream stream)
 356:     throws InvalidMidiDataException, IOException
 357:   {
 358:     Iterator<MidiFileReader> readers =
 359:       ServiceFactory.lookupProviders(MidiFileReader.class);
 360:     while (readers.hasNext())
 361:     {
 362:       MidiFileReader sr = readers.next();
 363:       Sequence sq = sr.getSequence(stream);
 364:       if (sq != null)
 365:         return sq;
 366:     }
 367:     throw new InvalidMidiDataException("Can't read Sequence from stream");
 368:   }
 369: 
 370:   /**
 371:    * Read a Sequence object from the given url.
 372:    *
 373:    * @param url the url from which to read the Sequence
 374:    * @return the Sequence object
 375:    * @throws InvalidMidiDataException if we were unable to read the Sequence
 376:    * @throws IOException if an I/O error happened while reading
 377:    */
 378:   public static Sequence getSequence(URL url)
 379:     throws InvalidMidiDataException, IOException
 380:   {
 381:     Iterator<MidiFileReader> readers =
 382:       ServiceFactory.lookupProviders(MidiFileReader.class);
 383:     while (readers.hasNext())
 384:     {
 385:       MidiFileReader sr = readers.next();
 386:       Sequence sq = sr.getSequence(url);
 387:       if (sq != null)
 388:         return sq;
 389:     }
 390:     throw new InvalidMidiDataException("Cannot read from url " + url);
 391:   }
 392: 
 393:   /**
 394:    * Read a Sequence object from the given file.
 395:    *
 396:    * @param file the file from which to read the Sequence
 397:    * @return the Sequence object
 398:    * @throws InvalidMidiDataException if we were unable to read the Sequence
 399:    * @throws IOException if an I/O error happened while reading
 400:    */
 401:   public static Sequence getSequence(File file)
 402:     throws InvalidMidiDataException, IOException
 403:   {
 404:     Iterator<MidiFileReader> readers =
 405:       ServiceFactory.lookupProviders(MidiFileReader.class);
 406:     while (readers.hasNext())
 407:     {
 408:       MidiFileReader sr = readers.next();
 409:       Sequence sq = sr.getSequence(file);
 410:       if (sq != null)
 411:         return sq;
 412:     }
 413:     throw new InvalidMidiDataException("Can't read Sequence from file "
 414:                                        + file);
 415:   }
 416: 
 417:   /**
 418:    * Return an array of supported MIDI file types on this system.
 419:    *
 420:    * @return the array of supported MIDI file types
 421:    */
 422:   public static int[] getMidiFileTypes()
 423:   {
 424:     // We only support a max of 3 MIDI file types.
 425:     boolean supported[] = new boolean[3];
 426:     // The number of supported formats.
 427:     int count = 0;
 428:     Iterator<MidiFileWriter> writers =
 429:       ServiceFactory.lookupProviders(MidiFileWriter.class);
 430:     while (writers.hasNext())
 431:     {
 432:       MidiFileWriter fw = writers.next();
 433:       int types[] = fw.getMidiFileTypes();
 434:       for (int i = types.length; i > 0;)
 435:       {
 436:         int type = types[--i];
 437:         if (supported[type] == false)
 438:         {
 439:           count++;
 440:           supported[type] = true;
 441:         }
 442:       }
 443:     }
 444:     int result[] = new int[count];
 445:     for (int i = supported.length; i > 0;)
 446:     {
 447:       if (supported[--i])
 448:         result[--count] = i;
 449:     }
 450:     return result;
 451:   }
 452: 
 453:   /**
 454:    * Return true if the system supports writing files of type fileType.
 455:    *
 456:    * @param fileType the MIDI file type we want to write
 457:    * @return true if we can write fileType files, false otherwise
 458:    */
 459:   public static boolean isFileTypeSupported(int fileType)
 460:   {
 461:     Iterator<MidiFileWriter> writers = ServiceFactory.lookupProviders(MidiFileWriter.class);
 462:     while (writers.hasNext())
 463:     {
 464:       MidiFileWriter fw = writers.next();
 465: 
 466:       if (fw.isFileTypeSupported(fileType))
 467:         return true;
 468:     }
 469:     return false;
 470:   }
 471: 
 472:   /**
 473:    * Return an array of supported MIDI file types on this system
 474:    * for the given sequnce.
 475:    *
 476:    * @param sequence the sequnce to write
 477:    * @return the array of supported MIDI file types
 478:    */
 479:   public static int[] getMidiFileTypes(Sequence sequence)
 480:   {
 481:     // We only support a max of 3 MIDI file types.
 482:     boolean supported[] = new boolean[3];
 483:     // The number of supported formats.
 484:     int count = 0;
 485:     Iterator<MidiFileWriter> writers = ServiceFactory.lookupProviders(MidiFileWriter.class);
 486:     while (writers.hasNext())
 487:     {
 488:       MidiFileWriter fw = (MidiFileWriter) writers.next();
 489:       int types[] = fw.getMidiFileTypes(sequence);
 490:       for (int i = types.length; i > 0;)
 491:       {
 492:         int type = types[--i];
 493:         if (supported[type] == false)
 494:         {
 495:           count++;
 496:           supported[type] = true;
 497:         }
 498:       }
 499:     }
 500:     int result[] = new int[count];
 501:     for (int i = supported.length; i > 0;)
 502:     {
 503:       if (supported[--i])
 504:         result[--count] = i;
 505:     }
 506:     return result;
 507:   }
 508: 
 509:   /**
 510:    * Return true if the system supports writing files of type fileType
 511:    * for the given sequence.
 512:    *
 513:    * @param fileType the MIDI file type we want to write
 514:    * @param sequence the Sequence we want to write
 515:    * @return true if we can write fileType files for sequence, false otherwise
 516:    */
 517:   public static boolean isFileTypeSupported(int fileType, Sequence sequence)
 518:   {
 519:     Iterator<MidiFileWriter> writers = ServiceFactory.lookupProviders(MidiFileWriter.class);
 520:     while (writers.hasNext())
 521:     {
 522:       MidiFileWriter fw = (MidiFileWriter) writers.next();
 523: 
 524:       if (fw.isFileTypeSupported(fileType, sequence))
 525:         return true;
 526:     }
 527:     return false;
 528:   }
 529: 
 530:   /**
 531:    * Write a sequence to an output stream using a specific MIDI file format.
 532:    *
 533:    * @param in the sequence to write
 534:    * @param fileType the MIDI file format to use
 535:    * @param out the output stream to write to
 536:    * @return the number of bytes written
 537:    * @throws IOException if an I/O exception happens
 538:    * @throws IllegalArgumentException if fileType is not supported for in
 539:    */
 540:   public static int write(Sequence in, int fileType, OutputStream out)
 541:     throws IOException
 542:   {
 543:     Iterator<MidiFileWriter> writers = ServiceFactory.lookupProviders(MidiFileWriter.class);
 544:     while (writers.hasNext())
 545:     {
 546:       MidiFileWriter fw = (MidiFileWriter) writers.next();
 547: 
 548:       if (fw.isFileTypeSupported(fileType, in))
 549:         return fw.write(in, fileType, out);
 550:     }
 551:     throw new IllegalArgumentException("File type "
 552:                                        + fileType + " is not supported");
 553:   }
 554: 
 555:   /**
 556:    * Write a sequence to a file using a specific MIDI file format.
 557:    *
 558:    * @param in the sequence to write
 559:    * @param fileType the MIDI file format to use
 560:    * @param out the file to write to
 561:    * @return the number of bytes written
 562:    * @throws IOException if an I/O exception happens
 563:    * @throws IllegalArgumentException if fileType is not supported for in
 564:    */
 565:   public static int write(Sequence in, int fileType, File out)
 566:     throws IOException
 567:   {
 568:     Iterator<MidiFileWriter> writers = ServiceFactory.lookupProviders(MidiFileWriter.class);
 569:     while (writers.hasNext())
 570:     {
 571:       MidiFileWriter fw = (MidiFileWriter) writers.next();
 572: 
 573:       if (fw.isFileTypeSupported(fileType, in))
 574:         return fw.write(in, fileType, out);
 575:     }
 576:     throw new IllegalArgumentException("File type "
 577:                                        + fileType + " is not supported");
 578:   }
 579: }