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:   /**
  68:    * Get an array of all available MIDI devices.
  69:    * 
  70:    * @return a possibly empty array of all available MIDI devices
  71:    */
  72:   public static MidiDevice.Info[] getMidiDeviceInfo()
  73:   {
  74:     Iterator deviceProviders = 
  75:     ServiceFactory.lookupProviders(MidiDeviceProvider.class);
  76:     List infoList = new ArrayList();
  77:     
  78:     while (deviceProviders.hasNext())
  79:     {
  80:       MidiDeviceProvider provider = (MidiDeviceProvider) deviceProviders.next();
  81:       MidiDevice.Info[] infos = provider.getDeviceInfo();
  82:       for (int i = infos.length; i > 0; )
  83:         infoList.add(infos[--i]);
  84:     }
  85:     
  86:     return (MidiDevice.Info[]) 
  87:     infoList.toArray(new MidiDevice.Info[infoList.size()]);
  88:   }
  89:   
  90:   /**
  91:    * Get the specified MIDI device.
  92:    * 
  93:    * @param info a description of the device we're looking for
  94:    * @return the requested MIDI device
  95:    * @throws MidiUnavailableException if no MIDI devices are configured or found
  96:    * @throws IllegalArgumentException if the device described by info is not found
  97:    */
  98:   public static MidiDevice getMidiDevice(MidiDevice.Info info) 
  99:     throws MidiUnavailableException
 100:   {
 101:     Iterator deviceProviders = 
 102:     ServiceFactory.lookupProviders(MidiDeviceProvider.class);
 103:     
 104:     if (! deviceProviders.hasNext())
 105:       throw new MidiUnavailableException("No MIDI device providers available.");
 106:     
 107:     do
 108:     {
 109:       MidiDeviceProvider provider = 
 110:         (MidiDeviceProvider) deviceProviders.next();
 111:       if (provider.isDeviceSupported(info))
 112:         return provider.getDevice(info);
 113:     } while (deviceProviders.hasNext());
 114:     
 115:     throw new IllegalArgumentException("MIDI device " 
 116:                        + info + " not available.");
 117:   }
 118:   
 119:   /**
 120:    * Get the default Receiver instance.  This just picks the first one
 121:    * it finds for now.
 122:    * 
 123:    * @return the default Receiver instance
 124:    * @throws MidiUnavailableException if no Receiver is found
 125:    */
 126:   public static Receiver getReceiver() throws MidiUnavailableException
 127:   {
 128:     // TODO: The 1.5 spec has a fancy mechanism to specify the default
 129:     // receiver device.  For now, well just return the first one we find.
 130:     MidiDevice.Info[] infos = getMidiDeviceInfo();
 131:     for (int i = 0; i < infos.length; i++)
 132:     {
 133:       MidiDevice device = getMidiDevice(infos[i]);
 134:       if (device instanceof Receiver)
 135:         return (Receiver) device;
 136:     }
 137:     throw new MidiUnavailableException("No Receiver device available");
 138:   }
 139: 
 140:   /**
 141:    * Get the default Transmitter instance.  This just picks the first one
 142:    * it finds for now.
 143:    * 
 144:    * @return the default Transmitter instance
 145:    * @throws MidiUnavailableException if no Transmitter is found
 146:    */
 147:   public static Transmitter getTransmitter() throws MidiUnavailableException
 148:   {
 149:     // TODO: The 1.5 spec has a fancy mechanism to specify the default
 150:     // Transmitter device.  For now, well just return the first one we find.
 151:     MidiDevice.Info[] infos = getMidiDeviceInfo();
 152:     for (int i = 0; i < infos.length; i++)
 153:     {
 154:       MidiDevice device = getMidiDevice(infos[i]);
 155:       if (device instanceof Transmitter)
 156:         return (Transmitter) device;
 157:     }
 158:     throw new MidiUnavailableException("No Transmitter device available");
 159:   }
 160: 
 161:   /**
 162:    * Get the default Synthesizer instance.  This just picks the first one
 163:    * it finds for now.
 164:    * 
 165:    * @return the default Synthesizer instance
 166:    * @throws MidiUnavailableException if no Synthesizer is found
 167:    */
 168:   public static Synthesizer getSynthesizer() throws MidiUnavailableException
 169:   {
 170:     // TODO: The 1.5 spec has a fancy mechanism to specify the default
 171:     // Synthesizer device.  For now, well just return the first one we find.
 172:     MidiDevice.Info[] infos = getMidiDeviceInfo();
 173:     for (int i = 0; i < infos.length; i++)
 174:     {
 175:       MidiDevice device = getMidiDevice(infos[i]);
 176:       if (device instanceof Synthesizer)
 177:         return (Synthesizer) device;
 178:     }
 179:     throw new MidiUnavailableException("No Synthesizer device available");
 180:   }
 181:   
 182:   /**
 183:    * Get the default Sequencer instance.  This just picks the first one
 184:    * it finds for now.
 185:    * 
 186:    * @return the default Sequencer instance
 187:    * @throws MidiUnavailableException if no Sequencer is found
 188:    */
 189:   public static Sequencer getSequencer() throws MidiUnavailableException
 190:   {
 191:     // TODO: The 1.5 spec has a fancy mechanism to specify the default
 192:     // Sequencer device.  For now, well just return the first one we find.
 193:     MidiDevice.Info[] infos = getMidiDeviceInfo();
 194:     for (int i = 0; i < infos.length; i++)
 195:     {
 196:       MidiDevice device = getMidiDevice(infos[i]);
 197:       if (device instanceof Sequencer)
 198:         return (Sequencer) device;
 199:     }
 200:     throw new MidiUnavailableException("No Sequencer device available");
 201:   }  
 202:   
 203:   /**
 204:    * Read a Soundbank object from the given stream.
 205:    * 
 206:    * @param stream the stream from which to read the Soundbank
 207:    * @return the Soundbank object
 208:    * @throws InvalidMidiDataException if we were unable to read the soundbank
 209:    * @throws IOException if an I/O error happened while reading
 210:    */
 211:   public static Soundbank getSoundbank(InputStream stream)
 212:     throws InvalidMidiDataException, IOException
 213:   {
 214:     Iterator readers = ServiceFactory.lookupProviders(SoundbankReader.class);
 215:     while (readers.hasNext())
 216:     {
 217:       SoundbankReader sr = (SoundbankReader) readers.next();
 218:       Soundbank sb = sr.getSoundbank(stream);
 219:       if (sb != null)
 220:         return sb;
 221:     }
 222:     throw new InvalidMidiDataException("Cannot read soundbank from stream");
 223:   }
 224: 
 225:   /**
 226:    * Read a Soundbank object from the given url.
 227:    * 
 228:    * @param url the url from which to read the Soundbank
 229:    * @return the Soundbank object
 230:    * @throws InvalidMidiDataException if we were unable to read the soundbank
 231:    * @throws IOException if an I/O error happened while reading
 232:    */
 233:   public static Soundbank getSoundbank(URL url)
 234:     throws InvalidMidiDataException, IOException
 235:   {
 236:     Iterator readers = ServiceFactory.lookupProviders(SoundbankReader.class);
 237:     while (readers.hasNext())
 238:     {
 239:       SoundbankReader sr = (SoundbankReader) readers.next();
 240:       Soundbank sb = sr.getSoundbank(url);
 241:       if (sb != null)
 242:         return sb;
 243:     }
 244:     throw new InvalidMidiDataException("Cannot read from url " + url);
 245:   }
 246: 
 247:   /**
 248:    * Read a Soundbank object from the given file.
 249:    * 
 250:    * @param file the file from which to read the Soundbank
 251:    * @return the Soundbank object
 252:    * @throws InvalidMidiDataException if we were unable to read the soundbank
 253:    * @throws IOException if an I/O error happened while reading
 254:    */
 255:   public static Soundbank getSoundbank(File file)
 256:     throws InvalidMidiDataException, IOException
 257:   {
 258:     Iterator readers = ServiceFactory.lookupProviders(SoundbankReader.class);
 259:     while (readers.hasNext())
 260:     {
 261:       SoundbankReader sr = (SoundbankReader) readers.next();
 262:       Soundbank sb = sr.getSoundbank(file);
 263:       if (sb != null)
 264:         return sb;
 265:     }
 266:     throw new InvalidMidiDataException("Cannot read soundbank from file " 
 267:                        + file);
 268:   } 
 269: 
 270:   /**
 271:    * Read a MidiFileFormat object from the given stream.
 272:    * 
 273:    * @param stream the stream from which to read the MidiFileFormat
 274:    * @return the MidiFileFormat object
 275:    * @throws InvalidMidiDataException if we were unable to read the MidiFileFormat
 276:    * @throws IOException if an I/O error happened while reading
 277:    */
 278:   public static MidiFileFormat getMidiFileFormat(InputStream stream)
 279:     throws InvalidMidiDataException, IOException
 280:   {
 281:     Iterator readers = ServiceFactory.lookupProviders(MidiFileReader.class);
 282:     while (readers.hasNext())
 283:     {
 284:       MidiFileReader sr = (MidiFileReader) readers.next();
 285:       MidiFileFormat sb = sr.getMidiFileFormat(stream);
 286:       if (sb != null)
 287:         return sb;
 288:     }
 289:     throw new InvalidMidiDataException("Can't read MidiFileFormat from stream");
 290:   }
 291: 
 292:   /**
 293:    * Read a MidiFileFormat object from the given url.
 294:    * 
 295:    * @param url the url from which to read the MidiFileFormat
 296:    * @return the MidiFileFormat object
 297:    * @throws InvalidMidiDataException if we were unable to read the MidiFileFormat
 298:    * @throws IOException if an I/O error happened while reading
 299:    */
 300:   public static MidiFileFormat getMidiFileFormat(URL url)
 301:     throws InvalidMidiDataException, IOException
 302:   {
 303:     Iterator readers = ServiceFactory.lookupProviders(MidiFileReader.class);
 304:     while (readers.hasNext())
 305:     {
 306:       MidiFileReader sr = (MidiFileReader) readers.next();
 307:       MidiFileFormat sb = sr.getMidiFileFormat(url);
 308:       if (sb != null)
 309:         return sb;
 310:     }
 311:     throw new InvalidMidiDataException("Cannot read from url " + url);
 312:   }
 313: 
 314:   /**
 315:    * Read a MidiFileFormat object from the given file.
 316:    * 
 317:    * @param file the file from which to read the MidiFileFormat
 318:    * @return the MidiFileFormat object
 319:    * @throws InvalidMidiDataException if we were unable to read the MidiFileFormat
 320:    * @throws IOException if an I/O error happened while reading
 321:    */
 322:   public static MidiFileFormat getMidiFileFormat(File file)
 323:     throws InvalidMidiDataException, IOException
 324:   {
 325:     Iterator readers = ServiceFactory.lookupProviders(MidiFileReader.class);
 326:     while (readers.hasNext())
 327:     {
 328:       MidiFileReader sr = (MidiFileReader) readers.next();
 329:       MidiFileFormat sb = sr.getMidiFileFormat(file);
 330:       if (sb != null)
 331:         return sb;
 332:     }
 333:     throw new InvalidMidiDataException("Can't read MidiFileFormat from file " 
 334:                                        + file);
 335:   } 
 336:   
 337:   /**
 338:    * Read a Sequence object from the given stream.
 339:    * 
 340:    * @param stream the stream from which to read the Sequence
 341:    * @return the Sequence object
 342:    * @throws InvalidMidiDataException if we were unable to read the Sequence
 343:    * @throws IOException if an I/O error happened while reading
 344:    */
 345:   public static Sequence getSequence(InputStream stream)
 346:     throws InvalidMidiDataException, IOException
 347:   {
 348:     Iterator readers = ServiceFactory.lookupProviders(MidiFileReader.class);
 349:     while (readers.hasNext())
 350:     {
 351:       MidiFileReader sr = (MidiFileReader) readers.next();
 352:       Sequence sq = sr.getSequence(stream);
 353:       if (sq != null)
 354:         return sq;
 355:     }
 356:     throw new InvalidMidiDataException("Can't read Sequence from stream");
 357:   }
 358: 
 359:   /**
 360:    * Read a Sequence object from the given url.
 361:    * 
 362:    * @param url the url from which to read the Sequence
 363:    * @return the Sequence object
 364:    * @throws InvalidMidiDataException if we were unable to read the Sequence
 365:    * @throws IOException if an I/O error happened while reading
 366:    */
 367:   public static Sequence getSequence(URL url)
 368:     throws InvalidMidiDataException, IOException
 369:   {
 370:     Iterator readers = ServiceFactory.lookupProviders(MidiFileReader.class);
 371:     while (readers.hasNext())
 372:     {
 373:       MidiFileReader sr = (MidiFileReader) readers.next();
 374:       Sequence sq = sr.getSequence(url);
 375:       if (sq != null)
 376:         return sq;
 377:     }
 378:     throw new InvalidMidiDataException("Cannot read from url " + url);
 379:   }
 380: 
 381:   /**
 382:    * Read a Sequence object from the given file.
 383:    * 
 384:    * @param file the file from which to read the Sequence
 385:    * @return the Sequence object
 386:    * @throws InvalidMidiDataException if we were unable to read the Sequence
 387:    * @throws IOException if an I/O error happened while reading
 388:    */
 389:   public static Sequence getSequence(File file)
 390:     throws InvalidMidiDataException, IOException
 391:   {
 392:     Iterator readers = ServiceFactory.lookupProviders(MidiFileReader.class);
 393:     while (readers.hasNext())
 394:     {
 395:       MidiFileReader sr = (MidiFileReader) readers.next();
 396:       Sequence sq = sr.getSequence(file);
 397:       if (sq != null)
 398:         return sq;
 399:     }
 400:     throw new InvalidMidiDataException("Can't read Sequence from file " 
 401:                                        + file);
 402:   } 
 403:   
 404:   /**
 405:    * Return an array of supported MIDI file types on this system.
 406:    * 
 407:    * @return the array of supported MIDI file types
 408:    */
 409:   public static int[] getMidiFileTypes()
 410:   {
 411:     // We only support a max of 3 MIDI file types.
 412:     boolean supported[] = new boolean[3];
 413:     // The number of supported formats.
 414:     int count = 0;
 415:     Iterator writers = ServiceFactory.lookupProviders(MidiFileWriter.class);
 416:     while (writers.hasNext())
 417:     {
 418:       MidiFileWriter fw = (MidiFileWriter) writers.next();
 419:       int types[] = fw.getMidiFileTypes();
 420:       for (int i = types.length; i > 0;)
 421:       {
 422:         int type = types[--i];
 423:         if (supported[type] == false)
 424:         {
 425:           count++;
 426:           supported[type] = true;
 427:         }
 428:       }
 429:     }
 430:     int result[] = new int[count];
 431:     for (int i = supported.length; i > 0;)
 432:     {
 433:       if (supported[--i])
 434:         result[--count] = i;
 435:     }
 436:     return result;
 437:   }
 438: 
 439:   /**
 440:    * Return true if the system supports writing files of type fileType.
 441:    * 
 442:    * @param fileType the MIDI file type we want to write
 443:    * @return true if we can write fileType files, false otherwise
 444:    */
 445:   public static boolean isFileTypeSupported(int fileType)
 446:   {
 447:     Iterator writers = ServiceFactory.lookupProviders(MidiFileWriter.class);
 448:     while (writers.hasNext())
 449:     {
 450:       MidiFileWriter fw = (MidiFileWriter) writers.next();
 451:       
 452:       if (fw.isFileTypeSupported(fileType))
 453:         return true;
 454:     }
 455:     return false;
 456:   }
 457:   
 458:   /**
 459:    * Return an array of supported MIDI file types on this system
 460:    * for the given sequnce.
 461:    * 
 462:    * @param sequence the sequnce to write
 463:    * @return the array of supported MIDI file types
 464:    */
 465:   public static int[] getMidiFileTypes(Sequence sequence)
 466:   {
 467:     // We only support a max of 3 MIDI file types.
 468:     boolean supported[] = new boolean[3];
 469:     // The number of supported formats.
 470:     int count = 0;
 471:     Iterator writers = ServiceFactory.lookupProviders(MidiFileWriter.class);
 472:     while (writers.hasNext())
 473:     {
 474:       MidiFileWriter fw = (MidiFileWriter) writers.next();
 475:       int types[] = fw.getMidiFileTypes(sequence);
 476:       for (int i = types.length; i > 0;)
 477:       {
 478:         int type = types[--i];
 479:         if (supported[type] == false)
 480:         {
 481:           count++;
 482:           supported[type] = true;
 483:         }
 484:       }
 485:     }
 486:     int result[] = new int[count];
 487:     for (int i = supported.length; i > 0;)
 488:     {
 489:       if (supported[--i])
 490:         result[--count] = i;
 491:     }
 492:     return result;
 493:   }
 494:   
 495:   /**
 496:    * Return true if the system supports writing files of type fileType
 497:    * for the given sequence.
 498:    * 
 499:    * @param fileType the MIDI file type we want to write
 500:    * @param sequence the Sequence we want to write
 501:    * @return true if we can write fileType files for sequence, false otherwise
 502:    */
 503:   public static boolean isFileTypeSupported(int fileType, Sequence sequence)
 504:   {
 505:     Iterator writers = ServiceFactory.lookupProviders(MidiFileWriter.class);
 506:     while (writers.hasNext())
 507:     {
 508:       MidiFileWriter fw = (MidiFileWriter) writers.next();
 509:       
 510:       if (fw.isFileTypeSupported(fileType, sequence))
 511:         return true;
 512:     }
 513:     return false;
 514:   }
 515: 
 516:   /**
 517:    * Write a sequence to an output stream using a specific MIDI file format.
 518:    * 
 519:    * @param in the sequence to write
 520:    * @param fileType the MIDI file format to use
 521:    * @param out the output stream to write to
 522:    * @return the number of bytes written
 523:    * @throws IOException if an I/O exception happens
 524:    * @throws IllegalArgumentException if fileType is not supported for in
 525:    */
 526:   public static int write(Sequence in, int fileType, OutputStream out)
 527:     throws IOException
 528:   {
 529:     Iterator writers = ServiceFactory.lookupProviders(MidiFileWriter.class);
 530:     while (writers.hasNext())
 531:     {
 532:       MidiFileWriter fw = (MidiFileWriter) writers.next();
 533:     
 534:       if (fw.isFileTypeSupported(fileType, in))
 535:         return fw.write(in, fileType, out);
 536:     }
 537:     throw new IllegalArgumentException("File type " 
 538:                        + fileType + " is not supported");
 539:   }
 540: 
 541:   /**
 542:    * Write a sequence to a file using a specific MIDI file format.
 543:    * 
 544:    * @param in the sequence to write
 545:    * @param fileType the MIDI file format to use
 546:    * @param out the file to write to
 547:    * @return the number of bytes written
 548:    * @throws IOException if an I/O exception happens
 549:    * @throws IllegalArgumentException if fileType is not supported for in
 550:    */
 551:   public static int write(Sequence in, int fileType, File out)
 552:     throws IOException
 553:   {
 554:     Iterator writers = ServiceFactory.lookupProviders(MidiFileWriter.class);
 555:     while (writers.hasNext())
 556:     {
 557:       MidiFileWriter fw = (MidiFileWriter) writers.next();
 558:     
 559:       if (fw.isFileTypeSupported(fileType, in))
 560:         return fw.write(in, fileType, out);
 561:     }
 562:     throw new IllegalArgumentException("File type " 
 563:                        + fileType + " is not supported");
 564:   }
 565: }