/[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 2218 - (show annotations) (download) (as text)
Thu Jul 28 08:05:57 2011 UTC (12 years, 8 months ago) by iliev
File MIME type: text/x-c++hdr
File size: 12826 byte(s)
* sfz engine: use the newly introduced signal units model

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 class SignalUnitRack;
32
33 /**
34 * A signal unit consist of internal signal generator (like envelope generator,
35 * low frequency oscillator, etc) with a number of generator parameters which
36 * influence/modulate/dynamically change the generator's signal in some manner.
37 * Each generator parameter (also called signal unit parameter) can receive
38 * signal from another signal unit and use this signal to dynamically change the
39 * behavior of the signal generator. In turn, the signal of this unit can be fed
40 * to another unit(s) and influence its parameters.
41 */
42 class SignalUnit {
43 public:
44
45 /**
46 * This class represents a parameter which will influence the signal
47 * unit to which it belongs in certain way.
48 * For example, let's say the signal unit is a low frequency oscillator
49 * with frequency 1Hz. If we want to modulate the LFO to start with 1Hz
50 * and increment its frequency to 5Hz in 1 second, we can add
51 * a parameter which signal source is an envelope
52 * generator with attack time of 1 second and coefficient 4. Thus, the
53 * normalized level of the EG will move from 0 to 1 in one second.
54 * On every time step (sample point) the normalized level
55 * will be multiplied by 4 (the parameter coefficient) and added to the
56 * LFO's frequency.
57 * So, after 1 second, the LFO frequency will be 1x4 + 1 = 5Hz.
58 * We can also add another parameter for modulating the LFO's pitch depth
59 * and so on.
60 */
61 class Parameter {
62 public:
63 SignalUnit* pUnit; /* The source unit whose output signal
64 * will modulate the parameter.
65 */
66
67 float Coeff; // The modulation coefficient
68
69
70 Parameter() : Coeff(1), pUnit(NULL) { }
71
72 /**
73 * @param unit The source unit used to influence this parameter.
74 * @param coeff The coefficient by which the normalized signal
75 * received from the source unit should be multiplied when a
76 * default transformation is done.
77 */
78 Parameter(SignalUnit* unit, float coeff = 1) {
79 pUnit = unit;
80 Coeff = coeff;
81 }
82
83 Parameter(const Parameter& Prm) { Copy(Prm); }
84 void operator=(const Parameter& Prm) { Copy(Prm); }
85
86 void Copy(const Parameter& Prm) {
87 if (this == &Prm) return;
88
89 pUnit = Prm.pUnit;
90 Coeff = Prm.Coeff;
91 }
92
93
94 /**
95 * Calculates the transformation for this parameter
96 * which should be applied to the parameter's value
97 * and multiplies by Coeff.
98 * This implementation of the method just multiplies by Coeff.
99 */
100 virtual float Transform(float val) {
101 return val * Coeff;
102 }
103
104 /**
105 * Gets the current value of the parameter.
106 * This implementation returns the current signal level of the
107 * source unit with applied transformation if the source unit is
108 * active, otherwise returns 1.
109 * Note that this method assume that pUnit is not NULL.
110 */
111 virtual float GetValue() {
112 return pUnit->Active() ? Transform(pUnit->GetLevel()) : 1.0f;
113 }
114 };
115
116
117 public:
118 ArrayList<SignalUnit::Parameter> Params; // The list of parameters which are modulating the signal unit
119
120 SignalUnit(SignalUnitRack* rack): pRack(rack), bActive(false), Level(0.0f), bCalculating(false), uiDelayTrigger(0) { }
121 SignalUnit(const SignalUnit& Unit): pRack(Unit.pRack) { Copy(Unit); }
122 void operator=(const SignalUnit& Unit) { Copy(Unit); }
123
124 void Copy(const SignalUnit& Unit) {
125 if (this == &Unit) return;
126
127 bActive = Unit.bActive;
128 Level = Unit.Level;
129 Params = Unit.Params;
130 uiDelayTrigger = Unit.uiDelayTrigger;
131 bCalculating = false;
132 }
133
134 /*
135 * Determines whether the unit is active.
136 * If the unit is not active, its level should be ignored.
137 * For endpoint unit this method determines whether
138 * the rendering should be stopped.
139 */
140 virtual bool Active() { return bActive; }
141
142 /**
143 * Override this method to process the current control change events.
144 * @param itEvent - iterator pointing to the event to be processed.
145 */
146 virtual void ProcessCCEvent(uint8_t Controller, uint8_t Value) { }
147
148 virtual void EnterReleaseStage() { }
149
150 virtual void CancelRelease() { }
151
152 /**
153 * Gets the normalized level of the unit for the current
154 * time step (sample point). The level is calculated if it's not
155 * calculated for the current step yet. Because the level depends on
156 * the parameters, their levels are calculated too.
157 */
158 virtual float GetLevel() {
159 if (!bRecalculate) return Level;
160
161 if (bCalculating) {
162 std::cerr << "SignalUnit: Loop detected. Aborted!";
163 return Level;
164 }
165
166 bCalculating = true;
167
168 for(int i = 0; i < Params.size(); i++) {
169 Params[i].GetValue();
170 }
171
172 bRecalculate = bCalculating = false;
173 return Level;
174 }
175
176 /**
177 * Will be called to increment the time with one sample point.
178 * The unit should recalculate or prepare for recalculation
179 * its current level on every call of this function.
180 * Note that it is not known whether all source signal unit's levels
181 * are recalculated before the call of this method. So, the calculations
182 * that depends on the unit's parameters should be postponed to
183 * the call of GetLevel().
184 */
185 virtual void Increment() { bRecalculate = true; }
186
187 /**
188 * Initializes and triggers the unit.
189 * Note that when a voice is the owner of a unit rack, all settings
190 * should be reset when this method is called, because the sampler
191 * is reusing the voice objects.
192 */
193 virtual void Trigger() = 0;
194
195 /**
196 * When the signal unit rack is triggered, it triggers all signal
197 * units it holds. If for some reason the triggering of a unit
198 * should be delayed, this method can be set to return non-zero value
199 * specifying the delay in time steps.
200 * Note that this is only a helper method and the implementation
201 * should be done manually.
202 */
203 virtual uint DelayTrigger() { return uiDelayTrigger; }
204
205 /**
206 * A helper method which checks whether the delay
207 * stage is finished.
208 */
209 bool DelayStage();
210
211 protected:
212 SignalUnitRack* const pRack;
213
214 bool bActive; /* Don't use it to check the active state of the unit!!!
215 * Use Active() instead! */
216 float Level;
217 bool bRecalculate; /* Determines whether the unit's level should be recalculated. */
218 bool bCalculating; /* Determines whether the unit is in process of calculating
219 * its level. Used for preventing infinite loops.
220 */
221
222 uint uiDelayTrigger; /* in time steps */
223
224 };
225
226 class EndpointSignalUnit: public SignalUnit {
227 public:
228 EndpointSignalUnit(SignalUnitRack* rack): SignalUnit(rack) { }
229
230 /**
231 * Gets the volume modulation value
232 * for the current time step (sample point).
233 */
234 virtual float GetVolume() = 0;
235
236 /**
237 * Gets the filter cutoff frequency modulation value
238 * for the current time step (sample point).
239 */
240 virtual float GetFilterCutoff() = 0;
241
242 /**
243 * Gets the pitch modulation value
244 * for the current time step (sample point).
245 */
246 virtual float GetPitch() = 0;
247
248 /**
249 * Gets the resonance modulation value
250 * for the current time step (sample point).
251 */
252 virtual float GetResonance() = 0;
253
254 virtual float CalculateFilterCutoff(float cutoff) {
255 cutoff *= GetFilterCutoff();
256 return cutoff > 13500 ? 13500 : cutoff;
257 }
258
259 virtual float CalculatePitch(float pitch) {
260 return GetPitch() * pitch;
261 }
262
263 virtual float CalculateResonance(float res) {
264 return GetResonance() * res;
265 }
266 };
267
268 /**
269 * Continuous controller signal unit.
270 * The level of this unit corresponds to the controller changes
271 * and is normalized to be in the range from -1 to +1.
272 */
273 class CCSignalUnit: public SignalUnit {
274 private:
275 uint8_t Ctrl; // The number of the MIDI controller which modulates this signal unit.
276
277 public:
278 CCSignalUnit(SignalUnitRack* rack, uint8_t Controller): SignalUnit(rack) {
279 Ctrl = Controller;
280 }
281
282 CCSignalUnit(const CCSignalUnit& Unit): SignalUnit(Unit.pRack) { Copy(Unit); }
283 void operator=(const CCSignalUnit& Unit) { Copy(Unit); }
284
285 void Copy(const CCSignalUnit& Unit) {
286 Ctrl = Unit.Ctrl;
287 SignalUnit::Copy(Unit);
288 }
289
290 virtual void Increment() { }
291
292 virtual void ProcessCCEvent(uint8_t Controller, uint8_t Value) {
293 if (Controller != Ctrl) return;
294
295 // Normalize the value so it belongs to the interval [-1, +1]
296 Level = 2 * Value;
297 Level = Level/127.0f - 1.0f;
298
299 if (!bActive) bActive = true;
300 }
301 };
302
303 } // namespace LinuxSampler
304
305 #endif /* __LS_SIGNALUNIT_H__ */

  ViewVC Help
Powered by ViewVC