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

MultiLine2.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 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
44 template <unsigned int NUM_PHASES, unsigned int CONTROL_UPDATE_RATE, unsigned int LERP_RATE>
45 class MultiLine
46 {
47 private:
48
49 const unsigned int LERPS_PER_CONTROL;
50
51 unsigned int update_step_counter;
52 unsigned int num_update_steps;
53
54 //enum {LINE1,LINE2,LINE3,LINE4,IDLE};
55
56
57 struct phase{
58 byte phase_type;
59 unsigned int update_steps;
60 long lerp_steps; // signed, to match params to transition (line) type Q15n16, below
61 Q15n16 level;
62 };//target1,target2,target3,target4,idle;
63
64 phase phases[NUM_PHASES];
65 unsigned int current_phase_num;
66
67 phase * current_phase;
68
69 Line <Q15n16> transition;
70
71
72 inline
73 unsigned int convertMsecToControlUpdateSteps(unsigned int msec){
74 return (uint16_t) (((uint32_t)msec*CONTROL_UPDATE_RATE)>>10); // approximate /1000 with shift
75 }
76
77
78 inline
79 void setPhase(phase * next_phase) {
80 update_step_counter = 0;
81 num_update_steps = next_phase->update_steps;
82 transition.set(next_phase->level, next_phase->lerp_steps);
83 current_phase = next_phase;
84 }
85
86
87
88 inline
89 void checkForAndSetNextPhase() {
90 if (++update_step_counter >= num_update_steps){
91 if(current_phase_num < NUM_PHASES) current_phase_num++;
92 setPhase(&(phases[current_phase_num]));
93 }
94 }
95
96
97
98 inline
99 void setTime(phase * p, unsigned int msec)
100 {
101 p->update_steps = convertMsecToControlUpdateSteps(msec);
102 p->lerp_steps = (long) p->update_steps * LERPS_PER_CONTROL;
103 }
104
105
106 inline
107 void setUpdateSteps(phase * p, unsigned int steps)
108 {
109 p->update_steps = steps;
110 p->lerp_steps = (long) steps * LERPS_PER_CONTROL;
111 }
112
113
114
115 public:
116
117 /** Constructor.
118 */
119 MultiLine():LERPS_PER_CONTROL(LERP_RATE/CONTROL_UPDATE_RATE)
120 {
121 //for(int i=0;i++;i<NUM_PHASES-1) phases[i].phase_type =
122 // target1.phase_type = LINE1;
123 // target2.phase_type = LINE2;
124 // target3.phase_type = LINE3;
125 // target4.phase_type = LINE4;
126 // idle.phase_type = IDLE;
127 // target4.level = 0;
128 current_phase_num = NUM_PHASES-1;
129 current_phase = &phases[current_phase_num];
130 }
131
132
133
134 /** Updates the internal controls of the MultiLine.
135 Call this in updateControl().
136 */
137 void update(){ // control rate
138 checkForAndSetNextPhase();
139 }
140
141
142
143 /** Advances one step along the MultiLine and returns the level.
144 Call this in updateAudio().
145 @return the next value, as a Q15n16 fixed-point number.
146 */
147 inline
148 Q15n16 next()
149 {
150 return transition.next();
151 }
152
153
154
155 /** Start the target1 phase of the MultiLine. THis will restart the MultiLine no matter what phase it is up to.
156 */
157 inline
158 void start(){
159 current_phase_num = 0;
160 setPhase(&(phases[current_phase_num]));
161 }
162
163
164
165 /** Jump to to the final phase in the sequence
166 */
167 inline
168 void stop(){
169 setPhase(&(phases[NUM_PHASES-1]));
170 }
171
172
173
174 /** Set the target level of one of the phases.
175 @param phase_num which phase to edit.
176 @param value the target level of the phase being edited.
177 */
178 inline
179 void setTargetLevel(uint8_t phase_num, Q15n16 value)
180 {
181 phases[phase_num].level=value;
182 }
183
184
185 /** Set the time taken to reach the target level of a phase, in milliseconds.
186 The actual time taken will be resolved within the resolution of CONTROL_RATE.
187 @param phase_num which phase to edit.
188 @param msec the target time in milliseconds.
189 @note Beware of low time values in case internal step size gets calculated as 0, which would mean nothing happens.
190 */
191 inline
192 void setTargetTime(uint8_t phase_num, unsigned int msec)
193 {
194 setTime(&(phases[phase_num]), msec);
195 }
196
197
198 /** Set the target1 time of the MultiLine, expressed as the number of update steps (not MultiLine::next() interpolation steps) in the target1 phase.
199 @param steps the number of times MultiLine::update() will be called in the target1 phase.
200 */
201 inline
202 void setTargetUpdateSteps(uint8_t phase_num, unsigned int steps)
203 {
204 setUpdateSteps(&(phases[phase_num]), steps);
205 }
206
207
208 /** Tells if the MultiLine is currently playing.
209 @return true if playing, false if in the final state
210 */
211 inline
212 bool playing()
213 {
214 return current_phase_num != NUM_PHASES-1;
215 }
216
217
218 };
219
220
221 /** @example 07.Envelopes/MultiLine_Envelope/MultiLine_Envelope.ino
222 This is an example of how to use the MultiLine class.
223 */
224
225 #endif /* MultiLine_H_ */
MultiLine::setTargetLevel
void setTargetLevel(uint8_t phase_num, Q15n16 value)
Set the target level of one of the phases.
Definition: MultiLine2.h:179
Q15n16
int32_t Q15n16
signed fractional number using 15 integer bits and 16 fractional bits, represents -32767...
Definition: mozzi_fixmath.h:40
MultiLine::stop
void stop()
Jump to to the final phase in the sequence.
Definition: MultiLine2.h:168
MultiLine::playing
bool playing()
Tells if the MultiLine is currently playing.
Definition: MultiLine2.h:212
MultiLine::MultiLine
MultiLine()
Constructor.
Definition: MultiLine2.h:119
MultiLine::setTargetTime
void setTargetTime(uint8_t phase_num, unsigned int msec)
Set the time taken to reach the target level of a phase, in milliseconds.
Definition: MultiLine2.h:192
MultiLine::update
void update()
Updates the internal controls of the MultiLine.
Definition: MultiLine2.h:137
MultiLine::setTargetUpdateSteps
void setTargetUpdateSteps(uint8_t phase_num, unsigned int steps)
Set the target1 time of the MultiLine, expressed as the number of update steps (not MultiLine::next()...
Definition: MultiLine2.h:202
Line
For linear changes with a minimum of calculation at each step.
Definition: Line.h:37
MultiLine::next
Q15n16 next()
Advances one step along the MultiLine and returns the level.
Definition: MultiLine2.h:148
MultiLine::start
void start()
Start the target1 phase of the MultiLine.
Definition: MultiLine2.h:158