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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2218 - (hide 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 iliev 2205 /***************************************************************************
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 iliev 2217 class SignalUnitRack;
32    
33 iliev 2205 /**
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 iliev 2207 * 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 iliev 2205 * 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 iliev 2207 * a parameter which signal source is an envelope
52 iliev 2205 * 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 iliev 2207 SignalUnit* pUnit; /* The source unit whose output signal
64     * will modulate the parameter.
65 iliev 2205 */
66    
67 iliev 2207 float Coeff; // The modulation coefficient
68 iliev 2205
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 iliev 2218 void Copy(const Parameter& Prm) {
87 iliev 2205 if (this == &Prm) return;
88    
89     pUnit = Prm.pUnit;
90     Coeff = Prm.Coeff;
91     }
92    
93    
94     /**
95 iliev 2207 * Calculates the transformation for this parameter
96 iliev 2205 * 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 iliev 2207 * 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 iliev 2205 */
111     virtual float GetValue() {
112 iliev 2207 return pUnit->Active() ? Transform(pUnit->GetLevel()) : 1.0f;
113 iliev 2205 }
114     };
115    
116    
117     public:
118     ArrayList<SignalUnit::Parameter> Params; // The list of parameters which are modulating the signal unit
119    
120 iliev 2217 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 iliev 2205 void operator=(const SignalUnit& Unit) { Copy(Unit); }
123    
124 iliev 2218 void Copy(const SignalUnit& Unit) {
125 iliev 2205 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 iliev 2207 /**
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 iliev 2205 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 iliev 2217 /**
206     * A helper method which checks whether the delay
207     * stage is finished.
208     */
209     bool DelayStage();
210    
211 iliev 2205 protected:
212 iliev 2217 SignalUnitRack* const pRack;
213    
214 iliev 2205 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 iliev 2217 class EndpointSignalUnit: public SignalUnit {
227 iliev 2205 public:
228 iliev 2217 EndpointSignalUnit(SignalUnitRack* rack): SignalUnit(rack) { }
229    
230 iliev 2205 /**
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 iliev 2217 virtual float CalculateFilterCutoff(float cutoff) {
255     cutoff *= GetFilterCutoff();
256     return cutoff > 13500 ? 13500 : cutoff;
257     }
258 iliev 2205
259 iliev 2217 virtual float CalculatePitch(float pitch) {
260     return GetPitch() * pitch;
261 iliev 2205 }
262    
263 iliev 2217 virtual float CalculateResonance(float res) {
264     return GetResonance() * res;
265 iliev 2205 }
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 iliev 2217 class CCSignalUnit: public SignalUnit {
274 iliev 2205 private:
275     uint8_t Ctrl; // The number of the MIDI controller which modulates this signal unit.
276    
277     public:
278 iliev 2217 CCSignalUnit(SignalUnitRack* rack, uint8_t Controller): SignalUnit(rack) {
279 iliev 2205 Ctrl = Controller;
280     }
281    
282 iliev 2218 CCSignalUnit(const CCSignalUnit& Unit): SignalUnit(Unit.pRack) { Copy(Unit); }
283     void operator=(const CCSignalUnit& Unit) { Copy(Unit); }
284 iliev 2205
285 iliev 2218 void Copy(const CCSignalUnit& Unit) {
286 iliev 2205 Ctrl = Unit.Ctrl;
287 iliev 2218 SignalUnit::Copy(Unit);
288 iliev 2205 }
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 iliev 2217 Level = 2 * Value;
297     Level = Level/127.0f - 1.0f;
298 iliev 2205
299 iliev 2217 if (!bActive) bActive = true;
300 iliev 2205 }
301     };
302    
303     } // namespace LinuxSampler
304    
305     #endif /* __LS_SIGNALUNIT_H__ */

  ViewVC Help
Powered by ViewVC