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
23 #include <config-api.h>
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
37 struct cbox_envstage stages
[MAX_ENV_STAGES
];
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;
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)
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
;
67 cbox_envelope_init_stage(env
);
70 static inline void cbox_envelope_reset(struct cbox_envelope
*env
)
75 cbox_envelope_init_stage(env
);
78 static inline float cbox_envelope_get_next(struct cbox_envelope
*env
, int released
)
80 if (env
->cur_stage
< 0)
82 return env
->cur_value
;
84 struct cbox_envstage
*es
= &env
->shape
->stages
[env
->cur_stage
];
85 double pos
= es
->time
> 0 ? env
->cur_time
* env
->inv_time
: 1;
91 // instead of exp, may use 2**x which can be factored
92 // into a shift and a table lookup
93 env
->cur_value
= env
->stage_start_value
* expf(pos
* env
->exp_factor
);
94 if (env
->cur_value
<= 100.1/16384.0)
98 env
->cur_value
= env
->stage_start_value
+ (es
->end_value
- env
->stage_start_value
) * pos
;
99 if (pos
>= 1 || (es
->break_on_release
&& released
))
101 env
->cur_stage
= released
? es
->next_if_released
: es
->next_if_pressed
;
102 if (!es
->keep_last_value
)
103 env
->stage_start_value
= es
->end_value
;
105 env
->stage_start_value
= env
->cur_value
;
107 cbox_envelope_init_stage(env
);
109 return env
->cur_value
;
120 static inline void cbox_envelope_init_adsr(struct cbox_envelope_shape
*env
, const struct cbox_adsr
*adsr
, int sr
)
122 env
->start_value
= 0;
123 env
->stages
[0].end_value
= 1;
124 env
->stages
[0].time
= adsr
->attack
* sr
;
125 env
->stages
[0].next_if_pressed
= 1;
126 env
->stages
[0].next_if_released
= 1;
127 env
->stages
[0].keep_last_value
= 1;
128 env
->stages
[0].break_on_release
= 0;
129 env
->stages
[0].is_exp
= 0;
131 env
->stages
[1].end_value
= adsr
->sustain
;
132 env
->stages
[1].time
= adsr
->decay
* sr
;
133 env
->stages
[1].next_if_pressed
= 2;
134 env
->stages
[1].next_if_released
= 2;
135 env
->stages
[1].keep_last_value
= 0;
136 env
->stages
[1].break_on_release
= 0;
137 env
->stages
[1].is_exp
= 0;
139 env
->stages
[2].end_value
= adsr
->sustain
;
140 env
->stages
[2].time
= 1 * sr
;
141 env
->stages
[2].next_if_pressed
= 2;
142 env
->stages
[2].next_if_released
= 3;
143 env
->stages
[2].keep_last_value
= 0;
144 env
->stages
[2].break_on_release
= 1;
145 env
->stages
[2].is_exp
= 0;
147 env
->stages
[3].end_value
= 0;
148 env
->stages
[3].time
= adsr
->release
* sr
;
149 env
->stages
[3].next_if_pressed
= -1;
150 env
->stages
[3].next_if_released
= -1;
151 env
->stages
[3].keep_last_value
= 0;
152 env
->stages
[3].break_on_release
= 0;
153 env
->stages
[3].is_exp
= 1;
155 env
->stages
[15].end_value
= 0;
156 env
->stages
[15].time
= 0.01 * sr
;
157 env
->stages
[15].next_if_pressed
= -1;
158 env
->stages
[15].next_if_released
= -1;
159 env
->stages
[15].keep_last_value
= 0;
160 env
->stages
[15].break_on_release
= 0;
161 env
->stages
[15].is_exp
= 0;
175 static inline void cbox_dahdsr_init(struct cbox_dahdsr
*dahdsr
, float top_value
)
179 dahdsr
->attack
= 0.f
;
182 dahdsr
->sustain
= top_value
;
183 dahdsr
->release
= 0.05f
;
186 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
)
188 env
->start_value
= 0;
189 env
->stages
[0].end_value
= 0;
190 env
->stages
[0].time
= dahdsr
->delay
* sr
;
191 env
->stages
[0].next_if_pressed
= 1;
192 env
->stages
[0].next_if_released
= 5;
193 env
->stages
[0].keep_last_value
= 1;
194 env
->stages
[0].break_on_release
= 0;
195 env
->stages
[0].is_exp
= 0;
197 env
->stages
[1].end_value
= top_value
;
198 env
->stages
[1].time
= dahdsr
->attack
* sr
;
199 env
->stages
[1].next_if_pressed
= 2;
200 env
->stages
[1].next_if_released
= 5;
201 env
->stages
[1].keep_last_value
= 1;
202 env
->stages
[1].break_on_release
= 1;
203 env
->stages
[1].is_exp
= 0;
205 env
->stages
[2].end_value
= top_value
;
206 env
->stages
[2].time
= dahdsr
->hold
* sr
;
207 env
->stages
[2].next_if_pressed
= 3;
208 env
->stages
[2].next_if_released
= 5;
209 env
->stages
[2].keep_last_value
= 1;
210 env
->stages
[2].break_on_release
= 1;
211 env
->stages
[2].is_exp
= 0;
213 env
->stages
[3].end_value
= dahdsr
->sustain
;
214 env
->stages
[3].time
= dahdsr
->decay
* sr
;
215 env
->stages
[3].next_if_pressed
= 4;
216 env
->stages
[3].next_if_released
= 5;
217 env
->stages
[3].keep_last_value
= 1;
218 env
->stages
[3].break_on_release
= 1;
219 env
->stages
[3].is_exp
= 0;
221 env
->stages
[4].end_value
= dahdsr
->sustain
;
222 env
->stages
[4].time
= 1 * sr
;
223 env
->stages
[4].next_if_pressed
= 4;
224 env
->stages
[4].next_if_released
= 5;
225 env
->stages
[4].keep_last_value
= 0;
226 env
->stages
[4].break_on_release
= 1;
227 env
->stages
[4].is_exp
= 0;
229 env
->stages
[5].end_value
= 0;
230 env
->stages
[5].time
= dahdsr
->release
* sr
;
231 env
->stages
[5].next_if_pressed
= -1;
232 env
->stages
[5].next_if_released
= -1;
233 env
->stages
[5].keep_last_value
= 0;
234 env
->stages
[5].break_on_release
= 0;
235 env
->stages
[5].is_exp
= is_release_exp
;
237 env
->stages
[15].end_value
= 0;
238 env
->stages
[15].time
= 0.01 * sr
;
239 env
->stages
[15].next_if_pressed
= -1;
240 env
->stages
[15].next_if_released
= -1;
241 env
->stages
[15].keep_last_value
= 0;
242 env
->stages
[15].break_on_release
= 0;
243 env
->stages
[15].is_exp
= 0;
246 static inline void cbox_envelope_modify_dahdsr(struct cbox_envelope_shape
*env
, int part
, float value
, int sr
)
255 env
->stages
[part
].time
+= value
* sr
;
256 if (env
->stages
[part
].time
< 0)
257 env
->stages
[part
].time
= 0;
260 env
->stages
[3].end_value
= value
;
261 env
->stages
[4].end_value
= value
;