package ddf.minim.ugens; import ddf.minim.UGen; /** * <p> * The Bypass UGen allows you to wrap another UGen and then insert that UGen into your * signal chain using Bypass in its place. You can then dynamically route the * audio through the wrapped UGen or simply allow incoming audio to pass through unaffected. * Using a Bypass UGen allows you to avoid concurrency issues caused by patching and unpatching * during runtime from a Thread other than the audio one. * </p> * <p> * Your usage of Bypass might look something like this: * </p> * <pre> * Bypass<GranulateSteady> granulate = new Bypass( new GranulateSteady() ); * filePlayer.patch( granulate ).patch( mainOut ); * </pre> * <p> * If you needed to patch something else to one of the inputs of the GranulateSteady, * you'd use the <code>ugen</code> method of Bypass to retrieve the wrapped UGen * and operate on it: * </p> * <pre> * grainLenLine.patch( granulate.ugen().grainLen ); * </pre> * <p> * Now, calling the <code>activate</code> method will <em>bypass</em> the granulate effect * so that the Bypass object outputs the audio that is coming into it. Calling the * <code>deactivate</code> method will route the audio through the wrapped effect. The * <code>isActive</code> method indicates whether or not the wrapped effect is currently * being bypassed. * </p> * * @author Damien Di Fede * * @param <T> The type of UGen being wrapped, like GranulateSteady. * * @related UGen * * @example Synthesis/bypassExample */ public class Bypass<T extends UGen> extends UGen { private T mUGen; // do NOT allow people to patch directly to this! private UGenInput audio; private boolean mActive; /** * Construct a Bypass UGen that wraps a UGen of type T. * * @param ugen * the UGen that this can bypass */ public Bypass( T ugen ) { mUGen = ugen; audio = addAudio(); mActive = false; } /** * Retrieve the UGen that this Bypass is wrapping. * * @return the wrapped UGen, cast to the class this Bypass was constructed with. * * @example Synthesis/bypassExample * * @related Bypass */ public T ugen() { return mUGen; } @Override protected void sampleRateChanged() { mUGen.setSampleRate( sampleRate() ); } @Override protected void addInput( UGen input ) { audio.setIncomingUGen( input ); input.patch( mUGen ); } @Override protected void removeInput( UGen input ) { if ( audio.getIncomingUGen() == input ) { audio.setIncomingUGen(null); input.unpatch( mUGen ); } } public void setChannelCount( int channelCount ) { // this will set our audio input properly super.setChannelCount(channelCount); // but we also need to let our wrapped UGen know mUGen.setChannelCount(channelCount); } /** * Activate the bypass functionality. In other words, the wrapped UGen will NOT * have an effect on the UGen patched to this Bypass. * * @example Synthesis/bypassExample * * @related Bypass */ public void activate() { mActive = true; } /** * Deactivate the bypass functionality. In other words, the wrapped UGen WILL * have an effect on the UGen patched to this Bypass, as if it was in the * signal chain in place of this Bypass. * * @example Synthesis/bypassExample * * @related Bypass */ public void deactivate() { mActive = false; } /** * Find out if this Bypass is active or not. * * @return true if the bypass functionality is on. * * @example Synthesis/bypassExample * * @related Bypass */ public boolean isActive() { return mActive; } @Override protected void uGenerate(float[] channels) { mUGen.tick(channels); // but stomp the result if we are active if ( mActive ) { System.arraycopy(audio.getLastValues(), 0, channels, 0, channels.length); } } }