Mega Code Archive

 
Categories / Java by API / Javax Sound Sampled
 

New DataLine Info Info(Class lineClass, AudioFormat format)

/*  * Copyright (c) 2004 David Flanagan.  All rights reserved.  * This code is from the book Java Examples in a Nutshell, 3nd Edition.  * It is provided AS-IS, WITHOUT ANY WARRANTY either expressed or implied.  * You may study, use, and modify it for any non-commercial purpose,  * including teaching and use in open-source projects.  * You may distribute it non-commercially as long as you retain this notice.  * For a commercial use license, or to purchase the book,   * please visit http://www.davidflanagan.com/javaexamples3.  */ import java.io.IOException; import java.net.URL; import javax.sound.midi.InvalidMidiDataException; import javax.sound.midi.MetaEventListener; import javax.sound.midi.MetaMessage; import javax.sound.midi.MidiSystem; import javax.sound.midi.MidiUnavailableException; import javax.sound.midi.Sequencer; import javax.sound.midi.Synthesizer; import javax.sound.sampled.AudioFormat; import javax.sound.sampled.AudioInputStream; import javax.sound.sampled.AudioSystem; import javax.sound.sampled.DataLine; import javax.sound.sampled.LineUnavailableException; import javax.sound.sampled.SourceDataLine; import javax.sound.sampled.UnsupportedAudioFileException; /**  * This class plays sounds streaming from a URL: it does not have to preload the  * entire sound into memory before playing it. It is a command-line application  * with no gui. It includes code to convert ULAW and ALAW audio formats to PCM  * so they can be played. Use the -m command-line option before MIDI files.  */ public class Main {   // Create a URL from the command-line argument and pass it to the   // right static method depending on the presence of the -m (MIDI) option.   public static void main(String[] args) throws Exception {     if (args[0].equals("-m"))       streamMidiSequence(new URL(args[1]));     else       streamSampledAudio(new URL(args[0]));     // Exit explicitly.     // This is needed because the audio system starts background threads.     System.exit(0);   }   /** Read sampled audio data from the specified URL and play it */   public static void streamSampledAudio(URL url) throws IOException, UnsupportedAudioFileException,       LineUnavailableException {     AudioInputStream ain = null; // We read audio data from here     SourceDataLine line = null; // And write it here.     try {       // Get an audio input stream from the URL       ain = AudioSystem.getAudioInputStream(url);       // Get information about the format of the stream       AudioFormat format = ain.getFormat();       DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);       // If the format is not supported directly (i.e. if it is not PCM       // encoded, then try to transcode it to PCM.       if (!AudioSystem.isLineSupported(info)) {         // This is the PCM format we want to transcode to.         // The parameters here are audio format details that you         // shouldn't need to understand for casual use.         AudioFormat pcm = new AudioFormat(format.getSampleRate(), 16, format.getChannels(), true,             false);         // Get a wrapper stream around the input stream that does the         // transcoding for us.         ain = AudioSystem.getAudioInputStream(pcm, ain);         // Update the format and info variables for the transcoded data         format = ain.getFormat();         info = new DataLine.Info(SourceDataLine.class, format);       }       // Open the line through which we'll play the streaming audio.       line = (SourceDataLine) AudioSystem.getLine(info);       line.open(format);       // Allocate a buffer for reading from the input stream and writing       // to the line. Make it large enough to hold 4k audio frames.       // Note that the SourceDataLine also has its own internal buffer.       int framesize = format.getFrameSize();       byte[] buffer = new byte[4 * 1024 * framesize]; // the buffer       int numbytes = 0; // how many bytes       // We haven't started the line yet.       boolean started = false;       for (;;) { // We'll exit the loop when we reach the end of stream         // First, read some bytes from the input stream.         int bytesread = ain.read(buffer, numbytes, buffer.length - numbytes);         // If there were no more bytes to read, we're done.         if (bytesread == -1)           break;         numbytes += bytesread;         // Now that we've got some audio data, to write to the line,         // start the line, so it will play that data as we write it.         if (!started) {           line.start();           started = true;         }         // We must write bytes to the line in an integer multiple of         // the framesize. So figure out how many bytes we'll write.         int bytestowrite = (numbytes / framesize) * framesize;         // Now write the bytes. The line will buffer them and play         // them. This call will block until all bytes are written.         line.write(buffer, 0, bytestowrite);         // If we didn't have an integer multiple of the frame size,         // then copy the remaining bytes to the start of the buffer.         int remaining = numbytes - bytestowrite;         if (remaining > 0)           System.arraycopy(buffer, bytestowrite, buffer, 0, remaining);         numbytes = remaining;       }       // Now block until all buffered sound finishes playing.       line.drain();     } finally { // Always relinquish the resources we use       if (line != null)         line.close();       if (ain != null)         ain.close();     }   }   // A MIDI protocol constant that isn't defined by javax.sound.midi   public static final int END_OF_TRACK = 47;   /* MIDI or RMF data from the specified URL and play it */   public static void streamMidiSequence(URL url) throws IOException, InvalidMidiDataException,       MidiUnavailableException {     Sequencer sequencer = null; // Converts a Sequence to MIDI events     Synthesizer synthesizer = null; // Plays notes in response to MIDI events     try {       // Create, open, and connect a Sequencer and Synthesizer       // They are closed in the finally block at the end of this method.       sequencer = MidiSystem.getSequencer();       sequencer.open();       synthesizer = MidiSystem.getSynthesizer();       synthesizer.open();       sequencer.getTransmitter().setReceiver(synthesizer.getReceiver());       // Specify the InputStream to stream the sequence from       sequencer.setSequence(url.openStream());       // This is an arbitrary object used with wait and notify to       // prevent the method from returning before the music finishes       final Object lock = new Object();       // Register a listener to make the method exit when the stream is       // done. See Object.wait() and Object.notify()       sequencer.addMetaEventListener(new MetaEventListener() {         public void meta(MetaMessage e) {           if (e.getType() == END_OF_TRACK) {             synchronized (lock) {               lock.notify();             }           }         }       });       // Start playing the music       sequencer.start();       // Now block until the listener above notifies us that we're done.       synchronized (lock) {         while (sequencer.isRunning()) {           try {             lock.wait();           } catch (InterruptedException e) {           }         }       }     } finally {       // Always relinquish the sequencer, so others can use it.       if (sequencer != null)         sequencer.close();       if (synthesizer != null)         synthesizer.close();     }   } }