CSL 5.2

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

Envelope.h
Go to the documentation of this file.
1 ///
2 /// Envelope.h -- The basic (concrete) CSL breakpoint envelope classes.
3 /// See the copyright notice and acknowledgment of authors in the file COPYRIGHT
4 ///
5 ///
6 /// These are UnitGenerators that represent arbitrarily long breakpoint functions and do linear
7 /// interpolation between their breakpoints. There are several kinds of
8 /// constructors, e.g., using breakpoint objects or x/y value pairs, and one
9 /// can scale the values or times of an existing envelope.
10 ///
11 /// Classes:
12 /// LineSegment: A linearly interpolated segment with start and end values, and a duration (in seconds).
13 /// Envelope: a collection of LineSegments; may have an input and act like an effect,
14 /// or have no input and act like a control UnitGenerator
15 /// Specific kinds of envelope (AR, ADSR, Triangle) and RandomEnvelope
16 ///
17
18 #ifndef CSL_Envelope_H
19 #define CSL_Envelope_H
20
21 #include "CSL_Core.h"
22 #include "CPoint.h"
23
24 namespace csl {
25
26 ///
27 /// LineSegment flags for line interpolation.
28 ///
29
30 #ifdef CSL_ENUMS
31 typedef enum {
32 kLine, ///< linear interpolation between start and end values.
33 kExpon, ///< linear interpolation between start and end values.
34 } LineMode;
35 #else
36 #define kLine 1
37 #define kExpon 2
38 typedef int LineMode;
39 #endif
40
41 ///
42 /// A linearly interpolated segment -- this has start and end values, and a duration (in seconds).
43 ///
44
45 class LineSegment : public UnitGenerator {
46 public:
47 LineSegment(); ///< empty constructor
48 LineSegment(float d, float s, float e, LineMode mode = kLine); ///< Declare dur in sec, start, stop values
49
50 /// Accessors
51 float start() { return mStart; } ///< Returns the initial value of the line segment.
52 float end() { return mEnd; } ///< Returns the target value of the line segment.
53 float duration() { return mDuration; } ///< Returns the total time it will take to get from start to end value.
54 unsigned currentFrame() { return mCurrentFrame; };
55
56 void setEnd(float tend) { mEnd = tend; }
57 void setStart(float tstart) { mStart = tstart; mCurrentValue = mStart; }
58 void setDuration(unsigned tduration) { mDuration = (float) tduration; } ///< Overloaded to accept either float or unsigned.
59 void setDuration(float tduration) { mDuration = tduration; }
60 void setMode(LineMode tmode) { mMode = tmode; } ///< Sets the interpolation kind (linear or exponential)
61
62 /// next buffer interpolator
63 void nextBuffer(Buffer &outputBuffer, unsigned outBufNum) throw (CException);
64 /// handy version given Scalable port pointers
65 virtual void nextBuffer(Buffer &outputBuffer, unsigned outBufNum, Port * scalePort, Port * offsetPort) throw (CException);
66
67 void reset(); ///< reset counters
68 void trigger() { this->reset(); }; ///< reset internal time to restart envelope
69 void dump(); ///< Prints to screen the start and end values and the duration of the line.
70
71 protected:
72 float mStart; ///< Start value
73 float mEnd; ///< Ending value
74 float mDuration ; ///< Length of the line segment (IN SECONDS)
75 LineMode mMode; ///< How am I to calculate the values from start to end values of the line.
76 float mCurrentValue; ///< Internal book-keeping
77 unsigned mCurrentFrame; ///< cache
78 };
79
80 /// a map between a time and a line segment
81
82 typedef map<float, LineSegment *> Breakpoints;
83
84 ///
85 /// Envelope: a collection of LineSegments; may have an input (scale) and act like a processor,
86 /// or have no input and act like a control UGen. I inherit Scalable setScale, setOffset for inputs
87 ///
88
89 class Envelope : public UnitGenerator, public Scalable {
90 public:
91 Envelope() : UnitGenerator(), Scalable(1, 0), mDuration(0), mSegments(0), mValues(0) { };
92 Envelope(LineMode mode, float t, float x1, float y1, float x2 = 0, float y2 = 1.0, float x3 = 0, float y3 = 1.0,
93 float x4 = 0, float y4 = 1.0, float x5 = 0, float y5 = 1.0, float x6 = 0, float y6 = 1.0);
94 Envelope(LineMode mode, float t, unsigned int size, float x[], float y[]);
95 Envelope(float t, float x1, float y1, float x2 = 0, float y2 = 1.0, float x3 = 0, float y3 = 1.0,
96 float x4 = 0, float y4 = 1.0, float x5 = 0, float y5 = 1.0, float x6 = 0, float y6 = 1.0);
97 Envelope(float t, unsigned int size, float x[], float y[]);
98
99 virtual ~Envelope();
100 /// This answers whether I'm active (ptr < end)
101 virtual bool isActive();
102
103 void addBreakpoint(float startTime, float value);
104
105 void setMode(LineMode mode);
106 // void setInterpolationAtSegment(LineMode mode, unsigned idx); ///< allows to specify interpolation other than linear for a segment.
107 virtual void setDuration(float d); ///< set/scale durations
108 virtual void scaleTimes(float s); ///< scale durations
109 virtual void scaleValues(float s); ///< scale values so the max is s
110
111 virtual void reset(); ///< reset internal time to restart envelope
112 virtual void trigger(); ///< reset internal time to restart envelope
113 virtual void dump();
114 /// The main FrameStream work method
115 virtual void nextBuffer(Buffer &outputBuffer, unsigned outBufNum) throw (CException);
116
117 protected:
118 float mDuration; ///< Total duration, typically in seconds
119 float mCurrentMark; ///< How far we have read
120 Breakpoints mSegmentMap; ///< list of envelope breakpoints
121 LineSegment **mSegments; ///< array of line segments that for the envelope
122 float *mValues;
123 unsigned mSize;
124 /// Internal helper method for computing the next buffer
125 unsigned int privateNextBuffer(CPoint *breakpoint, LineSegment *segment, float *buffer, unsigned int numFrames);
126 void createSegments(); ///< Allocate memory for the segments.
127 void calculateSegments(); ///< Calculate the internal data
128 };
129
130 /// ADSR = 4-segment attack/decay/sustain/release envelope class.
131
132 /**
133 Most of this is inherited from Envelope.
134 This design is an extended ADSR envelope with an initial constant segment and offset
135 (default = 0@0; this can be used to make an attack delay as on ARP ADSRs), attack time and
136 max. val (default = 1.0), decay time, sustain level, and release time and final value (default = 0.0).
137 All times are assumed to be given in seconds.
138 Note that there are many variations on the constructor.
139 The 5 line segments used internally look something like the following
140
141 | / .
142 | / \ .
143 | / \--------------- .
144 | / \ .
145 |---/ \ .
146 | \----- .
147 --------------------------------------------------------------------
148
149 Note that, internally, the breakpoints are kept with cumulative times, whereas the
150 line segments only have start/stop Y values and durations (i.e., no absolute time reference).
151 */
152
153 class ADSR : public Envelope {
154
155 public:
156 ADSR() : Envelope() { };
157 /// Minimal version - ADSR
158 ADSR(LineMode mode, float t, float a, float d, float s, float r);
159 /// with initial delay - IADSR
160 ADSR(LineMode mode, float t, float i, float a, float d, float s, float r);
161 /// Minimal version - ADSR
162 ADSR(float t, float a, float d, float s, float r);
163 /// with initial delay - IADSR
164 ADSR(float t, float i, float a, float d, float s, float r);
165 ~ADSR() { };
166 /// Special accessors
167 void setDuration(float d); ///< set duration = scale steady-state part of env
168 void setDelay(float del);
169 void setAttack(float attack);
170 void setDecay(float decay);
171 void setSustain(float sustain);
172 void setRelease(float release);
173
174 void release(void); /// trigger the release segment
175 };
176
177 /// AR = 3-segment attack/release envelope class.
178
179 /**
180 Most of this is inherited from Envelope.
181 This design is an extended AR envelope with an initial constant segment and offset
182 (default = 0@0; this can be used to make an attack delay as on ARP ARs), attack time and
183 max. val (default = 1.0), and release time and final value (default = 0.0).
184 All times are assumed to be given in seconds.
185 Note that there are many variations on the constructor.
186 The line segments used internally look something like the following
187
188 |
189 | /---------------
190 | / \
191 |---/ \
192 | \-----
193 ------------------------------------
194
195 Note that, internally, the breakpoints are kept with cumulative times, whereas the
196 line segments only have start/stop Y values and durations (i.e., no absolute time reference).
197 */
198
199 class AR : public Envelope {
200
201 public: /// Various Constructors
202 AR() : Envelope() { };
203 /// Minimal version - AR
204 AR(LineMode mode, float t, float a, float r);
205 /// with initial delay - IAR
206 AR(LineMode mode, float t, float i, float a, float r);
207 /// Minimal version - AR
208 AR(float t, float a, float r);
209 /// with initial delay - IAR
210 AR(float t, float i, float a, float r);
211
212 ~AR() { };
213 /// Special accessors
214 void setDuration(float d); ///< set duration = scale steady-state part of env
215 void setDelay(float del);
216 void setAttack(float attack);
217 void setRelease(float release);
218 void setAll(float d, float a, float r);
219 /// Operations
220 void release(void); ///< trigger the release segment
221 };
222
223 ///
224 /// Triangle envelope class -- equal attack/release times
225 ///
226
227 class Triangle : public Envelope {
228
229 public: /// Various Constructors
230 Triangle() : Envelope() { };
231 /// Simple constructor
232 Triangle(LineMode mode, float duration, float amplitude);
233 /// Versions with initial delay segments
234 Triangle(LineMode mode, float duration, float initialDelay, float amplitude);
235 /// Simple constructor
236 Triangle(float duration, float amplitude = 1.0f);
237 /// Versions with initial delay segments
238 Triangle(float duration, float initialDelay, float amplitude);
239 /// Minimal version - AR
240 ~Triangle() { };
241 };
242
243 ///
244 /// RandEnvelope envelope class -- makes random control signals using a single line segment
245 ///
246
247 class RandEnvelope : public Envelope {
248 public: /// defaults are 1 Hz, +- 1.0 range
249 RandEnvelope(float frequency = 1, float amplitude = 1, float offset = 0, float step = 0);
250 ~RandEnvelope() { };
251 /// Accessors
252 void setWalk(bool walk) { mWalk = walk; };
253 void setAmplitude(float amplitude) { mAmplitude = amplitude; };
254 void setFrequency(float frequency) { mFrequency = frequency; };
255 void setStep(float step) { mStep = step; };
256 void setOffset(float offset) { mOffset = offset; };
257
258 virtual bool isActive() { return false; };
259 /// These are no-ops in Random envelopes
260 void reset() { }; ///< reset internal time to restart envelope
261 void trigger() { }; ///< reset internal time to restart envelope
262 void dump() { }; ///< print the receiver
263 void setDuration(float d) { }; ///< set/scale durations
264 void scaleTimes(float s) { }; ///< scale durations
265
266 /// The main UGen work method
267 void nextBuffer(Buffer &outputBuffer, unsigned outBufNum) throw (CException);
268
269 protected:
270 float mLastVal; ///< last line segment ending value (unscaled and unoffset)
271 float mFrequency; ///< frequency for picking new values
272 float mAmplitude; ///< scale (+-)
273 float mStep; ///< max step between values (+-)
274 float mOffset; ///< DC offset
275 unsigned mCurrentIndex; ///< current index in line segment
276 unsigned mSegmentLength; ///< line segment's length in frames
277 bool mWalk; ///< whether to produce random values or a random walk
278 LineSegment mSegment; ///< single line segment
279
280 void initSegment(); ///< set up the line segment
281 void nextSegment(); ///< choose the values for the next line segment
282
283 };
284
285 }
286
287 #endif