package ddf.minim.ugens; import ddf.minim.UGen; /** * A UGen which chops the incoming audio into steady grains * of sound. The envelope of these sounds has a linear fade * in and fade out. * * @example Synthesis/granulateSteadyExample * * @related UGen * @related GranulateRandom * * @author Anderson Mills * */ public class GranulateSteady extends UGen { /** * The default input is "audio." * * @related GranulateSteady */ public UGenInput audio; /** * Controls the length of each grain. * * @related GranulateSteady */ public UGenInput grainLen; /** * Controls the space between each grain. * * @related GranulateSteady */ public UGenInput spaceLen; /** * Controls the length of the fade in and fade out. * * @related GranulateSteady */ public UGenInput fadeLen; // variables to determine the current placement WRT a grain private boolean insideGrain; private float timeSinceGrainStart; private float timeSinceGrainStop; private float timeStep; // variables to keep track of the grain values // these are only set when appropriate for the algorithm // the user-manipulated values are held by the inputs private float grainLength = 0.010f; private float spaceLength = 0.020f; private float fadeLength = 0.0025f; private float minAmp = 0.0f; private float maxAmp = 1.0f; /** * Constructor for GranulateSteady. * grainLength, length of each grain, defaults to 10 msec. * spaceLength, space between each grain, defaults to 20 msec. * fadeLength, length of the linear fade in and fade out of the grain envelope, defaults to 2.5 msec. * minAmp, minimum amplitude of the envelope, defaults to 0. * maxAmp, maximum amplitude of the envelope, defaults to 1. */ public GranulateSteady() { this( 0.01f, 0.02f, 0.0025f, 0.0f, 1.0f ); } /** * Constructor for GranulateSteady. * minAmp, minimum amplitude of the envelope, defaults to 0. * maxAmp, maximum amplitude of the envelope, defaults to 1. * * @param grainLength * float: length of each grain in seconds * @param spaceLength * float: space between each grain in seconds * @param fadeLength * float: length of the linear fade in and fade out of the grain envelope in seconds */ public GranulateSteady( float grainLength, float spaceLength, float fadeLength ) { this( grainLength, spaceLength, fadeLength, 0.0f, 1.0f ); } /** * Constructor for GranulateSteady. * @param grainLength * float: length of each grain in seconds * @param spaceLength * float: space between each grain in seconds * @param fadeLength * float: length of the linear fade in and fade out of the grain envelope in seconds * @param minAmp * float: minimum amplitude of the envelope * @param maxAmp * float: maximum amplitude of the envelope */ public GranulateSteady( float grainLength, float spaceLength, float fadeLength, float minAmp, float maxAmp ) { super(); // jam3: These can't be instantiated until the uGenInputs ArrayList // in the super UGen has been constructed audio = new UGenInput(InputType.AUDIO); grainLen = new UGenInput( InputType.CONTROL ); spaceLen = new UGenInput( InputType.CONTROL ); fadeLen = new UGenInput( InputType.CONTROL ); //amplitude = new UGenInput(InputType.CONTROL); setAllParameters( grainLength, spaceLength, fadeLength, minAmp, maxAmp ); insideGrain = true; timeSinceGrainStart = 0.0f; timeSinceGrainStop = 0.0f; timeStep = 0.0f; } /** * Use this method to notify GranulateSteady that the sample rate has changed. */ protected void sampleRateChanged() { timeStep = 1.0f/sampleRate(); } /** * Immediately sets all public class members concerning time to new values. * @param grainLength * float: grain length of each grain in seconds * @param spaceLength * float: space between each grain in seconds * @param fadeLength * float: length of the linear fade in and fade out of the grain envelope in seconds * * @related GranulateSteady */ public void setAllTimeParameters( float grainLength, float spaceLength, float fadeLength ) { setAllParameters( grainLength, spaceLength, fadeLength, minAmp, maxAmp ); } /** * Immediately sets all public class members to new values. * * @param grainLength * float: grain length of each grain in seconds * @param spaceLength * float: space between each grain in seconds * @param fadeLength * float: length of the linear fade in and fade out of the grain envelope in seconds * @param minAmp * float: minimum amplitude of the envelope * @param maxAmp * float: maximum amplitude of the envelope * * @related GranulateSteady */ public void setAllParameters( float grainLength, float spaceLength, float fadeLength, float minAmp, float maxAmp) { grainLen.setLastValue(grainLength); spaceLen.setLastValue(spaceLength); fadeLen.setLastValue(fadeLength); this.grainLength = grainLength; this.spaceLength = spaceLength; this.fadeLength = fadeLength; this.minAmp = minAmp; this.maxAmp = maxAmp; } /** * Sets the state of this granulate to the very start of a grain. * Useful for syncing the granulate timing with other audio. * * @related GranulateSteady */ public void reset() { // start the grain timeSinceGrainStart = 0.0f; insideGrain = true; // only set the grain values at the beginning of a grain grainLength = grainLen.getLastValue(); checkFadeLength(); fadeLength = fadeLen.getLastValue(); checkFadeLength(); } // This makes sure that fadeLength isn't more than half the grainLength private void checkFadeLength() { fadeLength = Math.min( fadeLength, grainLength/2.0f ); } // Make those samples! @Override protected void uGenerate( float[] channels ) { if ( insideGrain ) // inside a grain { // start with an amplitude at maxAmp float amp = maxAmp; if ( timeSinceGrainStart < fadeLength ) // inside the rise of the envelope { // linear fade in amp *= timeSinceGrainStart/fadeLength; } else if ( timeSinceGrainStart > ( grainLength - fadeLength ) ) // inside the decay of the envelope { // linear fade out amp *= ( grainLength - timeSinceGrainStart )/fadeLength; } // generate the sample for( int i = 0; i < channels.length; i++ ) { channels[i] = amp*audio.getLastValues()[i]; } // increment time timeSinceGrainStart += timeStep; if ( timeSinceGrainStart > grainLength ) // just after the grain { // stop the grain timeSinceGrainStop = 0.0f; insideGrain = false; // only set space volues at the beginning of a space spaceLength = spaceLen.getLastValue(); } } else // outside of a grain { // generate the samples for( int i = 0; i < channels.length; i++ ) { channels[i] = minAmp; } // increment time timeSinceGrainStop += timeStep; if ( timeSinceGrainStop > spaceLength ) // just inside a grain again { reset(); } } } }