+ Vintage Delay: attempt at fixing the delay initialization problem after startup...
[calf.git] / src / calf / envelope.h
bloba5703476976b5edf4d1fb944ec54e134a1bd90b1
1 /* Calf DSP Library
2 * ADSR envelope class (and other envelopes in future)
4 * Copyright (C) 2007-2008 Krzysztof Foltman
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General
17 * Public License along with this program; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
19 * Boston, MA 02111-1307, USA.
21 #ifndef __CALF_ENVELOPE_H
22 #define __CALF_ENVELOPE_H
24 #include "primitives.h"
26 namespace dsp {
28 /// Rate-based ADSR envelope class. Note that if release rate is slower than decay
29 /// rate, this envelope won't use release rate until output level falls below sustain level
30 /// it's different to what certain hardware synth companies did, but it prevents the very
31 /// un-musical (IMHO) behaviour known from (for example) SoundFont 2.
32 class adsr
34 public:
35 enum env_state {
36 STOP, ///< envelope is stopped
37 ATTACK, ///< attack - rise from 0 to 1
38 DECAY, ///< decay - fall from 1 to sustain level
39 SUSTAIN, ///< sustain - remain at sustain level (unless sustain is 0 - then it gets stopped)
40 RELEASE, ///< release - fall from sustain (or pre-sustain) level to 0
41 LOCKDECAY ///< locked decay
44 /// Current envelope stage
45 env_state state;
46 /// @note these are *rates*, not times
47 double attack, decay, sustain, release;
48 /// Requested release time (not the rate!) in frames, used for recalculating the rate if sustain is changed
49 double release_time;
50 /// Current envelope (output) level
51 double value;
52 /// Release rate used for the current note (calculated from this note's sustain level, and not the current sustain level,
53 /// which may have changed after note has been released)
54 double thisrelease;
55 /// Sustain level used for the current note (used to calculate release rate if sustain changed during release stage
56 /// of the current note)
57 double thiss;
59 adsr()
61 attack = decay = sustain = release = thisrelease = thiss = 0.f;
62 reset();
64 /// Stop (reset) the envelope
65 inline void reset()
67 value = 0.f;
68 thiss = 0.f;
69 state = STOP;
71 /// Set the envelope parameters (updates rate member variables based on values passed)
72 /// @param a attack time
73 /// @param d decay time
74 /// @param s sustain level
75 /// @param r release time
76 /// @param er Envelope (update) rate
77 inline void set(float a, float d, float s, float r, float er)
79 attack = 1.0 / (a * er);
80 decay = (1 - s) / (d * er);
81 sustain = s;
82 release_time = r * er;
83 release = s / release_time;
84 // in release:
85 // lock thiss setting (start of release for current note) and unlock thisrelease setting (current note's release rate)
86 if (state != RELEASE)
87 thiss = s;
88 else
89 thisrelease = thiss / release_time;
91 /// @retval true if envelope is in released state (forced decay, release or stopped)
92 inline bool released() const
94 return state == LOCKDECAY || state == RELEASE || state == STOP;
96 /// @retval true if envelope is stopped (has not been started or has run till its end)
97 inline bool stopped() const
99 return state == STOP;
101 /// Start the envelope
102 inline void note_on()
104 state = ATTACK;
105 thiss = sustain;
107 /// Release the envelope
108 inline void note_off()
110 // Do nothing if envelope is already stopped
111 if (state == STOP)
112 return;
113 // XXXKF what if envelope is already released? (doesn't happen in any current synth, but who knows?)
114 // Raise sustain value if it has been changed... I'm not sure if it's needed
115 thiss = std::max(sustain, value);
116 // Calculate release rate from sustain level
117 thisrelease = thiss / release_time;
118 // we're in attack or decay, and if decay is faster than release
119 if (value > sustain && decay > thisrelease) {
120 // use standard release time later (because we'll be switching at sustain point)
121 thisrelease = release;
122 state = LOCKDECAY;
123 } else {
124 // in attack/decay, but use fixed release time
125 // in case value fell below sustain, assume it didn't (for the purpose of calculating release rate only)
126 state = RELEASE;
129 /// Calculate next envelope value
130 inline void advance()
132 // XXXKF This may use a state array instead of a switch some day (at least for phases other than attack and possibly sustain)
133 switch(state)
135 case ATTACK:
136 value += attack;
137 if (value >= 1.0) {
138 value = 1.0;
139 state = DECAY;
141 break;
142 case DECAY:
143 value -= decay;
144 if (value < sustain)
146 value = sustain;
147 state = SUSTAIN;
149 break;
150 case LOCKDECAY:
151 value -= decay;
152 if (value < sustain)
154 if (value < 0.f)
155 value = 0.f;
156 state = RELEASE;
157 thisrelease = release;
159 break;
160 case SUSTAIN:
161 value = sustain;
162 if (value < 0.00001f) {
163 value = 0;
164 state = STOP;
166 break;
167 case RELEASE:
168 value -= thisrelease;
169 if (value <= 0.f) {
170 value = 0.f;
171 state = STOP;
173 break;
174 case STOP:
175 value = 0.f;
176 break;
183 #endif