001/* MidiSystem.java -- Access system MIDI resources 002 Copyright (C) 2005 Free Software Foundation, Inc. 003 004This file is part of GNU Classpath. 005 006GNU Classpath is free software; you can redistribute it and/or modify 007it under the terms of the GNU General Public License as published by 008the Free Software Foundation; either version 2, or (at your option) 009any later version. 010 011GNU Classpath is distributed in the hope that it will be useful, but 012WITHOUT ANY WARRANTY; without even the implied warranty of 013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014General Public License for more details. 015 016You should have received a copy of the GNU General Public License 017along with GNU Classpath; see the file COPYING. If not, write to the 018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 01902110-1301 USA. 020 021Linking this library statically or dynamically with other modules is 022making a combined work based on this library. Thus, the terms and 023conditions of the GNU General Public License cover the whole 024combination. 025 026As a special exception, the copyright holders of this library give you 027permission to link this library with independent modules to produce an 028executable, regardless of the license terms of these independent 029modules, and to copy and distribute the resulting executable under 030terms of your choice, provided that you also meet, for each linked 031independent module, the terms and conditions of the license of that 032module. An independent module is a module which is not derived from 033or based on this library. If you modify this library, you may extend 034this exception to your version of the library, but you are not 035obligated to do so. If you do not wish to do so, delete this 036exception statement from your version. */ 037 038 039package javax.sound.midi; 040 041import gnu.classpath.ServiceFactory; 042 043import java.io.File; 044import java.io.IOException; 045import java.io.InputStream; 046import java.io.OutputStream; 047import java.net.URL; 048import java.util.ArrayList; 049import java.util.List; 050import java.util.Iterator; 051 052import javax.sound.midi.spi.MidiDeviceProvider; 053import javax.sound.midi.spi.MidiFileReader; 054import javax.sound.midi.spi.MidiFileWriter; 055import 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 */ 065public 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}