package ddf.minim;
import javax.sound.sampled.AudioFormat;
import ddf.minim.spi.AudioOut;
/**
* An <code>AudioSource</code> is a kind of wrapper around an
* <code>AudioStream</code>. An <code>AudioSource</code> will add its
* <code>AudioBuffer</code>s as listeners on the stream so that you can access
* the stream's samples without having to implement <code>AudioListener</code>
* yourself. It also provides the <code>Effectable</code> and
* <code>Recordable</code> interface. Because an <code>AudioStream</code> must
* be closed when you are finished with it, you must remember to call
* {@link #close()} on any <code>AudioSource</code>s you obtain from Minim, such
* as <code>AudioInput</code>s, <code>AudioOutput</code>s, and
* <code>AudioPlayer</code>s.
*
* @author Damien Di Fede
* @invisible
*
*/
public class AudioSource extends Controller implements Effectable, Recordable
{
// the instance of Minim that created us, if one did.
Minim parent;
private AudioOut stream;
// the signal splitter used to manage listeners to the source
// our stereobuffer will be the first in the list
private SignalSplitter splitter;
// the StereoBuffer that will subscribe to synth
private StereoBuffer buffer;
// the effects chain used for effecting
private EffectsChain effects;
/**
* The AudioBuffer containing the left channel samples. If this is a mono
* sound, it contains the single channel of audio.
*
* @example Basics/PlayAFile
*
* @related AudioBuffer
*/
public final AudioBuffer left;
/**
* The AudioBuffer containing the right channel samples. If this is a mono
* sound, <code>right</code> contains the same samples as
* <code>left</code>.
*
* @example Basics/PlayAFile
*
* @related AudioBuffer
*/
public final AudioBuffer right;
/**
* The AudioBuffer containing the mix of the left and right channels. If this is
* a mono sound, <code>mix</code> contains the same
* samples as <code>left</code>.
*
* @example Basics/PlayAFile
*
* @related AudioBuffer
*/
public final AudioBuffer mix;
/**
* Constructs an <code>AudioSource</code> that will subscribe to the samples
* in <code>stream</code>. It is expected that the stream is using a
* <code>DataLine</code> for playback. If it is not, calls to
* <code>Controller</code>'s methods will result in a
* <code>NullPointerException</code>.
*
* @param istream
* the <code>AudioStream</code> to subscribe to and wrap
*
* @invisible
*/
public AudioSource(AudioOut istream)
{
super( istream.getControls() );
stream = istream;
// we gots a buffer for users to poll
buffer = new StereoBuffer( stream.getFormat().getChannels(),
stream.bufferSize(), this );
left = buffer.left;
right = buffer.right;
mix = buffer.mix;
// we gots a signal splitter that we'll add any listeners the user wants
splitter = new SignalSplitter( stream.getFormat(), stream.bufferSize() );
// we stick our buffer in the signal splitter because we can only set
// one
// listener on the stream
splitter.addListener( buffer );
// and there it goes.
stream.setAudioListener( splitter );
// we got an effects chain that we'll add user effects to
effects = new EffectsChain();
// we set it as the effect on the stream
stream.setAudioEffect( effects );
stream.open();
}
/**
* Closes this source, making it unavailable.
*
* @invisible
*/
public void close()
{
Minim.debug( "Closing " + this.toString() );
stream.close();
// if we have a parent, tell them to stop tracking us
// so that we can get garbage collected
if ( parent != null )
{
parent.removeSource( this );
}
}
/** @deprecated */
public void addEffect(AudioEffect effect)
{
effects.add( effect );
}
/** @deprecated */
public void clearEffects()
{
effects.clear();
}
/** @deprecated */
public void disableEffect(int i)
{
effects.disable( i );
}
/** @deprecated */
public void disableEffect(AudioEffect effect)
{
effects.disable( effect );
}
/** @deprecated */
public int effectCount()
{
return effects.size();
}
/** @deprecated */
public void effects()
{
effects.enableAll();
}
/** @deprecated */
public boolean hasEffect(AudioEffect e)
{
return effects.contains( e );
}
/** @deprecated */
public void enableEffect(int i)
{
effects.enable( i );
}
/** @deprecated */
public void enableEffect(AudioEffect effect)
{
effects.enable( effect );
}
/** @deprecated */
public AudioEffect getEffect(int i)
{
return effects.get( i );
}
/** @deprecated */
public boolean isEffected()
{
return effects.hasEnabled();
}
/** @deprecated */
public boolean isEnabled(AudioEffect effect)
{
return effects.isEnabled( effect );
}
/** @deprecated */
public void noEffects()
{
effects.disableAll();
}
/** @deprecated */
public void removeEffect(AudioEffect effect)
{
effects.remove( effect );
}
/** @deprecated */
public AudioEffect removeEffect(int i)
{
return effects.remove( i );
}
/**
* Add an AudioListener to this sound generating object,
* which will have its samples method called every time
* this object generates a new buffer of samples.
*
* @shortdesc Add an AudioListener to this sound generating object.
*
* @example Advanced/AddAndRemoveAudioListener
*
* @param listener
* the AudioListener that will listen to this
*
* @related AudioListener
*/
public void addListener( AudioListener listener )
{
splitter.addListener( listener );
}
/**
* The internal buffer size of this sound object.
* The left, right, and mix AudioBuffers of this object
* will be this large, and sample buffers passed to
* AudioListeners added to this object will be this large.
*
* @shortdesc The internal buffer size of this sound object.
*
* @example Basics/PlayAFile
*
* @return int: the internal buffer size of this sound object, in sample frames.
*/
public int bufferSize()
{
return stream.bufferSize();
}
/**
* Returns an AudioFormat object that describes the audio properties
* of this sound generating object. This is often useful information
* when doing sound analysis or some synthesis, but typically you
* will not need to know about the specific format.
*
* @shortdesc Returns AudioFormat object that describes the audio properties
* of this sound generating object.
*
* @example Advanced/GetAudioFormat
*
* @return an AudioFormat describing this sound object.
*/
public AudioFormat getFormat()
{
return stream.getFormat();
}
/**
* Removes an AudioListener that was previously
* added to this sound object.
*
* @example Advanced/AddAndRemoveAudioListener
*
* @param listener
* the AudioListener that should stop listening to this
*
* @related AudioListener
*/
public void removeListener( AudioListener listener )
{
splitter.removeListener( listener );
}
/**
* The type is an int describing the number of channels
* this sound object has.
*
* @return Minim.MONO if this is mono, Minim.STEREO if this is stereo
*/
public int type()
{
return stream.getFormat().getChannels();
}
/**
* Returns the sample rate of this sound object.
*
* @return the sample rate of this sound object.
*/
public float sampleRate()
{
return stream.getFormat().getSampleRate();
}
}