/[svn]/linuxsampler/trunk/src/engines/common/SignalUnit.h
ViewVC logotype

Contents of /linuxsampler/trunk/src/engines/common/SignalUnit.h

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2207 - (show annotations) (download) (as text)
Fri Jul 15 15:43:49 2011 UTC (12 years, 9 months ago) by iliev
File MIME type: text/x-c++hdr
File size: 14228 byte(s)
* simplified the signal unit model
* sf2: initial implementation of modulation LFO and cutoff filter

1 /***************************************************************************
2 * *
3 * LinuxSampler - modular, streaming capable sampler *
4 * *
5 * Copyright (C) 2011 Grigor Iliev *
6 * *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program; if not, write to the Free Software *
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
20 * MA 02111-1307 USA *
21 ***************************************************************************/
22
23 #ifndef __LS_SIGNALUNIT_H__
24 #define __LS_SIGNALUNIT_H__
25
26 #include "../../common/ArrayList.h"
27
28
29 namespace LinuxSampler {
30
31 /**
32 * A signal unit consist of internal signal generator (like envelope generator,
33 * low frequency oscillator, etc) with a number of generator parameters which
34 * influence/modulate/dynamically change the generator's signal in some manner.
35 * Each generator parameter (also called signal unit parameter) can receive
36 * signal from another signal unit and use this signal to dynamically change the
37 * behavior of the signal generator. In turn, the signal of this unit can be fed
38 * to another unit(s) and influence its parameters.
39 */
40 class SignalUnit {
41 public:
42
43 /**
44 * This class represents a parameter which will influence the signal
45 * unit to which it belongs in certain way.
46 * For example, let's say the signal unit is a low frequency oscillator
47 * with frequency 1Hz. If we want to modulate the LFO to start with 1Hz
48 * and increment its frequency to 5Hz in 1 second, we can add
49 * a parameter which signal source is an envelope
50 * generator with attack time of 1 second and coefficient 4. Thus, the
51 * normalized level of the EG will move from 0 to 1 in one second.
52 * On every time step (sample point) the normalized level
53 * will be multiplied by 4 (the parameter coefficient) and added to the
54 * LFO's frequency.
55 * So, after 1 second, the LFO frequency will be 1x4 + 1 = 5Hz.
56 * We can also add another parameter for modulating the LFO's pitch depth
57 * and so on.
58 */
59 class Parameter {
60 public:
61 SignalUnit* pUnit; /* The source unit whose output signal
62 * will modulate the parameter.
63 */
64
65 float Coeff; // The modulation coefficient
66
67
68 Parameter() : Coeff(1), pUnit(NULL) { }
69
70 /**
71 * @param unit The source unit used to influence this parameter.
72 * @param coeff The coefficient by which the normalized signal
73 * received from the source unit should be multiplied when a
74 * default transformation is done.
75 */
76 Parameter(SignalUnit* unit, float coeff = 1) {
77 pUnit = unit;
78 Coeff = coeff;
79 }
80
81 Parameter(const Parameter& Prm) { Copy(Prm); }
82 void operator=(const Parameter& Prm) { Copy(Prm); }
83
84 virtual void Copy(const Parameter& Prm) {
85 if (this == &Prm) return;
86
87 pUnit = Prm.pUnit;
88 Coeff = Prm.Coeff;
89 }
90
91
92 /**
93 * Calculates the transformation for this parameter
94 * which should be applied to the parameter's value
95 * and multiplies by Coeff.
96 * This implementation of the method just multiplies by Coeff.
97 */
98 virtual float Transform(float val) {
99 return val * Coeff;
100 }
101
102 /**
103 * Gets the current value of the parameter.
104 * This implementation returns the current signal level of the
105 * source unit with applied transformation if the source unit is
106 * active, otherwise returns 1.
107 * Note that this method assume that pUnit is not NULL.
108 */
109 virtual float GetValue() {
110 return pUnit->Active() ? Transform(pUnit->GetLevel()) : 1.0f;
111 }
112 };
113
114
115 public:
116 ArrayList<SignalUnit::Parameter> Params; // The list of parameters which are modulating the signal unit
117
118 SignalUnit() : bActive(false), Level(0.0f), bCalculating(false), uiDelayTrigger(0) { }
119 SignalUnit(const SignalUnit& Unit) { Copy(Unit); }
120 void operator=(const SignalUnit& Unit) { Copy(Unit); }
121
122 virtual void Copy(const SignalUnit& Unit) {
123 if (this == &Unit) return;
124
125 bActive = Unit.bActive;
126 Level = Unit.Level;
127 Params = Unit.Params;
128 uiDelayTrigger = Unit.uiDelayTrigger;
129 bCalculating = false;
130 }
131
132 /*
133 * Determines whether the unit is active.
134 * If the unit is not active, its level should be ignored.
135 * For endpoint unit this method determines whether
136 * the rendering should be stopped.
137 */
138 virtual bool Active() { return bActive; }
139
140 /**
141 * Override this method to process the current control change events.
142 * @param itEvent - iterator pointing to the event to be processed.
143 */
144 virtual void ProcessCCEvent(uint8_t Controller, uint8_t Value) { }
145
146 virtual void EnterReleaseStage() { }
147
148 virtual void CancelRelease() { }
149
150 /**
151 * Gets the normalized level of the unit for the current
152 * time step (sample point). The level is calculated if it's not
153 * calculated for the current step yet. Because the level depends on
154 * the parameters, their levels are calculated too.
155 */
156 virtual float GetLevel() {
157 if (!bRecalculate) return Level;
158
159 if (bCalculating) {
160 std::cerr << "SignalUnit: Loop detected. Aborted!";
161 return Level;
162 }
163
164 bCalculating = true;
165
166 for(int i = 0; i < Params.size(); i++) {
167 Params[i].GetValue();
168 }
169
170 bRecalculate = bCalculating = false;
171 return Level;
172 }
173
174 /**
175 * Will be called to increment the time with one sample point.
176 * The unit should recalculate or prepare for recalculation
177 * its current level on every call of this function.
178 * Note that it is not known whether all source signal unit's levels
179 * are recalculated before the call of this method. So, the calculations
180 * that depends on the unit's parameters should be postponed to
181 * the call of GetLevel().
182 */
183 virtual void Increment() { bRecalculate = true; }
184
185 /**
186 * Initializes and triggers the unit.
187 * Note that when a voice is the owner of a unit rack, all settings
188 * should be reset when this method is called, because the sampler
189 * is reusing the voice objects.
190 */
191 virtual void Trigger() = 0;
192
193 /**
194 * When the signal unit rack is triggered, it triggers all signal
195 * units it holds. If for some reason the triggering of a unit
196 * should be delayed, this method can be set to return non-zero value
197 * specifying the delay in time steps.
198 * Note that this is only a helper method and the implementation
199 * should be done manually.
200 */
201 virtual uint DelayTrigger() { return uiDelayTrigger; }
202
203 protected:
204 bool bActive; /* Don't use it to check the active state of the unit!!!
205 * Use Active() instead! */
206 float Level;
207 bool bRecalculate; /* Determines whether the unit's level should be recalculated. */
208 bool bCalculating; /* Determines whether the unit is in process of calculating
209 * its level. Used for preventing infinite loops.
210 */
211
212 uint uiDelayTrigger; /* in time steps */
213
214 };
215
216 class EndpointSignalUnit: virtual public SignalUnit {
217 public:
218 /**
219 * Gets the volume modulation value
220 * for the current time step (sample point).
221 */
222 virtual float GetVolume() = 0;
223
224 /**
225 * Gets the filter cutoff frequency modulation value
226 * for the current time step (sample point).
227 */
228 virtual float GetFilterCutoff() = 0;
229
230 /**
231 * Gets the pitch modulation value
232 * for the current time step (sample point).
233 */
234 virtual float GetPitch() = 0;
235
236 /**
237 * Gets the resonance modulation value
238 * for the current time step (sample point).
239 */
240 virtual float GetResonance() = 0;
241
242 virtual float CalculateFilterCutoff(float cutoff) = 0;
243
244 virtual float CalculatePitch(float pitch) = 0;
245
246 virtual float CalculateResonance(float res) = 0;
247 };
248
249
250 class SignalUnitRack;
251
252 template <class O /* The signal unit's owner */>
253 class SignalUnitBase: virtual public SignalUnit {
254 public:
255 SignalUnitBase() : pOwner(NULL) { }
256 SignalUnitBase(const SignalUnitBase& Unit) { Copy(Unit); }
257 void operator=(const SignalUnitBase& Unit) { Copy(Unit); }
258
259 virtual void Copy(const SignalUnitBase& Unit) {
260 if (this == &Unit) return;
261
262 pOwner = Unit.pOwner;
263 SignalUnit::Copy(Unit);
264 }
265
266 protected:
267 O* pOwner; // The owner to which this rack belongs.
268
269 SignalUnitRack* GetSignalUnitRack() { return pOwner->GetSignalUnitRack(); }
270
271 public:
272
273
274 /**
275 * The owner of the unit is set by the rack
276 * just before the call to the unit's trigger method.
277 */
278 void SetOwner(O* Owner) { pOwner = Owner; }
279
280 /**
281 * A helper method which checks whether the delay
282 * stage is finished.
283 */
284 bool DelayStage() {
285 return (DelayTrigger() >= GetSignalUnitRack()->GetCurrentStep());
286 }
287 };
288
289 /**
290 * Continuous controller signal unit.
291 * The level of this unit corresponds to the controller changes
292 * and is normalized to be in the range from -1 to +1.
293 */
294 template<class O>
295 class CCSignalUnit: public SignalUnitBase<O> {
296 private:
297 uint8_t Ctrl; // The number of the MIDI controller which modulates this signal unit.
298
299 public:
300 CCSignalUnit(uint8_t Controller) {
301 Ctrl = Controller;
302 }
303
304 CCSignalUnit(const CCSignalUnit& Unit) { Copy(Unit); }
305 void operator=(const CCSignalUnit& Unit) { Copy(Unit); }
306
307 virtual void Copy(const CCSignalUnit& Unit) {
308 SignalUnitBase<O>::Copy(Unit);
309 Ctrl = Unit.Ctrl;
310 }
311
312 virtual void Increment() { }
313
314 virtual void ProcessCCEvent(uint8_t Controller, uint8_t Value) {
315 if (Controller != Ctrl) return;
316
317 // Normalize the value so it belongs to the interval [-1, +1]
318 SignalUnitBase<O>::Level = 2 * Value;
319 SignalUnitBase<O>::Level = SignalUnitBase<O>::Level/127.0f - 1.0f;
320
321 if (!SignalUnitBase<O>::bActive) SignalUnitBase<O>::bActive = true;
322 }
323 };
324
325 /**
326 * Endpoint signal unit.
327 */
328 template<class O>
329 class EndpointSignalUnitBase : public SignalUnitBase<O>, public EndpointSignalUnit {
330 public:
331
332 virtual float CalculateFilterCutoff(float cutoff) {
333 cutoff *= GetFilterCutoff();
334 return cutoff > 13500 ? 13500 : cutoff;
335 }
336
337 virtual float CalculatePitch(float pitch) {
338 return GetPitch() * pitch;
339 }
340
341 virtual float CalculateResonance(float res) {
342 return GetResonance() * res;
343 }
344 };
345
346 } // namespace LinuxSampler
347
348 #endif /* __LS_SIGNALUNIT_H__ */

  ViewVC Help
Powered by ViewVC