package ddf.minim.ugens; import ddf.minim.AudioOutput; import ddf.minim.UGen; /** * A UGen that plays input audio through a standard ADSR (Attack, Decay, Sustain, Release) * envelope based on time from noteOn and noteOff. * * @example Synthesis/ADSRExample * * @author Anderson Mills * */ public class ADSR extends UGen { /** * The default input is "audio." * You won't need to patch to this directly, since * simply patching to the ADSR itself will achieve * the same result. * * @related ADSR */ public UGenInput audio; // amplitude before the ADSR hits private float beforeAmplitude; // amplitude after the release of the ADSR private float afterAmplitude; // the max amplitude of the envelope private float maxAmplitude; // the current amplitude private float amplitude; // the time of the attack private float attackTime; // the time of the decay private float decayTime; // the level of the sustain private float sustainLevel; // the time of the release private float releaseTime; // the current size of the step private float timeStepSize; // the time from noteOn private float timeFromOn; // the time from noteOff private float timeFromOff; // the envelope has received noteOn private boolean isTurnedOn; // the envelope has received noteOff private boolean isTurnedOff; // unpatch the note after it's finished private boolean unpatchAfterRelease; private AudioOutput output; private UGen ugenOutput; /** * Constructor for an ADSR envelope. * Maximum amplitude is set to 1.0. * Attack and decay times are set to 1 sec. * Sustain level is set to 0.0. Release time is set to 1 sec. * Amplitude before and after the envelope is set to 0. */ public ADSR() { this(1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f); } /** * Constructor for an ADSR envelope with maximum amplitude. * Attack and decay times are set to 1 sec. * Sustain level is set to 0.0. Release time is set to 1 sec. * Amplitude before and after the envelope is set to 0. * * @param maxAmp * float: the maximum amplitude for the envelope */ public ADSR(float maxAmp) { this(maxAmp, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f); } /** * Constructor for an ADSR envelope with maximum amplitude, attack Time. * Decay time is set to 1 sec. * Sustain level is set to 0.0. Release time is set to 1 sec. * Amplitude before and after the envelope is set to 0. * * @param maxAmp * float: the maximum amplitude for the envelope * @param attTime * float: the attack time, in seconds */ public ADSR( float maxAmp, float attTime ) { this(maxAmp, attTime, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f); } /** * Constructor for an ADSR envelope with maximum amplitude, attack Time, and decay time. * Sustain level is set to 0.0. Release time is set to 1 sec. * Amplitude before and after the envelope is set to 0. * * @param maxAmp * float: the maximum amplitude for the envelope * @param attTime * float: the attack time, in seconds * @param decTime * float: the decay time, in seconds * */ public ADSR( float maxAmp, float attTime, float decTime ) { this(maxAmp, attTime, decTime, 0.0f, 1.0f, 0.0f, 0.0f); } /** * Constructor for an ADSR envelope with maximum amplitude, attack Time, decay time, and sustain level. * Release time is set to 1 sec. Amplitude before and after the envelope is set to 0. * * @param maxAmp * float: the maximum amplitude for the envelope * @param attTime * float: the attack time, in seconds * @param decTime * float: the decay time, in seconds * @param susLvl * float: the percentage of the maximum amplitude to maintain after the decay completes */ public ADSR( float maxAmp, float attTime, float decTime, float susLvl ) { this(maxAmp, attTime, decTime, susLvl, 1.0f, 0.0f, 0.0f); } /** * Constructor for an ADSR envelope with maximum amplitude, attack Time, decay time, sustain level, * and release time. Amplitude before and after the envelope is set to 0. * * @param maxAmp * float: the maximum amplitude for the envelope * @param attTime * float: the attack time, in seconds * @param decTime * float: the decay time, in seconds * @param susLvl * float: the percentage of the maximum amplitude to maintain after the decay completes * @param relTime * float: the release time, in seconds */ public ADSR(float maxAmp, float attTime, float decTime, float susLvl, float relTime) { this(maxAmp, attTime, decTime, susLvl, relTime, 0.0f, 0.0f); } /** * Constructor for an ADSR envelope with maximum amplitude, attack Time, decay time, sustain level, * release time, an amplitude before the envelope. Amplitude after the envelope is set to 0. * * @param maxAmp * float: the maximum amplitude for the envelope * @param attTime * float: the attack time, in seconds * @param decTime * float: the decay time, in seconds * @param susLvl * float: the percentage of the maximum amplitude to maintain after the decay completes * @param relTime * float: the release time, in seconds * @param befAmp * float: the amplitude to apply before the envelope is activated */ public ADSR(float maxAmp, float attTime, float decTime, float susLvl, float relTime, float befAmp) { this(maxAmp, attTime, decTime, susLvl, relTime, befAmp, 0.0f); } /** * Constructor for an ADSR envelope. * * @param maxAmp * float: the maximum amplitude for the envelope * @param attTime * float: the attack time, in seconds * @param decTime * float: the decay time, in seconds * @param susLvl * float: the percentage of the maximum amplitude to maintain after the decay completes * @param relTime * float: the release time, in seconds * @param befAmp * float: the amplitude to apply before the envelope is activated * @param aftAmp * float: the amplitude to apply once the envelope has completed */ public ADSR(float maxAmp, float attTime, float decTime, float susLvl, float relTime, float befAmp, float aftAmp) { super(); audio = new UGenInput(InputType.AUDIO); maxAmplitude = maxAmp; attackTime = attTime; decayTime = decTime; sustainLevel = susLvl; releaseTime = relTime; beforeAmplitude = befAmp; afterAmplitude = aftAmp; amplitude = beforeAmplitude; isTurnedOn = false; isTurnedOff = false; timeFromOn = -1.0f; timeFromOff = -1.0f; unpatchAfterRelease = false; } /** * Permits the changing of the ADSR parameters. * * @param maxAmp * float: the maximum amplitude for the envelope * @param attTime * float: the attack time, in seconds * @param decTime * float: the decay time, in seconds * @param susLvl * float: the percentage of the maximum amplitude to maintain after the decay completes * @param relTime * float: the release time, in seconds * @param befAmp * float: the amplitude to apply before the envelope is activated * @param aftAmp * float: the amplitude to apply once the envelope has completed * * @related ADSR */ public void setParameters( float maxAmp, float attTime, float decTime, float susLvl, float relTime, float befAmp, float aftAmp) { maxAmplitude = maxAmp; attackTime = attTime; decayTime = decTime; sustainLevel = susLvl; releaseTime = relTime; beforeAmplitude = befAmp; afterAmplitude = aftAmp; } /** * Specifies that the ADSR envelope should begin. * * @example Synthesis/ADSRExample * * @related ADSR */ public void noteOn() { timeFromOn = 0f; isTurnedOn = true; // ddf: reset these so that the envelope can be retriggered timeFromOff = -1.f; isTurnedOff = false; } /** * Specifies that the ADSR envelope should start the release time. * * @example Synthesis/ADSRExample * * @related ADSR */ public void noteOff() { timeFromOff = 0f; isTurnedOff = true; } /** * Use this method to notify the ADSR that the sample rate has changed. */ @Override protected void sampleRateChanged() { timeStepSize = 1/sampleRate(); } /** * Tell the ADSR that it should unpatch itself from the output after the release time. * * @param output * AudioOutput: the output this should unpatch itself from * * @example Synthesis/ADSRExample * * @related ADSR */ public void unpatchAfterRelease( AudioOutput output ) { unpatchAfterRelease = true; this.output = output; } /** * Tell the ADSR that it should unpatch itself from this UGen after the release time. * * @param ugen * the UGen this should unpatch itself from * * @related ADSR */ public void unpatchAfterRelease( UGen ugen ) { unpatchAfterRelease = true; ugenOutput = ugen; } @Override protected void uGenerate(float[] channels) { // before the envelope, just output the beforeAmplitude*audio if (!isTurnedOn) { for(int i = 0; i < channelCount(); i++) { channels[i] = beforeAmplitude*audio.getLastValues()[i]; } } // after the envelope, just output the afterAmplitude*audio else if (timeFromOff > releaseTime) { for(int i = 0; i < channelCount(); i++) { channels[i] = afterAmplitude*audio.getLastValues()[i]; } if ( unpatchAfterRelease ) { if ( output != null ) { unpatch( output ); output = null; } if ( ugenOutput != null ) { unpatch( ugenOutput ); ugenOutput = null; } unpatchAfterRelease = false; } } // inside the envelope else { if ((isTurnedOn) && (!isTurnedOff)) { // ATTACK if (timeFromOn <= attackTime) { // use time remaining until maxAmplitude to change amplitude float timeRemain = (attackTime - timeFromOn); amplitude += (maxAmplitude - amplitude)*timeStepSize/timeRemain; } // DECAY else if ((timeFromOn > attackTime) && (timeFromOn <= (attackTime+decayTime))) { // use time remaining until sustain to change to sustain level float timeRemain = (attackTime + decayTime - timeFromOn); amplitude += (sustainLevel*maxAmplitude - amplitude)*timeStepSize/timeRemain; } // SUSTAIN else if (timeFromOn > (attackTime+decayTime)) { // hold the sustain level amplitude = sustainLevel*maxAmplitude; } timeFromOn += timeStepSize; } // RELEASE else //isTurnedOn and isTurnedOFF and timeFromOff < releaseTime { // use remaining time to get to afterAmplitude float timeRemain = (releaseTime - timeFromOff); amplitude += (afterAmplitude - amplitude)*timeStepSize/timeRemain; timeFromOff += timeStepSize; } // finally multiply the input audio to generate the output for(int i = 0; i < channelCount(); i++) { channels[i] = amplitude*audio.getLastValues()[i]; } } } }