package ddf.minim;
import ddf.minim.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();
}
}