1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * This code was translated from the JSyn Java code. 17 * JSyn is Copyright 2009 Phil Burk, Mobileer Inc 18 * JSyn is licensed under the Apache License, Version 2.0 19 */ 20 21 #ifndef SYNTHMARK_ENVELOPE_ADSR_H 22 #define SYNTHMARK_ENVELOPE_ADSR_H 23 24 #include <cstdint> 25 #include <math.h> 26 #include "SynthTools.h" 27 #include "UnitGenerator.h" 28 29 namespace marksynth { 30 31 /** 32 * Generate a contour that can be used to control amplitude or 33 * other parameters. 34 */ 35 36 class EnvelopeADSR : public UnitGenerator 37 { 38 public: EnvelopeADSR()39 EnvelopeADSR() 40 : mAttack(0.05) 41 , mDecay(0.6) 42 , mSustainLevel(0.4) 43 , mRelease(2.5) 44 {} 45 46 virtual ~EnvelopeADSR() = default; 47 48 #define MIN_DURATION (1.0 / 100000.0) 49 50 enum State { 51 IDLE, ATTACKING, DECAYING, SUSTAINING, RELEASING 52 }; 53 setGate(bool gate)54 void setGate(bool gate) { 55 triggered = gate; 56 } 57 isIdle()58 bool isIdle() { 59 return mState == State::IDLE; 60 } 61 62 /** 63 * Time in seconds for the falling stage to go from 0 dB to -90 dB. The decay stage will stop at 64 * the sustain level. But we calculate the time to fall to -90 dB so that the decay 65 * <em>rate</em> will be unaffected by the sustain level. 66 */ setDecayTime(synth_float_t time)67 void setDecayTime(synth_float_t time) { 68 mDecay = time; 69 } 70 getDecayTime()71 synth_float_t getDecayTime() { 72 return mDecay; 73 } 74 75 /** 76 * Time in seconds for the rising stage of the envelope to go from 0.0 to 1.0. The attack is a 77 * linear ramp. 78 */ setAttackTime(synth_float_t time)79 void setAttackTime(synth_float_t time) { 80 mAttack = time; 81 } 82 getAttackTime()83 synth_float_t getAttackTime() { 84 return mAttack; 85 } 86 generate(int32_t numSamples)87 void generate(int32_t numSamples) { 88 for (int i = 0; i < numSamples; i++) { 89 switch (mState) { 90 case IDLE: 91 for (; i < numSamples; i++) { 92 output[i] = mLevel; 93 if (triggered) { 94 startAttack(); 95 break; 96 } 97 } 98 break; 99 100 case ATTACKING: 101 for (; i < numSamples; i++) { 102 // Increment first so we can render fast attacks. 103 mLevel += increment; 104 if (mLevel >= 1.0) { 105 mLevel = 1.0; 106 output[i] = mLevel; 107 startDecay(); 108 break; 109 } else { 110 output[i] = mLevel; 111 if (!triggered) { 112 startRelease(); 113 break; 114 } 115 } 116 } 117 break; 118 119 case DECAYING: 120 for (; i < numSamples; i++) { 121 output[i] = mLevel; 122 mLevel *= mScaler; // exponential decay 123 if (mLevel < kAmplitudeDb96) { 124 startIdle(); 125 break; 126 } else if (!triggered) { 127 startRelease(); 128 break; 129 } else if (mLevel < mSustainLevel) { 130 mLevel = mSustainLevel; 131 startSustain(); 132 break; 133 } 134 } 135 break; 136 137 case SUSTAINING: 138 for (; i < numSamples; i++) { 139 mLevel = mSustainLevel; 140 output[i] = mLevel; 141 if (!triggered) { 142 startRelease(); 143 break; 144 } 145 } 146 break; 147 148 case RELEASING: 149 for (; i < numSamples; i++) { 150 output[i] = mLevel; 151 mLevel *= mScaler; // exponential decay 152 if (triggered) { 153 startAttack(); 154 break; 155 } else if (mLevel < kAmplitudeDb96) { 156 startIdle(); 157 break; 158 } 159 } 160 break; 161 } 162 } 163 } 164 165 private: 166 startIdle()167 void startIdle() { 168 mState = State::IDLE; 169 mLevel = 0.0; 170 } 171 startAttack()172 void startAttack() { 173 if (mAttack < MIN_DURATION) { 174 mLevel = 1.0; 175 startDecay(); 176 } else { 177 increment = mSamplePeriod / mAttack; 178 mState = State::ATTACKING; 179 } 180 } 181 startDecay()182 void startDecay() { 183 double duration = mDecay; 184 if (duration < MIN_DURATION) { 185 startSustain(); 186 } else { 187 mScaler = SynthTools::convertTimeToExponentialScaler(duration, mSampleRate); 188 mState = State::DECAYING; 189 } 190 } 191 startSustain()192 void startSustain() { 193 mState = State::SUSTAINING; 194 } 195 startRelease()196 void startRelease() { 197 double duration = mRelease; 198 if (duration < MIN_DURATION) { 199 duration = MIN_DURATION; 200 } 201 mScaler = SynthTools::convertTimeToExponentialScaler(duration, mSampleRate); 202 mState = State::RELEASING; 203 } 204 205 synth_float_t mAttack; 206 synth_float_t mDecay; 207 /** 208 * Level for the sustain stage. The envelope will hold here until the input goes to zero or 209 * less. This should be set between 0.0 and 1.0. 210 */ 211 synth_float_t mSustainLevel; 212 /** 213 * Time in seconds to go from 0 dB to -90 dB. This stage is triggered when the input goes to 214 * zero or less. The release stage will start from the sustain level. But we calculate the time 215 * to fall from full amplitude so that the release <em>rate</em> will be unaffected by the 216 * sustain level. 217 */ 218 synth_float_t mRelease; 219 220 State mState = State::IDLE; 221 synth_float_t mScaler = 1.0; 222 synth_float_t mLevel = 0.0; 223 synth_float_t increment = 0; 224 bool triggered = false; 225 226 }; 227 228 }; 229 #endif // SYNTHMARK_ENVELOPE_ADSR_H 230