sound.player
Class SoundPlayback

java.lang.Object
  extended by sound.player.SoundPlayback

public class SoundPlayback
extends java.lang.Object

Overview

A buffer supporting the real-time playback of audio and the writing of audio data to a sound file. Single channel (mono) and multichannel audio (stereo) are supported. This class, along with SoundCapture, intends to provide an easy to use interface to Java Sound, Java's audio API. Java Sound supports the writing of audio data to a sound file or the computer's audio output port, but only affineTransform the byte level, which is audio format specific. This class, however, provides higher level support for the writing of double or integer valued samples to the computer's audio output port or any supported sound file type. This class is therefore useful when it one desires to playback audio samples in an audio format independent way.

Depending on available system resources, it may be possible to run an instance of this class and an instance of SoundCapture concurrently. This allows for the concurrent capture, signal processing, and playback of audio data.

Usage

Two constructors are provided. One constructor creates a sound playback object that sends audio data to the speaker. If this constructor is used, there will be a small delay between the time that the audio data is delivered to this object and the time that the corresponding audio is actually heard. This latency can be adjusted by setting the bufferSize constructor parameter. Another constructor creates a sound playback object that sends audio data to a sound file.

After calling the appropriate constructor, startPlayback() must be called to initialize the audio system. The putSamples() or putSamplesInt() method should then be repeatedly called to deliver the audio data to the audio output device (speaker or file). The audio samples delivered to putSamples() should be in the proper range, or clipping will occur. putSamples() expects the samples to be in the range (-1, 1). putSamplesInt() expects the samples to be in the range (-2^(bits_per_sample/2), 2^(bits_per_sample/2)), where bits_per_sample is the number of bits per sample. Note that it is possible (but probably not useful) to interleave calls to putSamples() and putSamplesInt(). Finally, after no more audio playback is desired, stopPlayback() should be called to free up audio system resources.

Security issues

Applications have no restrictions on the capturing or playback of audio. Applet code is not allowed to write native files by default. The .java.policy file must be modified to grant applets more privileges.

Note: Requires Java 2 v1.3.0 or later.

Since:
Ptolemy II 1.0
Version:
$Id: SoundPlayback.java,v 1.39 2003/04/11 16:15:19 cxh Exp $
Author:
Brian K. Vogel

Constructor Summary
SoundPlayback(float sampleRate, int sampleSizeInBits, int channels, int bufferSize, int putSamplesSize)
          Construct a sound playback object that plays audio through the computer's speaker.
SoundPlayback(java.lang.String fileName, float sampleRate, int sampleSizeInBits, int channels, int bufferSize, int putSamplesSize)
          Construct a sound playback object that writes audio to a sound file with the specified name.
 
Method Summary
 void putSamples(double[][] putSamplesArray)
          Play an array of audio samples.
 void putSamplesInt(int[][] putSamplesArray)
          Play an array of audio samples.
 void startPlayback()
          Perform initialization for the playback of audio data.
 void stopPlayback()
          Stop playing/writing audio.
 
Methods inherited from class java.lang.Object
equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Constructor Detail

SoundPlayback

public SoundPlayback(float sampleRate,
                     int sampleSizeInBits,
                     int channels,
                     int bufferSize,
                     int putSamplesSize)
Construct a sound playback object that plays audio through the computer's speaker. Note that when this constructor is used, putSamples() should be called often enough to prevent underflow of the internal audio input buffer.

Parameters:
sampleRate - Sample rate in Hz. Must be in the range: 8000 to 48000.
sampleSizeInBits - Number of bits per sample (valid choices are 8 or 16).
channels - Number of audio channels. 1 for mono, 2 for stereo, etc.
bufferSize - Requested size of the internal audio input buffer in samples. This controls the latency (delay from the time putSamples() is called until the audio is actually heard). A lower bound on the latency is given by (bufferSize / sampleRate) seconds. Ideally, the smallest value that gives acceptable performance (no underflow) should be used. Typical values are about 1/10 th the sample rate. For example, affineTransform 44100 Hz sample rate, a typical buffer size value might be 4410.
putSamplesSize - Size of the array parameter of putSamples(). For performance reasons, the size should be chosen smaller than bufferSize. Typical values are 1/2 to 1/16 th of bufferSize.

SoundPlayback

public SoundPlayback(java.lang.String fileName,
                     float sampleRate,
                     int sampleSizeInBits,
                     int channels,
                     int bufferSize,
                     int putSamplesSize)
Construct a sound playback object that writes audio to a sound file with the specified name. Valid sound file formats are WAVE (.wav), AIFF (.aif, .aiff), AU (.au). The file format is automatically determined from the file extension. The sound file will be initialized when startPlayback() is called. If there is a problem creating the sound file, an IOException will be thrown in startPlayback(). Thereafter, each call to putSamples() will add putSamplesSize samples to the sound file. To close and save the sound file, call stopPlayback().

