Mozzi  version v2.0
sound synthesis library for Arduino
ADSR.h
1 /*
2  * ADSR.h
3  *
4  * This file is part of Mozzi.
5  *
6  * Copyright 2012-2024 Tim Barrass and the Mozzi Team
7  *
8  * Mozzi is licensed under the GNU Lesser General Public Licence (LGPL) Version 2.1 or later.
9  *
10  */
11 
12 #ifndef ADSR_H_
13 #define ADSR_H_
14 
15 #include <Arduino.h>
16 #include "Line.h"
17 #include "mozzi_fixmath.h"
18 
19 
20 /** A simple ADSR envelope generator. This implementation has separate update() and next()
21 methods, where next() interpolates values between each update().
22 The "normal" way to use this would be with update() in updateControl(), where it calculates a new internal state each control step,
23 and then next() is in updateAudio(), called much more often, where it interpolates between the control values.
24 This also allows the ADSR updates to be made even more sparsely if desired, eg. every 3rd control update.
25 @tparam CONTROL_UPDATE_RATE The frequency of control updates.
26 Ordinarily this will be MOZZI_CONTROL_RATE, but an alternative (amongst others) is
27 to set this as well as the LERP_RATE parameter to MOZZI_AUDIO_RATE, and call both update() and next() in updateAudio().
28 Such a use would allow accurate envelopes with finer resolution of the control points than MOZZI_CONTROL_RATE.
29 @tparam LERP_RATE Sets how often next() will be called, to interpolate between updates set by CONTROL_UPDATE_RATE.
30 This will produce the smoothest results if it's set to MOZZI_AUDIO_RATE, but if you need to save processor time and your
31 envelope changes slowly or controls something like a filter where there may not be problems with glitchy or clicking transitions,
32 LERP_RATE could be set to MOZZI_CONTROL_RATE (for instance). Then update() and next() could both be called in updateControl(),
33 greatly reducing the amount of processing required compared to calling next() in updateAudio().
34 @todo Test whether using the template parameters makes any difference to speed,
35 and rationalise which units do and don't need them.
36 Template objects are messy when you try to use pointers to them,
37 you have to include the whole template in the pointer handling.
38 */
39 
40 template <unsigned int CONTROL_UPDATE_RATE, unsigned int LERP_RATE, typename T = unsigned int>
41 class ADSR
42 {
43 private:
44 
45  const unsigned int LERPS_PER_CONTROL;
46 
47  T update_step_counter;
48  T num_update_steps;
49 
50  enum {ATTACK,DECAY,SUSTAIN,RELEASE,IDLE};
51 
52 
53  struct phase{
54  byte phase_type;
55  T update_steps;
56  long lerp_steps; // signed, to match params to transition (line) type Q15n16, below
57  Q8n0 level;
58  }attack,decay,sustain,release,idle;
59 
60  phase * current_phase;
61 
62  // Linear audio rate transitions for envelope
63  //Line <unsigned long> transition;
64  Line <Q15n16> transition; // scale up unsigned char levels for better accuracy, then scale down again for output
65 
66  inline
67  T convertMsecToControlUpdateSteps(unsigned int msec){
68  return (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(Q8n0_to_Q15n16(next_phase->level),next_phase->lerp_steps);
77  current_phase = next_phase;
78  }
79 
80 
81  inline
82  void checkForAndSetNextPhase(phase * next_phase) {
83  if (++update_step_counter >= num_update_steps){
84  setPhase(next_phase);
85  }
86  }
87 
88 
89 
90  inline
91  void setTime(phase * p, unsigned int msec)
92  {
93  p->update_steps = convertMsecToControlUpdateSteps(msec);
94  p->lerp_steps = (long) p->update_steps * LERPS_PER_CONTROL;
95  }
96 
97 
98  inline
99  void setUpdateSteps(phase * p, unsigned int steps)
100  {
101  p->update_steps = steps;
102  p->lerp_steps = (long) steps * LERPS_PER_CONTROL;
103  }
104 
105 
106 
107 public:
108 
109  /** Constructor.
110  */
111  ADSR():LERPS_PER_CONTROL(LERP_RATE/CONTROL_UPDATE_RATE)
112  {
113  attack.phase_type = ATTACK;
114  decay.phase_type = DECAY;
115  sustain.phase_type = SUSTAIN;
116  release.phase_type = RELEASE;
117  idle.phase_type = IDLE;
118  release.level = 0;
119  adsr_playing = false;
120  current_phase = &idle;
121  }
122 
123 
124 
125  /** Updates the internal controls of the ADSR.
126  Call this in updateControl().
127  */
128  void update(){ // control rate
129 
130  switch(current_phase->phase_type) {
131 
132  case ATTACK:
133  checkForAndSetNextPhase(&decay);
134  break;
135 
136  case DECAY:
137  checkForAndSetNextPhase(&sustain);
138  break;
139 
140  case SUSTAIN:
141  checkForAndSetNextPhase(&release);
142  break;
143 
144  case RELEASE:
145  checkForAndSetNextPhase(&idle);
146  break;
147 
148  case IDLE:
149  adsr_playing = false;
150  break;
151  }
152  }
153 
154 
155 
156  /** Advances one audio step along the ADSR and returns the level.
157  Call this in updateAudio().
158  @return the next value, as an unsigned char.
159  */
160  inline
161  unsigned char next()
162  {
163  unsigned char out = 0;
164  if (adsr_playing) out = Q15n16_to_Q8n0(transition.next());
165  return out;
166  }
167 
168 
169 
170  /** Start the attack phase of the ADSR. This will restart the ADSR no matter what phase it is up to.
171  @param reset If true, the envelope will start from 0, even if it is still playing (often useful for effect envelopes).
172  If false (default if omitted), the envelope will start rising from the current level, which could be non-zero, if
173  it is still playing (most useful for note envelopes).
174  */
175  inline
176  void noteOn(bool reset=false){
177  if (reset) transition.set(0);
178  setPhase(&attack);
179  adsr_playing = true;
180  }
181 
182 
183 
184  /** Start the release phase of the ADSR.
185  @todo fix release for rate rather than steps (time), so it releases at the same rate whatever the current level.
186  */
187  inline
188  void noteOff(){
189  setPhase(&release);
190  }
191 
192 
193 
194  /** Set the attack level of the ADSR.
195  @param value the attack level.
196  */
197  inline
198  void setAttackLevel(byte value)
199  {
200  attack.level=value;
201  }
202 
203 
204 
205  /** Set the decay level of the ADSR.
206  @param value the decay level.
207  */
208  inline
209  void setDecayLevel(byte value)
210  {
211  decay.level=value;
212  }
213 
214 
215  /** Set the sustain level of the ADSR.
216  @param value the sustain level. Usually the same as the decay level,
217  for a steady sustained note.
218  */
219  inline
220  void setSustainLevel(byte value)
221  {
222  sustain.level=value;
223  }
224 
225  /** Set the release level of the ADSR. Normally you'd make this 0,
226  but you have the option of some other value.
227  @param value the release level (usually 0).
228  */
229  inline
230  void setReleaseLevel(byte value)
231  {
232  release.level=value;
233  }
234 
235 
236  inline
237  void setIdleLevel(byte value)
238  {
239  idle.level=value;
240  }
241 
242 
243  /** Set the attack and decay levels of the ADSR. This assumes a conventional
244  ADSR where the sustain continues at the same level as the decay, till the release ramps to 0.
245  @param attack the new attack level.
246  @param decay the new decay level.
247  */
248  inline
249  void setADLevels(byte attack, byte decay)
250  {
251  setAttackLevel(attack);
252  setDecayLevel(decay);
253  setSustainLevel(decay); // stay at decay level
254  setReleaseLevel(1);
255  setIdleLevel(0);
256  }
257 
258 
259  /** Set the attack, decay, sustain and release levels.
260  @param attack the new attack level.
261  @param decay the new sustain level.
262  @param attack the new sustain level.
263  @param decay the new release level.
264  */
265  inline
266  void setLevels(byte attack, byte decay, byte sustain, byte release)
267  {
268  setAttackLevel(attack);
269  setDecayLevel(decay);
270  setSustainLevel(sustain);
271  setReleaseLevel(release);
272  setIdleLevel(0);
273  }
274 
275 
276  /** Set the attack time of the ADSR in milliseconds.
277  The actual time taken will be resolved within the resolution of MOZZI_CONTROL_RATE.
278  @param msec the unsigned int attack time in milliseconds.
279  @note Beware of low values (less than 20 or so, depending on how many steps are being taken),
280  in case internal step size gets calculated as 0, which would mean nothing happens.
281  */
282  inline
283  void setAttackTime(unsigned int msec)
284  {
285  setTime(&attack, msec);
286  }
287 
288 
289  /** Set the decay time of the ADSR in milliseconds.
290  The actual time taken will be resolved within the resolution of MOZZI_CONTROL_RATE.
291  @param msec the unsigned int decay time in milliseconds.
292  @note Beware of low values (less than 20 or so, depending on how many steps are being taken),
293  in case internal step size gets calculated as 0, which would mean nothing happens.
294  */
295  inline
296  void setDecayTime(unsigned int msec)
297  {
298  setTime(&decay, msec);
299  }
300 
301 
302  /** Set the sustain time of the ADSR in milliseconds.
303  The actual time taken will be resolved within the resolution of MOZZI_CONTROL_RATE.
304  The sustain phase will finish if the ADSR recieves a noteOff().
305  @param msec the unsigned int sustain time in milliseconds.
306  @note Beware of low values (less than 20 or so, depending on how many steps are being taken),
307  in case internal step size gets calculated as 0, which would mean nothing happens.
308  */
309  inline
310  void setSustainTime(unsigned int msec)
311  {
312  setTime(&sustain, msec);
313  }
314 
315 
316 
317  /** Set the release time of the ADSR in milliseconds.
318  The actual time taken will be resolved within the resolution of MOZZI_CONTROL_RATE.
319  @param msec the unsigned int release 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 setReleaseTime(unsigned int msec)
325  {
326  setTime(&release, msec);
327  }
328 
329 
330  inline
331  void setIdleTime(unsigned int msec)
332  {
333  setTime(&idle, msec);
334  }
335 
336 
337  /** Set the attack, decay and release times of the ADSR in milliseconds.
338  The actual times will be resolved within the resolution of MOZZI_CONTROL_RATE.
339  @param attack_ms the new attack time in milliseconds.
340  @param decay_ms the new decay time in milliseconds.
341  @param sustain_ms the new sustain time in milliseconds.
342  @param release_ms the new release time in milliseconds.
343  @note Beware of low values (less than 20 or so, depending on how many steps are being taken),
344  in case internal step size gets calculated as 0, which would mean nothing happens.
345  */
346  inline
347  void setTimes(unsigned int attack_ms, unsigned int decay_ms, unsigned int sustain_ms, unsigned int release_ms)
348  {
349  setAttackTime(attack_ms);
350  setDecayTime(decay_ms);
351  setSustainTime(sustain_ms);
352  setReleaseTime(release_ms);
353  setIdleTime(65535); // guarantee step size of line will be 0
354  }
355 
356 
357 
358  /** Set the attack time of the ADSR, expressed as the number of update steps (not ADSR::next() interpolation steps) in the attack phase.
359  @param steps the number of times ADSR::update() will be called in the attack phase.
360  */
361  inline
362  void setAttackUpdateSteps(unsigned int steps)
363  {
364  setUpdateSteps(&attack, steps);
365  }
366 
367 
368  /** Set the decay time of the ADSR, expressed as the number of update steps (not ADSR::next() interpolation steps) in the decay phase.
369  @param steps the number of times ADSR::update() will be called in the decay phase.
370  */
371  inline
372  void setDecayUpdateSteps(unsigned int steps)
373  {
374  setUpdateSteps(&decay, steps);
375  }
376 
377 
378  /** Set the sustain time of the ADSR, expressed as the number of update steps (not ADSR::next() interpolation steps) in the sustain phase.
379  @param steps the number of times ADSR::update() will be called in the sustain phase.
380  */
381  inline
382  void setSustainUpdateSteps(unsigned int steps)
383  {
384  setUpdateSteps(&sustain, steps);
385  }
386 
387 
388  /** Set the release time of the ADSR, expressed as the number of update steps (not ADSR::next() interpolation steps) in the release phase.
389  @param steps the number of times ADSR::update() will be called in the release phase.
390  */
391  inline
392  void setReleaseUpdateSteps(unsigned int steps)
393  {
394  setUpdateSteps(&release, steps);
395  }
396 
397 
398  inline
399  void setIdleUpdateSteps(unsigned int steps)
400  {
401  setUpdateSteps(&idle, steps);
402  }
403 
404  /** Set the attack, decay and release times of the ADSR, expressed in update steps (not ADSR::next() interpolation steps).
405  @param attack_steps the number of update steps in the attack phase
406  @param decay_steps the number of update steps in the decay phase
407  @param sustain_steps the number of update steps in the sustain phase
408  @param release_steps the number of update steps in the release phase
409  */
410  inline
411  void setAllUpdateSteps(unsigned int attack_steps, unsigned int decay_steps, unsigned int sustain_steps, unsigned int release_steps)
412  {
413  setAttackUpdateSteps(attack_steps);
414  setDecayUpdateSteps(decay_steps);
415  setSustainUpdateSteps(sustain_steps);
416  setReleaseUpdateSteps(release_steps);
417  setIdleUpdateSteps(65535); // guarantee step size of line will be 0
418  }
419 
420 
421 bool adsr_playing;
422 
423  /** Tells if the envelope is currently playing.
424  @return true if playing, false if in IDLE state
425  */
426  inline
427  bool playing()
428  {
429  return adsr_playing;
430  }
431 
432 
433 };
434 
435 
436 /** @example 07.Envelopes/ADSR_Envelope/ADSR_Envelope.ino
437 This is an example of how to use the ADSR class.
438 */
439 
440 #endif /* ADSR_H_ */