1 module stk.adsr; 2 3 import stk.stk; 4 import stk.generator; 5 6 /***************************************************/ 7 /*! \class ADSR 8 \brief STK ADSR envelope class. 9 10 This class implements a traditional ADSR (Attack, Decay, Sustain, 11 Release) envelope. It responds to simple keyOn and keyOff 12 messages, keeping track of its state. The \e state = ADSR::IDLE 13 before being triggered and after the envelope value reaches 0.0 in 14 the ADSR::RELEASE state. All rate, target and level settings must 15 be non-negative. All time settings are in seconds and must be 16 positive. 17 18 by Perry R. Cook and Gary P. Scavone, 1995--2016. 19 */ 20 /***************************************************/ 21 22 class ADSR : Generator 23 { 24 public: 25 26 //! ADSR envelope states. 27 enum : int { 28 ATTACK, /*!< Attack */ 29 DECAY, /*!< Decay */ 30 SUSTAIN, /*!< Sustain */ 31 RELEASE, /*!< Release */ 32 IDLE /*!< Before attack / after release */ 33 } 34 35 //! Default constructor. 36 this () { 37 target_ = 0.0; 38 value_ = 0.0; 39 attackRate_ = 0.001; 40 decayRate_ = 0.001; 41 releaseRate_ = 0.005; 42 releaseTime_ = -1.0; 43 sustainLevel_ = 0.5; 44 state_ = IDLE; 45 Stk.addSampleRateAlert(this); 46 } 47 48 //! Class destructor. 49 ~this() { 50 Stk.removeSampleRateAlert(this); 51 } 52 53 //! Set target = 1, state = \e ADSR::ATTACK. 54 void keyOn() { 55 if ( target_ <= 0.0 ) 56 target_ = 1.0; 57 state_ = ATTACK; 58 } 59 60 //! Set target = 0, state = \e ADSR::RELEASE. 61 void keyOff() { 62 target_ = 0.0; 63 state_ = RELEASE; 64 65 // FIXED October 2010 - Nick Donaldson 66 // Need to make release rate relative to current value!! 67 // Only update if we have set a TIME rather than a RATE, 68 // in which case releaseTime_ will be -1 69 if ( releaseTime_ > 0.0 ) 70 releaseRate_ = value_ / ( releaseTime_ * Stk.sampleRate() ); 71 } 72 73 //! Set the attack rate (gain / sample). 74 void setAttackRate( StkFloat rate ) { 75 assert(rate >= 0); 76 attackRate_ = rate; 77 } 78 79 //! Set the target value for the attack (default = 1.0). 80 void setAttackTarget( StkFloat target ) { 81 assert(target >= 0); 82 target_ = target; 83 } 84 85 //! Set the decay rate (gain / sample). 86 void setDecayRate( StkFloat rate ) { 87 decayRate_ = rate; 88 } 89 90 //! Set the sustain level. 91 void setSustainLevel( StkFloat level ) { 92 sustainLevel_ = level; 93 } 94 95 //! Set the release rate (gain / sample). 96 void setReleaseRate( StkFloat rate ) { 97 releaseRate_ = rate; 98 99 // Set to negative value so we don't update the release rate on keyOff() 100 releaseTime_ = -1.0; 101 } 102 103 //! Set the attack rate based on a time duration (seconds). 104 void setAttackTime( StkFloat time ) { 105 attackRate_ = 1.0 / ( time * Stk.sampleRate() ); 106 } 107 108 //! Set the decay rate based on a time duration (seconds). 109 void setDecayTime( StkFloat time ) { 110 decayRate_ = (1.0 - sustainLevel_) / ( time * Stk.sampleRate() ); 111 } 112 113 //! Set the release rate based on a time duration (seconds). 114 void setReleaseTime( StkFloat time ) { 115 releaseRate_ = sustainLevel_ / ( time * Stk.sampleRate() ); 116 releaseTime_ = time; 117 } 118 119 //! Set sustain level and attack, decay, and release time durations (seconds). 120 void setAllTimes( StkFloat aTime, StkFloat dTime, StkFloat sLevel, StkFloat rTime ) { 121 this.setAttackTime( aTime ); 122 this.setSustainLevel( sLevel ); 123 this.setDecayTime( dTime ); 124 this.setReleaseTime( rTime ); 125 } 126 127 //! Set a sustain target value and attack or decay from current value to target. 128 void setTarget( StkFloat target ) { 129 target_ = target; 130 this.setSustainLevel( target_ ); 131 if ( value_ < target_ ) state_ = ATTACK; 132 if ( value_ > target_ ) state_ = DECAY; 133 } 134 135 //! Return the current envelope \e state (ATTACK, DECAY, SUSTAIN, RELEASE, IDLE). 136 int getState() const { 137 return state_; 138 } 139 140 //! Set to state = ADSR::SUSTAIN with current and target values of \e value. 141 void setValue( StkFloat value ) { 142 state_ = SUSTAIN; 143 target_ = value; 144 value_ = value; 145 this.setSustainLevel( value ); 146 lastFrame_[0] = value; 147 } 148 149 //! Return the last computed output value. 150 StkFloat lastOut() const { return lastFrame_[0]; }; 151 152 //! Compute and return one output sample. 153 StkFloat tick() { 154 switch ( state_ ) { 155 156 case ATTACK: 157 value_ += attackRate_; 158 if ( value_ >= target_ ) { 159 value_ = target_; 160 target_ = sustainLevel_; 161 state_ = DECAY; 162 } 163 lastFrame_[0] = value_; 164 break; 165 166 case DECAY: 167 if ( value_ > sustainLevel_ ) { 168 value_ -= decayRate_; 169 if ( value_ <= sustainLevel_ ) { 170 value_ = sustainLevel_; 171 state_ = SUSTAIN; 172 } 173 } 174 else { 175 value_ += decayRate_; // attack target < sustain level 176 if ( value_ >= sustainLevel_ ) { 177 value_ = sustainLevel_; 178 state_ = SUSTAIN; 179 } 180 } 181 lastFrame_[0] = value_; 182 break; 183 184 case RELEASE: 185 value_ -= releaseRate_; 186 if ( value_ <= 0.0 ) { 187 value_ = 0.0; 188 state_ = IDLE; 189 } 190 lastFrame_[0] = value_; 191 break; 192 default: 193 break; 194 195 } 196 197 return value_; 198 } 199 200 //! Fill a channel of the StkFrames object with computed outputs. 201 /*! 202 The \c channel argument must be less than the number of 203 channels in the StkFrames argument (the first channel is specified 204 by 0). However, range checking is only performed if _STK_DEBUG_ 205 is defined during compilation, in which case an out-of-range value 206 will trigger an StkError exception. 207 */ 208 ref StkFrames tick( ref StkFrames frames, uint channel = 0 ) { 209 StkFloat *samples = &frames[channel]; 210 uint hop = frames.channels(); 211 for ( uint i=0; i < frames.frames(); i++, samples += hop ) 212 *samples = tick(); 213 return frames; 214 } 215 216 protected: 217 218 override void sampleRateChanged( StkFloat newRate, StkFloat oldRate ) { 219 if ( !ignoreSampleRateChange_ ) { 220 attackRate_ = oldRate * attackRate_ / newRate; 221 decayRate_ = oldRate * decayRate_ / newRate; 222 releaseRate_ = oldRate * releaseRate_ / newRate; 223 } 224 } 225 226 int state_; 227 StkFloat value_; 228 StkFloat target_; 229 StkFloat attackRate_; 230 StkFloat decayRate_; 231 StkFloat releaseRate_; 232 StkFloat releaseTime_; 233 StkFloat sustainLevel_; 234 }