/[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 2207 - (hide annotations) (download) (as text)
Fri Jul 15 15:43:49 2011 UTC (12 years, 8 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 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     /**
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 iliev 2207 * 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 iliev 2205 * 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 iliev 2207 * a parameter which signal source is an envelope
50 iliev 2205 * 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 iliev 2207 SignalUnit* pUnit; /* The source unit whose output signal
62     * will modulate the parameter.
63 iliev 2205 */
64    
65 iliev 2207 float Coeff; // The modulation coefficient
66 iliev 2205
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 iliev 2207 * Calculates the transformation for this parameter
94 iliev 2205 * 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 iliev 2207 * 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 iliev 2205 */
109     virtual float GetValue() {
110 iliev 2207 return pUnit->Active() ? Transform(pUnit->GetLevel()) : 1.0f;
111 iliev 2205 }
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 iliev 2207 /**
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 iliev 2205 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 iliev 2207 cutoff *= GetFilterCutoff();
334     return cutoff > 13500 ? 13500 : cutoff;
335 iliev 2205 }
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