Merge pull request #1 from atsampson/master
[calfbox.git] / envelope.h
blob1747071fa113ab847cfc7c02ec09af2c14c12727
1 /*
2 Calf Box, an open source musical instrument.
3 Copyright (C) 2010-2011 Krzysztof Foltman
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #ifndef CBOX_ENVELOPE_H
20 #define CBOX_ENVELOPE_H
22 #include <glib.h>
23 #include <config-api.h>
25 struct cbox_envstage
27 double end_value;
28 int time;
29 int next_if_pressed, next_if_released, keep_last_value, break_on_release, is_exp;
32 #define MAX_ENV_STAGES 16
34 struct cbox_envelope_shape
36 double start_value;
37 struct cbox_envstage stages[MAX_ENV_STAGES];
40 struct cbox_envelope
42 struct cbox_envelope_shape *shape;
43 double stage_start_value, cur_value, exp_factor, inv_time;
44 int cur_stage, cur_time;
47 static inline void cbox_envelope_init_stage(struct cbox_envelope *env)
49 struct cbox_envstage *es = &env->shape->stages[env->cur_stage];
50 env->inv_time = es->time ? 1.0 / es->time : 1;
51 if (es->is_exp)
53 if (env->stage_start_value < 100.0/16384.0)
54 env->stage_start_value = 100.0/16384.0;
55 double ev = es->end_value;
56 if (ev < 100.0/16384.0)
57 ev = 100.0/16384.0;
58 env->exp_factor = log(ev/env->stage_start_value);
62 static inline void cbox_envelope_go_to(struct cbox_envelope *env, int stage)
64 env->stage_start_value = env->cur_value;
65 env->cur_stage = stage;
66 env->cur_time = 0;
67 cbox_envelope_init_stage(env);
70 static inline void cbox_envelope_reset(struct cbox_envelope *env)
72 env->cur_value = 0;
73 env->cur_stage = 0;
74 env->cur_time = 0;
75 cbox_envelope_init_stage(env);
78 static inline void cbox_envelope_update_shape(struct cbox_envelope *env, struct cbox_envelope_shape *shape)
80 struct cbox_envelope_shape *old_shape = env->shape;
81 env->shape = shape;
82 if (env->cur_stage < 0)
83 return;
84 struct cbox_envstage *ns = &env->shape->stages[env->cur_stage];
85 struct cbox_envstage *os = &old_shape->stages[env->cur_stage];
86 if (os->time > 0)
87 env->cur_time = env->cur_time * ns->time / os->time;
88 if (env->cur_time > ns->time)
89 env->cur_time = ns->time;
92 static inline float cbox_envelope_get_next(struct cbox_envelope *env, int released)
94 if (env->cur_stage < 0)
96 return env->cur_value;
98 struct cbox_envstage *es = &env->shape->stages[env->cur_stage];
99 double pos = es->time > 0 ? env->cur_time * env->inv_time : 1;
100 env->cur_time++;
101 if (pos > 1)
102 pos = 1;
103 if (es->is_exp)
105 // instead of exp, may use 2**x which can be factored
106 // into a shift and a table lookup
107 env->cur_value = env->stage_start_value * expf(pos * env->exp_factor);
108 if (env->cur_value <= 100.1/16384.0)
109 env->cur_value = 0;
111 else
112 env->cur_value = env->stage_start_value + (es->end_value - env->stage_start_value) * pos;
113 if (pos >= 1 || (es->break_on_release && released))
115 env->cur_stage = released ? es->next_if_released : es->next_if_pressed;
116 if (!es->keep_last_value)
117 env->stage_start_value = es->end_value;
118 else
119 env->stage_start_value = env->cur_value;
120 env->cur_time = 0;
121 cbox_envelope_init_stage(env);
123 return env->cur_value;
126 struct cbox_adsr
128 float attack;
129 float decay;
130 float sustain;
131 float release;
134 static inline void cbox_envelope_init_adsr(struct cbox_envelope_shape *env, const struct cbox_adsr *adsr, int sr)
136 env->start_value = 0;
137 env->stages[0].end_value = 1;
138 env->stages[0].time = adsr->attack * sr;
139 env->stages[0].next_if_pressed = 1;
140 env->stages[0].next_if_released = 1;
141 env->stages[0].keep_last_value = 1;
142 env->stages[0].break_on_release = 0;
143 env->stages[0].is_exp = 0;
145 env->stages[1].end_value = adsr->sustain;
146 env->stages[1].time = adsr->decay * sr;
147 env->stages[1].next_if_pressed = 2;
148 env->stages[1].next_if_released = 2;
149 env->stages[1].keep_last_value = 0;
150 env->stages[1].break_on_release = 0;
151 env->stages[1].is_exp = 0;
153 env->stages[2].end_value = adsr->sustain;
154 env->stages[2].time = 1 * sr;
155 env->stages[2].next_if_pressed = 2;
156 env->stages[2].next_if_released = 3;
157 env->stages[2].keep_last_value = 0;
158 env->stages[2].break_on_release = 1;
159 env->stages[2].is_exp = 0;
161 env->stages[3].end_value = 0;
162 env->stages[3].time = adsr->release * sr;
163 env->stages[3].next_if_pressed = -1;
164 env->stages[3].next_if_released = -1;
165 env->stages[3].keep_last_value = 0;
166 env->stages[3].break_on_release = 0;
167 env->stages[3].is_exp = 1;
169 env->stages[15].end_value = 0;
170 env->stages[15].time = 0.01 * sr;
171 env->stages[15].next_if_pressed = -1;
172 env->stages[15].next_if_released = -1;
173 env->stages[15].keep_last_value = 0;
174 env->stages[15].break_on_release = 0;
175 env->stages[15].is_exp = 0;
178 struct cbox_dahdsr
180 float start;
181 float delay;
182 float attack;
183 float hold;
184 float decay;
185 float sustain;
186 float release;
189 static inline void cbox_dahdsr_init(struct cbox_dahdsr *dahdsr, float top_value)
191 dahdsr->start = 0.f;
192 dahdsr->delay = 0.f;
193 dahdsr->attack = 0.f;
194 dahdsr->hold = 0.f;
195 dahdsr->decay = 0.f;
196 dahdsr->sustain = top_value;
197 dahdsr->release = 0.05f;
200 static inline void cbox_envelope_init_dahdsr(struct cbox_envelope_shape *env, const struct cbox_dahdsr *dahdsr, int sr, float top_value, gboolean is_release_exp)
202 env->start_value = 0;
203 env->stages[0].end_value = 0;
204 env->stages[0].time = dahdsr->delay * sr;
205 env->stages[0].next_if_pressed = 1;
206 env->stages[0].next_if_released = 5;
207 env->stages[0].keep_last_value = 1;
208 env->stages[0].break_on_release = 0;
209 env->stages[0].is_exp = 0;
211 env->stages[1].end_value = top_value;
212 env->stages[1].time = dahdsr->attack * sr;
213 env->stages[1].next_if_pressed = 2;
214 env->stages[1].next_if_released = 5;
215 env->stages[1].keep_last_value = 1;
216 env->stages[1].break_on_release = 1;
217 env->stages[1].is_exp = 0;
219 env->stages[2].end_value = top_value;
220 env->stages[2].time = dahdsr->hold * sr;
221 env->stages[2].next_if_pressed = 3;
222 env->stages[2].next_if_released = 5;
223 env->stages[2].keep_last_value = 1;
224 env->stages[2].break_on_release = 1;
225 env->stages[2].is_exp = 0;
227 env->stages[3].end_value = dahdsr->sustain;
228 env->stages[3].time = dahdsr->decay * sr;
229 env->stages[3].next_if_pressed = 4;
230 env->stages[3].next_if_released = 5;
231 env->stages[3].keep_last_value = 1;
232 env->stages[3].break_on_release = 1;
233 env->stages[3].is_exp = 0;
235 env->stages[4].end_value = dahdsr->sustain;
236 env->stages[4].time = 1 * sr;
237 env->stages[4].next_if_pressed = 4;
238 env->stages[4].next_if_released = 5;
239 env->stages[4].keep_last_value = 0;
240 env->stages[4].break_on_release = 1;
241 env->stages[4].is_exp = 0;
243 env->stages[5].end_value = 0;
244 env->stages[5].time = dahdsr->release * sr;
245 env->stages[5].next_if_pressed = -1;
246 env->stages[5].next_if_released = -1;
247 env->stages[5].keep_last_value = 0;
248 env->stages[5].break_on_release = 0;
249 env->stages[5].is_exp = is_release_exp;
251 env->stages[15].end_value = 0;
252 env->stages[15].time = 0.01 * sr;
253 env->stages[15].next_if_pressed = -1;
254 env->stages[15].next_if_released = -1;
255 env->stages[15].keep_last_value = 0;
256 env->stages[15].break_on_release = 0;
257 env->stages[15].is_exp = 0;
260 static inline void cbox_envelope_modify_dahdsr(struct cbox_envelope_shape *env, int part, float value, int sr)
262 switch(part)
264 case 0: // delay
265 case 1: // attack
266 case 2: // hold
267 case 3: // decay
268 case 5: // release
269 env->stages[part].time += value * sr;
270 if (env->stages[part].time < 0)
271 env->stages[part].time = 0;
272 break;
273 case 4: // sustain
274 env->stages[3].end_value = value;
275 env->stages[4].end_value = value;
276 break;
280 #endif