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

Ead.h
1 /*
2 * Ead.h
3 *
4 * Adapted from ead~.c puredata external (creb library)
5 * Copyright (c) 2000-2003 by Tom Schouten
6 *
7 * Copyright 2012 Tim Barrass, 2000-2003 Tom Schouten
8 *
9 * This file is part of Mozzi.
10 *
11 * Mozzi is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
12 *
13 */
14
15 #ifndef EAD_H_
16 #define EAD_H_
17
18 #include "math.h"
19 #include "mozzi_fixmath.h"
20
21
22 /** Exponential attack decay envelope. This produces a natural sounding
23 envelope. It calculates a new value each time next() is called, which can be
24 mapped to other parameters to change the amplitude or timbre of a sound.
25 @note Currently doesn't work at audio rate... may need larger number
26 types for Q8n8attack and Q8n8decay ?
27 */
28
29 class Ead
30 {
31
32 public:
33
34 /** Constructor
35 @param update_rate
36 Usually this will be CONTROL_RATE or AUDIO_RATE, unless you
37 design another scheme for updating. One such alternative scheme could take turns
38 for various control changes in a rotating schedule to spread out calculations
39 made in successive updateControl() routines.
40 */
41 Ead(unsigned int update_rate) : UPDATE_RATE(update_rate)
42 {
43 ;
44 }
45
46 /** Set the attack time in milliseconds.
47 @param attack_ms The time taken for values returned by successive calls of
48 the next() method to change from 0 to 255.
49 */
50 inline
51 void setAttack(unsigned int attack_ms)
52 {
53 Q8n8attack = float_to_Q8n8(millisToOneMinusRealPole(attack_ms));
54 }
55
56
57 /** Set the decay time in milliseconds.
58 @param decay_ms The time taken for values returned by successive calls of
59 the next() method to change from 255 to 0.
60 */
61 inline
62 void setDecay(unsigned int decay_ms)
63 {
64 Q8n8decay = float_to_Q8n8(millisToOneMinusRealPole(decay_ms));
65 }
66
67
68 /** Set attack and decay times in milliseconds.
69 @param attack_ms The time taken for values returned by successive calls of
70 the next() method to change from 0 to 255.
71 @param decay_ms The time taken for values returned by successive calls of
72 the next() method to change from 255 to 0.
73 */
74 inline
75 void set(unsigned int attack_ms, unsigned int decay_ms)
76 {
77 setAttack(attack_ms);
78 setDecay(decay_ms);
79 }
80
81
82 /** Start the envelope from the beginning.
83 This can be used at any time, even if the previous envelope is not finished.
84 */
85 inline
86 void start()
87 {
88 Q8n24state = 0;
89 attack_phase = true;
90 }
91
92
93 /** Set attack and decay times in milliseconds, and start the envelope from the beginning.
94 This can be used at any time, even if the previous envelope is not finished.
95 @param attack_ms The time taken for values returned by successive calls of
96 the next() method to change from 0 to 255.
97 @param decay_ms The time taken for values returned by successive calls of
98 the next() method to change from 255 to 0.
99 */
100 inline
101 void start(unsigned int attack_ms, unsigned int decay_ms)
102 {
103 set(attack_ms, decay_ms);
104 //Q8n24state = 0; // don't restart from 0, just go from whatever the current level is, to avoid glitches
105 attack_phase = true;
106 }
107
108
109 /** Calculate and return the next envelope value, in the range -128 to 127
110 @note Timing: 5us
111 */
112
113 inline
114 uint8_t next()
115 {
116 if(attack_phase)
117 {
118 // multiply A(a1,b1) * A(a2,b2) = A(a1+a2, b1+b2)
119 Q8n24state += (((Q8n24)(Q8n24_FIX1 - Q8n24state) * Q8n8attack)) >> 8; // Q8n24, shifts all back into n24
120 if (Q8n24state >= Q8n24_FIX1-256)
121 {
122 Q8n24state = Q8n24_FIX1-256;
123 attack_phase = false;
124 }
125 }else{ /* decay phase */
126 Q8n24state -= (Q8n24state * Q8n8decay)>>8;
127 }
128 return Q8n24_to_Q0n8(Q8n24state);
129 }
130
131
132 private:
133
134 Q8n8 Q8n8attack;
135 Q8n8 Q8n8decay;
136 Q8n24 Q8n24state;
137 bool attack_phase;
138 const unsigned int UPDATE_RATE;
139
140
141 /* convert milliseconds to 1-p, with p a real pole */
142 inline
143 float millisToOneMinusRealPole(unsigned int milliseconds)
144 {
145 static const float NUMERATOR = 1000.0f * log(0.001f);
146 return -expm1(NUMERATOR / ((float)UPDATE_RATE * milliseconds));
147 }
148
149
150 // Compute exp(x) - 1 without loss of precision for small values of x.
151 inline
152 float expm1(float x)
153 {
154 if (fabs(x) < 1e-5)
155 {
156 return x + 0.5*x*x;
157 }
158 else
159 {
160 return exp(x) - 1.0;
161 }
162 }
163
164 };
165
166 /**
167 @example 07.Envelopes/Ead_Envelope/Ead_Envelope.ino
168 This is an example of how to use the Ead class.
169 */
170
171 #endif /* EAD_H_ */
Q8n8
uint16_t Q8n8
unsigned fractional number using 8 integer bits and 8 fractional bits, represents 0 to 255...
Definition: mozzi_fixmath.h:35
Ead::start
void start(unsigned int attack_ms, unsigned int decay_ms)
Set attack and decay times in milliseconds, and start the envelope from the beginning.
Definition: Ead.h:101
Ead::set
void set(unsigned int attack_ms, unsigned int decay_ms)
Set attack and decay times in milliseconds.
Definition: Ead.h:75
Ead
Exponential attack decay envelope.
Definition: Ead.h:29
Ead::Ead
Ead(unsigned int update_rate)
Constructor.
Definition: Ead.h:41
Ead::start
void start()
Start the envelope from the beginning.
Definition: Ead.h:86
float_to_Q8n8
Q8n8 float_to_Q8n8(float a)
Convert float to Q8n8 fix.
Definition: mozzi_fixmath.h:103
Ead::setAttack
void setAttack(unsigned int attack_ms)
Set the attack time in milliseconds.
Definition: Ead.h:51
Ead::setDecay
void setDecay(unsigned int decay_ms)
Set the decay time in milliseconds.
Definition: Ead.h:62
Ead::next
uint8_t next()
Calculate and return the next envelope value, in the range -128 to 127.
Definition: Ead.h:114
Q8n24
uint32_t Q8n24
signed fractional number using 8 integer bits and 24 fractional bits, represents 0 to 255...
Definition: mozzi_fixmath.h:44
Q8n24_FIX1
#define Q8n24_FIX1
1 in Q8n24 format
Definition: mozzi_fixmath.h:64
Q8n24_to_Q0n8
Q0n8 Q8n24_to_Q0n8(Q8n24 a)
Convert Q8n24 fixed to Q0n8 uint8_t.
Definition: mozzi_fixmath.h:229