Note that the audio data will not actually be saved to file, fileName, until stopPlayback() is called. If an unknown audio format is used, an exception will be thrown in stopPlayback().

Parameters:
fileName - The file name to create. If the file already exists, overwrite it. Valid sound file formats are WAVE (.wav), AIFF (.aif, .aiff), AU (.au). The file format to write is determined automatically from the file extension.
sampleRate - Sample rate in Hz. Must be in the range: 8000 to 48000.
sampleSizeInBits - Number of bits per sample (valid choices are 8 or 16).
channels - Number of audio channels. 1 for mono, 2 for stereo.
putSamplesSize - Size of the array parameter of putSamples(). There is no restriction on the value of this parameter, but typical values are 64-2024.
Method Detail

putSamples

public void putSamples(double[][] putSamplesArray)
                throws java.io.IOException,
                       java.lang.IllegalStateException
Play an array of audio samples. If the "play audio to speaker" constructor was called, then queue the array of audio samples in putSamplesArray for playback. There will be a latency before the audio data is actually heard, since the audio data in putSamplesArray is queued to an internal audio buffer. The size of the internal buffer is set by the constructor. A lower bound on the latency is given by (bufferSize / sampleRate) seconds. If the "play audio to speaker" mode is used, then this method should be invoked often enough to prevent underflow of the internal audio buffer. Underflow is undesirable since it will cause audible gaps in audio playback, but no exception or error condition will occur. If the caller attempts to write more data than can be written, this method blocks until the data can be written to the internal audio buffer.

If the "write audio to file" constructor was used, then append the audio data contained in putSamplesArray to the sound file specified in the constructor. Note that underflow cannot occur for this case.

The samples should be in the range (-1, 1). Samples that are outside ths range will be hard-clipped so that they fall within this range.

Parameters:
putSamplesArray - A two dimensional array containing the samples to play or write to a file. The first index represents the channel number (0 for first channel, 1 for second channel, etc.). The second index represents the sample index within a channel. For example, putSamplesArray[n][m] contains the (m+1)th sample of the (n+1)th channel. putSamplesArray should be a rectangular array such that putSamplesArray.length() gives the number of channels and putSamplesArray[n].length() is equal to putSamplesSize, for all channels n. This is not actually checked, however.
Throws:
java.io.IOException - If there is a problem playing audio.
java.lang.IllegalStateException - If audio playback is currently inactive. That is, If startPlayback() has not yet been called or if stopPlayback() has already been called.

putSamplesInt

public void putSamplesInt(int[][] putSamplesArray)
                   throws java.io.IOException,
                          java.lang.IllegalStateException
Play an array of audio samples. If the "play audio to speaker" constructor was called, then queue the array of audio samples in putSamplesArray for playback. The samples should be in the range (-2^(bits_per_sample/2), 2^(bits_per_sample/2)). There will be a latency before the audio data is actually heard, since the audio data in putSamplesArray is queued to an internal audio buffer. The size of the internal buffer is set by the constructor. A lower bound on the latency is given by (bufferSize / sampleRate) seconds. If the "play audio to speaker" mode is used, then this method should be invoked often enough to prevent underflow of the internal audio buffer.

If the "write audio to file" constructor was used, then append the audio data contained in putSamplesArray to the sound file specified in the constructor.

The samples should be in the range (-2^(bits_per_sample/2), 2^(bits_per_sample/2)). Samples that are outside this range will be hard-clipped.

Parameters:
putSamplesArray - A two dimensional array containing the samples to play or write to a file. The first index represents the channel number (0 for first channel, 1 for second channel, etc.). The second index represents the sample index within a channel. For example, putSamplesArray[n][m] contains the (m+1)th sample of the (n+1)th channel. putSamplesArray should be a rectangular array such that putSamplesArray.length() gives the number of channels and putSamplesArray[n].length() is equal to putSamplesSize, for all channels n. This is not actually checked, however.
Throws:
java.io.IOException - If there is a problem playing audio.
java.lang.IllegalStateException - If audio playback is currently inactive. That is, If startPlayback() has not yet been called or if stopPlayback() has already been called.

startPlayback

public void startPlayback()
                   throws java.io.IOException,
                          java.lang.IllegalStateException
Perform initialization for the playback of audio data. This method must be invoked prior to the first invocation of putSamples(). This method must not be called more than once between invocations of stopPlayback(), or an exception will be thrown.

Throws:
java.io.IOException - If there is a problem setting up the system for audio playback. This will occur if a file cannot be opened or if the audio out port cannot be accessed.
java.lang.IllegalStateException - If this method is called more than once between invocations of stopCapture().

stopPlayback

public void stopPlayback()
                  throws java.io.IOException
Stop playing/writing audio. This method should be called when no more calls to putSamples(). are required, so that the system resources involved in the audio playback may be freed.

If the "write audio data to file" constructor was used, then the sound file specified by the constructor is saved and closed.

Throws:
java.io.IOException - If there is a problem closing the audio resources, or if the "write audio data to file" constructor was used and the sound file has an unsupported format.