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., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301 USA
21 #ifndef __CALF_ENVELOPE_H
22 #define __CALF_ENVELOPE_H
24 #include "primitives.h"
28 /// Rate-based ADSFR 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.
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); with fade != 0 it goes towards 0% (positive fade) or 100% (negative fade)
40 RELEASE
, ///< release - fall from sustain (or pre-sustain) level to 0
41 LOCKDECAY
, ///< locked decay
44 /// Current envelope stage
46 /// @note these are *rates*, not times
47 double attack
, decay
, sustain
, release
, fade
;
48 /// Requested release time (not the rate!) in frames, used for recalculating the rate if sustain is changed
50 /// Current envelope (output) level
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)
55 /// Sustain level used for the current note (used to calculate release rate if sustain changed during release stage
56 /// of the current note)
58 /// Value from the time before advance() was called last time
63 attack
= decay
= sustain
= release
= thisrelease
= thiss
= 0.f
;
66 /// Stop (reset) the envelope
69 old_value
= value
= 0.0;
73 /// Set the envelope parameters (updates rate member variables based on values passed)
74 /// @param a attack time
75 /// @param d decay time
76 /// @param s sustain level
77 /// @param r release time
78 /// @param er Envelope (update) rate
79 /// @param f fade time (if applicable)
80 inline void set(float a
, float d
, float s
, float r
, float er
, float f
= 0.f
)
82 attack
= 1.0 / (a
* er
);
83 decay
= (1 - s
) / (d
* er
);
85 release_time
= r
* er
;
86 release
= s
/ release_time
;
87 if (fabs(f
) > small_value
<float>())
88 fade
= 1.0 / (f
* er
);
92 // lock thiss setting (start of release for current note) and unlock thisrelease setting (current note's release rate)
96 thisrelease
= thiss
/ release_time
;
98 /// @retval true if envelope is in released state (forced decay, release or stopped)
99 inline bool released() const
101 return state
== LOCKDECAY
|| state
== RELEASE
|| state
== STOP
;
103 /// @retval true if envelope is stopped (has not been started or has run till its end)
104 inline bool stopped() const
106 return state
== STOP
;
108 /// Start the envelope
109 inline void note_on()
114 /// Release the envelope
115 inline void note_off()
117 // Do nothing if envelope is already stopped
120 // XXXKF what if envelope is already released? (doesn't happen in any current synth, but who knows?)
121 // Raise sustain value if it has been changed... I'm not sure if it's needed
122 thiss
= std::max(sustain
, value
);
123 // Calculate release rate from sustain level
124 thisrelease
= thiss
/ release_time
;
125 // we're in attack or decay, and if decay is faster than release
126 if (value
> sustain
&& decay
> thisrelease
) {
127 // use standard release time later (because we'll be switching at sustain point)
128 thisrelease
= release
;
131 // in attack/decay, but use fixed release time
132 // in case value fell below sustain, assume it didn't (for the purpose of calculating release rate only)
136 /// Calculate next envelope value
137 inline void advance()
140 // XXXKF This may use a state array instead of a switch some day (at least for phases other than attack and possibly sustain)
165 thisrelease
= release
;
177 if (value
< 0.00001f
) {
183 value
-= thisrelease
;
194 /// Return a value between old_value (previous step) and value (current step)
195 /// @param pos between 0 and 1
196 inline double interpolate(double pos
)
198 return old_value
+ (value
- old_value
) * pos
;
200 inline float get_amp_value()
202 if (state
== RELEASE
&& sustain
> 0 && value
< sustain
)
204 return value
* value
* value
/ (sustain
* sustain
);
210 /// Simple linear fade out for note tails
214 float step
, step_orig
;
217 fadeout(int steps
= 256)
219 step_orig
= (float)(1.f
/ steps
);
233 /// Fade back in with double speed (to prevent click on note restart)
241 /// Reset if fully faded out; fade back in if in the middle of fading out
244 if (value
<= 0.f
|| value
>= 1.f
)
250 void process(float *buffer
, int len
)
255 for (; value
> 0 && value
<= 1.0 && i
< len
; i
++)
260 if (value
<= 0 || value
> 1)
263 if (done
&& value
<= 0)
268 if (done
&& undoing
&& value
>= 1)
272 // prepare for the next fade-out