| Mozzi version v1.1.0 sound synthesis library for Arduino |

MultiLine.h
1 /*
2 * MultiLine.h
3 *
4 * Copyright 2012-2015 Tim Barrass.
5 *
6 * This file is part of Mozzi.
7 *
8 * Mozzi is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
9 *
10 */
11
12 #ifndef MultiLine_H_
13 #define MultiLine_H_
14
15 #if ARDUINO >= 100
16 #include "Arduino.h"
17 #else
18 #include "WProgram.h"
19 #endif
20 #include "Line.h"
21 #include "mozzi_fixmath.h"
22
23
24 /** A simple MultiLine envelope generator. This implementation has separate update() and next()
25 methods, where next() interpolates values between each update().
26 The "normal" way to use this would be with update() in updateControl(), where it calculates a new internal state each control step,
27 and then next() is in updateAudio(), called much more often, where it interpolates between the control values.
28 This also allows the MultiLine updates to be made even more sparsely if desired, eg. every 3rd control update.
29 @tparam CONTROL_UPDATE_RATE The frequency of control updates.
30 Ordinarily this will be CONTROL_RATE, but an alternative (amongst others) is
31 to set this as well as the LERP_RATE parameter to AUDIO_RATE, and call both update() and next() in updateAudio().
32 Such a use would allow accurate envelopes with finer resolution of the control points than CONTROL_RATE.
33 @tparam LERP_RATE Sets how often next() will be called, to interpolate between updates set by CONTROL_UPDATE_RATE.
34 This will produce the smoothest results if it's set to AUDIO_RATE, but if you need to save processor time and your
35 envelope changes slowly or controls something like a filter where there may not be problems with glitchy or clicking transitions,
36 LERP_RATE could be set to CONTROL_RATE (for instance). Then update() and next() could both be called in updateControl(),
37 greatly reducing the amount of processing required compared to calling next() in updateAudio().
38 @todo Test whether using the template parameters makes any difference to speed,
39 and rationalise which units which do and don't need them.
40 Template objects are messy when you try to use pointers to them,
41 you have to include the whole template shebang in the pointer handling.
42 */
43 template <unsigned int CONTROL_UPDATE_RATE, unsigned int LERP_RATE>
44 class MultiLine
45 {
46 private:
47
48 const unsigned int LERPS_PER_CONTROL;
49
50 unsigned int update_step_counter;
51 unsigned int num_update_steps;
52
53 enum {LINE1,LINE2,LINE3,LINE4,IDLE};
54
55
56 struct phase{
57 byte phase_type;
58 unsigned int update_steps;
59 long lerp_steps; // signed, to match params to transition (line) type Q15n16, below
60 Q15n16 level;
61 }target1,target2,target3,target4,idle;
62
63 phase * current_phase;
64 Line <Q15n16> transition;
65
66 inline
67 unsigned int convertMsecToControlUpdateSteps(unsigned int msec){
68 return (uint16_t) (((uint32_t)msec*CONTROL_UPDATE_RATE)>>10); // approximate /1000 with shift
69 }
70
71
72 inline
73 void setPhase(phase * next_phase) {
74 update_step_counter = 0;
75 num_update_steps = next_phase->update_steps;
76 transition.set(next_phase->level, next_phase->lerp_steps);
77 current_phase = next_phase;
78 }
79
80
81
82 inline
83 void checkForAndSetNextPhase(phase * next_phase) {
84 if (++update_step_counter >= num_update_steps){
85 setPhase(next_phase);
86 }
87 }
88
89
90
91 inline
92 void setTime(phase * p, unsigned int msec)
93 {
94 p->update_steps = convertMsecToControlUpdateSteps(msec);
95 p->lerp_steps = (long) p->update_steps * LERPS_PER_CONTROL;
96 }
97
98
99 inline
100 void setUpdateSteps(phase * p, unsigned int steps)
101 {
102 p->update_steps = steps;
103 p->lerp_steps = (long) steps * LERPS_PER_CONTROL;
104 }
105
106
107
108 public:
109
110 /** Constructor.
111 */
112 MultiLine():LERPS_PER_CONTROL(LERP_RATE/CONTROL_UPDATE_RATE)
113 {
114 target1.phase_type = LINE1;
115 target2.phase_type = LINE2;
116 target3.phase_type = LINE3;
117 target4.phase_type = LINE4;
118 idle.phase_type = IDLE;
119 target4.level = 0;
120 current_phase = &idle;
121 }
122
123
124
125 /** Updates the internal controls of the MultiLine.
126 Call this in updateControl().
127 */
128 void update(){ // control rate
129
130 switch(current_phase->phase_type) {
131
132 case LINE1:
133 checkForAndSetNextPhase(&target2);
134 break;
135
136 case LINE2:
137 checkForAndSetNextPhase(&target3);
138 break;
139
140 case LINE3:
141 checkForAndSetNextPhase(&target4);
142 break;
143
144 case LINE4:
145 checkForAndSetNextPhase(&idle);
146 //checkForAndSetIdle();
147 break;
148
149 case IDLE:
150 break;
151 }
152 }
153
154
155
156 /** Advances one step along the MultiLine and returns the level.
157 Call this in updateAudio().
158 @return the next value, as a Q15n16 fixed-point number.
159 */
160 inline
161 Q15n16 next()
162 {
163 return transition.next();
164 }
165
166
167
168 /** Start the target1 phase of the MultiLine. THis will restart the MultiLine no matter what phase it is up to.
169 */
170 inline
171 void start(){
172 setPhase(&target1);
173 }
174
175
176
177 /** Start the target4 phase of the MultiLine.
178 @todo fix target4 for rate rather than steps (time), so it "releases" at the same rate whatever the current level.
179 */
180 inline
181 void stop(){
182 setPhase(&target4);
183 }
184
185
186
187 /** Set the target1 level of the MultiLine.
188 @param value the target1 level.
189 */
190 inline
191 void setTarget1Level(Q15n16 value)
192 {
193 target1.level=value;
194 }
195
196
197
198 /** Set the target2 level of the MultiLine.
199 @param value the target2 level.
200 */
201 inline
202 void setTarget2Level(Q15n16 value)
203 {
204 target2.level=value;
205 }
206
207
208 /** Set the target3 level of the MultiLine.
209 @param value the target3 level. Usually the same as the target2 level,
210 for a steady target3ed note.
211 */
212 inline
213 void setTarget3Level(Q15n16 value)
214 {
215 target3.level=value;
216 }
217
218 /** Set the target4 level of the MultiLine. Normally you'd make this 0,
219 but you have the option of some other value.
220 @param value the target4 level (usually 0).
221 */
222 inline
223 void setTarget4Level(Q15n16 value)
224 {
225 target4.level=value;
226 }
227
228
229 inline
230 void setIdleLevel(Q15n16 value)
231 {
232 idle.level=value;
233 }
234
235
236 /** Set the target1, target2, target3 and target4 levels.
237 @param target1 the new target1 level.
238 @param target2 the new target3 level.
239 @param target1 the new target3 level.
240 @param target2 the new target4 level.
241 */
242 inline
243 void setLevels(Q15n16 target1, Q15n16 target2, Q15n16 target3, Q15n16 target4)
244 {
245 setTarget1Level(target1);
246 setTarget2Level(target2);
247 setTarget3Level(target3);
248 setTarget4Level(target4);
249 setIdleLevel(0);
250 }
251
252
253 /** Set the target1 time of the MultiLine in milliseconds.
254 The actual time taken will be resolved within the resolution of CONTROL_RATE.
255 @param msec the unsigned int target1 time in milliseconds.
256 @note Beware of low values (less than 20 or so, depending on how many steps are being taken),
257 in case internal step size gets calculated as 0, which would mean nothing happens.
258 */
259 inline
260 void setTarget1Time(unsigned int msec)
261 {
262 setTime(&target1, msec);
263 }
264
265
266 /** Set the target2 time of the MultiLine in milliseconds.
267 The actual time taken will be resolved within the resolution of CONTROL_RATE.
268 @param msec the unsigned int target2 time in milliseconds.
269 @note Beware of low values (less than 20 or so, depending on how many steps are being taken),
270 in case internal step size gets calculated as 0, which would mean nothing happens.
271 */
272 inline
273 void setTarget2Time(unsigned int msec)
274 {
275 setTime(&target2, msec);
276 }
277
278
279 /** Set the target3 time of the MultiLine in milliseconds.
280 The actual time taken will be resolved within the resolution of CONTROL_RATE.
281 The target3 phase will finish if the MultiLine recieves a stop().
282 @param msec the unsigned int target3 time in milliseconds.
283 @note Beware of low values (less than 20 or so, depending on how many steps are being taken),
284 in case internal step size gets calculated as 0, which would mean nothing happens.
285 */
286 inline
287 void setTarget3Time(unsigned int msec)
288 {
289 setTime(&target3, msec);
290 }
291
292
293
294 /** Set the target4 time of the MultiLine in milliseconds.
295 The actual time taken will be resolved within the resolution of CONTROL_RATE.
296 @param msec the unsigned int target4 time in milliseconds.
297 @note Beware of low values (less than 20 or so, depending on how many steps are being taken),
298 in case internal step size gets calculated as 0, which would mean nothing happens.
299 */
300 inline
301 void setTarget4Time(unsigned int msec)
302 {
303 setTime(&target4, msec);
304 }
305
306
307 inline
308 void setIdleTime(unsigned int msec)
309 {
310 setTime(&idle, msec);
311 }
312
313
314 /** Set the target1, target2 and target4 times of the MultiLine in milliseconds.
315 The actual times will be resolved within the resolution of CONTROL_RATE.
316 @param target1_ms the new target1 time in milliseconds.
317 @param target2_ms the new target2 time in milliseconds.
318 @param target3_ms the new target3 time in milliseconds.
319 @param target4_ms the new target4 time in milliseconds.
320 @note Beware of low values (less than 20 or so, depending on how many steps are being taken),
321 in case internal step size gets calculated as 0, which would mean nothing happens.
322 */
323 inline
324 void setTimes(unsigned int target1_ms, unsigned int target2_ms, unsigned int target3_ms, unsigned int target4_ms)
325 {
326 setTarget1Time(target1_ms);
327 setTarget2Time(target2_ms);
328 setTarget3Time(target3_ms);
329 setTarget4Time(target4_ms);
330 setIdleTime(65535); // guarantee step size of line will be 0
331 }
332
333
334
335 /** Set the target1 time of the MultiLine, expressed as the number of update steps (not MultiLine::next() interpolation steps) in the target1 phase.
336 @param steps the number of times MultiLine::update() will be called in the target1 phase.
337 */
338 inline
339 void setTarget1UpdateSteps(unsigned int steps)
340 {
341 setUpdateSteps(&target1, steps);
342 }
343
344
345 /** Set the target2 time of the MultiLine, expressed as the number of update steps (not MultiLine::next() interpolation steps) in the target2 phase.
346 @param steps the number of times MultiLine::update() will be called in the target2 phase.
347 */
348 inline
349 void setTarget2UpdateSteps(unsigned int steps)
350 {
351 setUpdateSteps(&target2, steps);
352 }
353
354
355 /** Set the target3 time of the MultiLine, expressed as the number of update steps (not MultiLine::next() interpolation steps) in the target3 phase.
356 @param steps the number of times MultiLine::update() will be called in the target3 phase.
357 */
358 inline
359 void setTarget3UpdateSteps(unsigned int steps)
360 {
361 setUpdateSteps(&target3, steps);
362 }
363
364
365 /** Set the target4 time of the MultiLine, expressed as the number of update steps (not MultiLine::next() interpolation steps) in the target4 phase.
366 @param steps the number of times MultiLine::update() will be called in the target4 phase.
367 */
368 inline
369 void setTarget4UpdateSteps(unsigned int steps)
370 {
371 setUpdateSteps(&target4, steps);
372 }
373
374
375 inline
376 void setIdleUpdateSteps(unsigned int steps)
377 {
378 setUpdateSteps(&idle, steps);
379 }
380
381 /** Set the target1, target2 and target4 times of the MultiLine, expressed in update steps (not MultiLine::next() interpolation steps).
382 @param target1_steps the number of update steps in the target1 phase
383 @param target2_steps the number of update steps in the target2 phase
384 @param target3_steps the number of update steps in the target3 phase
385 @param target4_steps the number of update steps in the target4 phase
386 */
387 inline
388 void setAllUpdateSteps(unsigned int target1_steps, unsigned int target2_steps, unsigned int target3_steps, unsigned int target4_steps)
389 {
390 setTarget1UpdateSteps(target1_steps);
391 setTarget2UpdateSteps(target2_steps);
392 setTarget3UpdateSteps(target3_steps);
393 setTarget4UpdateSteps(target4_steps);
394 setIdleUpdateSteps(65535); // guarantee? step size of line will be 0?
395 }
396
397
398
399 /** Tells if the envelope is currently playing.
400 @return true if playing, false if in IDLE state
401 */
402 inline
403 bool playing()
404 {
405 return !(current_phase->phase_type==IDLE);
406 }
407
408
409 };
410
411
412 /** @example 07.Envelopes/MultiLine_Envelope/MultiLine_Envelope.ino
413 This is an example of how to use the MultiLine class.
414 */
415
416 #endif /* MultiLine_H_ */
MultiLine::setTarget3Level
void setTarget3Level(Q15n16 value)
Set the target3 level of the MultiLine.
Definition: MultiLine.h:213
MultiLine::setTarget3Time
void setTarget3Time(unsigned int msec)
Set the target3 time of the MultiLine in milliseconds.
Definition: MultiLine.h:287
Q15n16
int32_t Q15n16
signed fractional number using 15 integer bits and 16 fractional bits, represents -32767...
Definition: mozzi_fixmath.h:40
MultiLine::setTarget2Level
void setTarget2Level(Q15n16 value)
Set the target2 level of the MultiLine.
Definition: MultiLine.h:202
MultiLine::stop
void stop()
Start the target4 phase of the MultiLine.
Definition: MultiLine.h:181
MultiLine::playing
bool playing()
Tells if the envelope is currently playing.
Definition: MultiLine.h:403
MultiLine::MultiLine
MultiLine()
Constructor.
Definition: MultiLine.h:112
MultiLine::setTarget4UpdateSteps
void setTarget4UpdateSteps(unsigned int steps)
Set the target4 time of the MultiLine, expressed as the number of update steps (not MultiLine::next()...
Definition: MultiLine.h:369
MultiLine::setTarget4Time
void setTarget4Time(unsigned int msec)
Set the target4 time of the MultiLine in milliseconds.
Definition: MultiLine.h:301
MultiLine::update
void update()
Updates the internal controls of the MultiLine.
Definition: MultiLine.h:128
MultiLine::setTarget2Time
void setTarget2Time(unsigned int msec)
Set the target2 time of the MultiLine in milliseconds.
Definition: MultiLine.h:273
MultiLine
A simple MultiLine envelope generator.
Definition: MultiLine.h:44
MultiLine::setTarget1Level
void setTarget1Level(Q15n16 value)
Set the target1 level of the MultiLine.
Definition: MultiLine.h:191
Line
For linear changes with a minimum of calculation at each step.
Definition: Line.h:37
MultiLine::setTarget3UpdateSteps
void setTarget3UpdateSteps(unsigned int steps)
Set the target3 time of the MultiLine, expressed as the number of update steps (not MultiLine::next()...
Definition: MultiLine.h:359
MultiLine::next
Q15n16 next()
Advances one step along the MultiLine and returns the level.
Definition: MultiLine.h:161
MultiLine::setTimes
void setTimes(unsigned int target1_ms, unsigned int target2_ms, unsigned int target3_ms, unsigned int target4_ms)
Set the target1, target2 and target4 times of the MultiLine in milliseconds.
Definition: MultiLine.h:324
MultiLine::setTarget4Level
void setTarget4Level(Q15n16 value)
Set the target4 level of the MultiLine.
Definition: MultiLine.h:223
MultiLine::setTarget2UpdateSteps
void setTarget2UpdateSteps(unsigned int steps)
Set the target2 time of the MultiLine, expressed as the number of update steps (not MultiLine::next()...
Definition: MultiLine.h:349
MultiLine::setAllUpdateSteps
void setAllUpdateSteps(unsigned int target1_steps, unsigned int target2_steps, unsigned int target3_steps, unsigned int target4_steps)
Set the target1, target2 and target4 times of the MultiLine, expressed in update steps (not MultiLine...
Definition: MultiLine.h:388
MultiLine::start
void start()
Start the target1 phase of the MultiLine.
Definition: MultiLine.h:171
MultiLine::setTarget1Time
void setTarget1Time(unsigned int msec)
Set the target1 time of the MultiLine in milliseconds.
Definition: MultiLine.h:260
MultiLine::setTarget1UpdateSteps
void setTarget1UpdateSteps(unsigned int steps)
Set the target1 time of the MultiLine, expressed as the number of update steps (not MultiLine::next()...
Definition: MultiLine.h:339
MultiLine::setLevels
void setLevels(Q15n16 target1, Q15n16 target2, Q15n16 target3, Q15n16 target4)
Set the target1, target2, target3 and target4 levels.
Definition: MultiLine.h:243