Source for javax.sound.midi.MidiSystem

   1: /* MidiSystem.java -- Access system MIDI resources
   2:    Copyright (C) 2005 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 deviceProviders = 
  80:     ServiceFactory.lookupProviders(MidiDeviceProvider.class);
  81:     List infoList = new ArrayList();
  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 (MidiDevice.Info[]) 
  92:     infoList.toArray(new MidiDevice.Info[infoList.size()]);
  93:   }
  94:   
  95:   /**
  96:    * Get the specified MIDI device.
  97:    * 
  98:    * @param info a description of the device we're looking for
  99:    * @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: }