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(); } }