1 /***************************************************************************
2  *                                                                         *
3  *   LinuxSampler - modular, streaming capable sampler                     *
4  *                                                                         *
5  *   Copyright (C) 2011 - 2012 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 #include "../../common/Pool.h"
28 
29 
30 namespace LinuxSampler {
31 
32     template<typename T>
33     class FixedArray {
34         public:
FixedArray(int capacity)35             FixedArray(int capacity) {
36                 iSize = 0;
37                 iCapacity = capacity;
38                 pData = new T[iCapacity];
39             }
40 
~FixedArray()41             ~FixedArray() {
42                 delete[] pData;
43                 pData = NULL;
44             }
45 
size()46             inline int size() const { return iSize; }
capacity()47             inline int capacity() { return iCapacity; }
48 
add(T element)49             void add(T element) {
50                 if (iSize >= iCapacity) throw Exception("Array out of bounds");
51                 pData[iSize++] = element;
52             }
53 
54 
increment()55             T& increment() {
56                 if (iSize >= iCapacity) throw Exception("Array out of bounds");
57                 return pData[iSize++];
58             }
59 
clear()60             void clear() { iSize = 0; }
61 
copy(const FixedArray<T> & array)62             void copy(const FixedArray<T>& array) {
63                 if(array.size() >= capacity()) throw Exception("Not enough space to copy array");
64                 for (int i = 0; i < array.size(); i++) pData[i] = array[i];
65                 iSize = array.size();
66             }
67 
68             inline T& operator[](int idx) const {
69                 return pData[idx];
70             }
71 
72         private:
73             T*   pData;
74             int  iSize;
75             int  iCapacity;
76     };
77 
78     class SignalUnitRack;
79 
80     /**
81      * A signal unit consist of internal signal generator (like envelope generator,
82      * low frequency oscillator, etc) with a number of generator parameters which
83      * influence/modulate/dynamically change the generator's signal in some manner.
84      * Each generator parameter (also called signal unit parameter) can receive
85      * signal from another signal unit and use this signal to dynamically change the
86      * behavior of the signal generator. In turn, the signal of this unit can be fed
87      * to another unit(s) and influence its parameters.
88      */
89     class SignalUnit {
90         public:
91 
92         /**
93          * This class represents a parameter which will influence the signal
94          * unit to which it belongs in certain way.
95          * For example, let's say the signal unit is a low frequency oscillator
96          * with frequency 1Hz. If we want to modulate the LFO to start with 1Hz
97          * and increment its frequency to 5Hz in 1 second, we can add
98          * a parameter which signal source is an envelope
99          * generator with attack time of 1 second and coefficient 4. Thus, the
100          * normalized level of the EG will move from 0 to 1 in one second.
101          * On every time step (sample point) the normalized level
102          * will be multiplied by 4 (the parameter coefficient) and added to the
103          * LFO's frequency.
104          * So, after 1 second, the LFO frequency will be 1x4 + 1 = 5Hz.
105          * We can also add another parameter for modulating the LFO's pitch depth
106          * and so on.
107          */
108         class Parameter {
109             public:
110                 SignalUnit* pUnit; /* The source unit whose output signal
111                                     * will modulate the parameter.
112                                     */
113 
114                 float Coeff; // The modulation coefficient
115 
116 
Parameter()117                 Parameter() : pUnit(NULL), Coeff(1) { }
118 
119                 /**
120                  * @param unit The source unit used to influence this parameter.
121                  * @param coeff The coefficient by which the normalized signal
122                  * received from the source unit should be multiplied when a
123                  * default transformation is done.
124                  */
125                 Parameter(SignalUnit* unit, float coeff = 1) {
126                     pUnit = unit;
127                     Coeff = coeff;
128                 }
129 
Parameter(const Parameter & Prm)130                 Parameter(const Parameter& Prm) { Copy(Prm); }
131                 void operator=(const Parameter& Prm) { Copy(Prm); }
132 
Copy(const Parameter & Prm)133                 void Copy(const Parameter& Prm) {
134                     if (this == &Prm) return;
135 
136                     pUnit = Prm.pUnit;
137                     Coeff = Prm.Coeff;
138                 }
139 
140 
141                 /**
142                  * Calculates the transformation for this parameter
143                  * which should be applied to the parameter's value
144                  * and multiplies by Coeff.
145                  * This implementation of the method just multiplies by Coeff.
146                  */
Transform(float val)147                 virtual float Transform(float val) {
148                     return val * Coeff;
149                 }
150 
151                 /**
152                  * Gets the current value of the parameter.
153                  * This implementation returns the current signal level of the
154                  * source unit with applied transformation if the source unit is
155                  * active, otherwise returns 1.
156                  * Note that this method assume that pUnit is not NULL.
157                  */
GetValue()158                 virtual float GetValue() {
159                     return pUnit->Active() ? Transform(pUnit->GetLevel()) : 1.0f;
160                 }
161         };
162 
163 
164         public:
165             ArrayList<SignalUnit::Parameter> Params; // The list of parameters which are modulating the signal unit
166 
SignalUnit(SignalUnitRack * rack)167             SignalUnit(SignalUnitRack* rack): pRack(rack), bActive(false), Level(0.0f), bRecalculate(true), bCalculating(false), uiDelayTrigger(0) { }
SignalUnit(const SignalUnit & Unit)168             SignalUnit(const SignalUnit& Unit): pRack(Unit.pRack) { Copy(Unit); }
169             void operator=(const SignalUnit& Unit) { Copy(Unit); }
~SignalUnit()170             virtual ~SignalUnit() { }
171 
Copy(const SignalUnit & Unit)172             void Copy(const SignalUnit& Unit) {
173                 if (this == &Unit) return;
174 
175                 bActive = Unit.bActive;
176                 Level   = Unit.Level;
177                 Params  = Unit.Params;
178                 uiDelayTrigger = Unit.uiDelayTrigger;
179                 bCalculating = false;
180             }
181 
182             /*
183              * Determines whether the unit is active.
184              * If the unit is not active, its level should be ignored.
185              * For endpoint unit this method determines whether
186              * the rendering should be stopped.
187              */
Active()188             virtual bool Active() { return bActive; }
189 
190             /**
191              * Override this method to process the current control change events.
192              * @param itEvent - iterator pointing to the event to be processed.
193              */
ProcessCCEvent(uint8_t Controller,uint8_t Value)194             virtual void ProcessCCEvent(uint8_t Controller, uint8_t Value) { }
195 
EnterReleaseStage()196             virtual void EnterReleaseStage() { }
197 
CancelRelease()198             virtual void CancelRelease() { }
199 
200             /**
201              * Gets the normalized level of the unit for the current
202              * time step (sample point). The level is calculated if it's not
203              * calculated for the current step yet. Because the level depends on
204              * the parameters, their levels are calculated too.
205              */
GetLevel()206             virtual float GetLevel() {
207                 if (Params.empty() || !bRecalculate) return Level;
208 
209                 if (bCalculating) {
210                     std::cerr << "SignalUnit: Loop detected. Aborted!";
211                     return Level;
212                 }
213 
214                 bCalculating = true;
215 
216                 for(int i = 0; i < Params.size(); i++) {
217                     Params[i].GetValue();
218                 }
219 
220                 bRecalculate = bCalculating = false;
221                 return Level;
222             }
223 
224             /**
225              * Will be called to increment the time with one sample point.
226              * The unit should recalculate or prepare for recalculation
227              * its current level on every call of this function.
228              * Note that it is not known whether all source signal unit's levels
229              * are recalculated before the call of this method. So, the calculations
230              * that depends on the unit's parameters should be postponed to
231              * the call of GetLevel().
232              */
Increment()233             virtual void Increment() { bRecalculate = true; }
234 
235             /**
236              * Initializes and triggers the unit.
237              * Note that when a voice is the owner of a unit rack, all settings
238              * should be reset when this method is called, because the sampler
239              * is reusing the voice objects.
240              */
241             virtual void Trigger() = 0;
242 
243             /**
244              * When the signal unit rack is triggered, it triggers all signal
245              * units it holds. If for some reason the triggering of a unit
246              * should be delayed, this method can be set to return non-zero value
247              * specifying the delay in time steps.
248              * Note that this is only a helper method and the implementation
249              * should be done manually.
250              */
DelayTrigger()251             virtual uint DelayTrigger() { return uiDelayTrigger; }
252 
253             /**
254              * A helper method which checks whether the delay
255              * stage is finished.
256              */
257             bool DelayStage();
258 
259         protected:
260             SignalUnitRack* const pRack;
261 
262             bool   bActive; /* Don't use it to check the active state of the unit!!!
263                              * Use Active() instead! */
264             float  Level;
265             bool   bRecalculate; /* Determines whether the unit's level should be recalculated. */
266             bool   bCalculating; /* Determines whether the unit is in process of calculating
267                                   * its level. Used for preventing infinite loops.
268                                   */
269 
270             uint   uiDelayTrigger; /* in time steps */
271 
272     };
273 
274     class EndpointSignalUnit: public SignalUnit {
275         public:
EndpointSignalUnit(SignalUnitRack * rack)276             EndpointSignalUnit(SignalUnitRack* rack): SignalUnit(rack) { }
277 
278             /**
279              * Gets the volume modulation value
280              * for the current time step (sample point).
281              */
282             virtual float GetVolume() = 0;
283 
284             /**
285              * Gets the filter cutoff frequency modulation value
286              * for the current time step (sample point).
287              */
288             virtual float GetFilterCutoff() = 0;
289 
290             /**
291              * Gets the pitch modulation value
292              * for the current time step (sample point).
293              */
294             virtual float GetPitch() = 0;
295 
296             /**
297              * Gets the resonance modulation value
298              * for the current time step (sample point).
299              */
300             virtual float GetResonance() = 0;
301 
302             /** Should return value in the range [-100, 100] (L <-> R) */
303             virtual float GetPan() = 0;
304 
CalculateFilterCutoff(float cutoff)305             virtual float CalculateFilterCutoff(float cutoff) {
306                 cutoff *= GetFilterCutoff();
307                 return cutoff > 13500 ? 13500 : cutoff;
308             }
309 
CalculatePitch(float pitch)310             virtual float CalculatePitch(float pitch) {
311                 return GetPitch() * pitch;
312             }
313 
CalculateResonance(float res)314             virtual float CalculateResonance(float res) {
315                 return GetResonance() * res;
316             }
317 
318             /** Should return value in the range [0, 127] (L <-> R) */
CalculatePan(int pan)319             virtual uint8_t CalculatePan(int pan) {
320                 int p = pan + GetPan() * 0.63;
321                 if (p < 0) return 0;
322                 if (p > 127) return 127;
323                 return p;
324             }
325 
326             /**
327              * Decreases the delay by Sample time steps.
328              * This method is used to delay the sample playback.
329              * While the endpoint unit is in delay stage the rack is not incremented.
330              */
DecreaseDelay(uint Samples)331             void DecreaseDelay(uint Samples) {
332                 uiDelayTrigger -= Samples;
333             }
334     };
335 
336     /**
337      * Used to smooth out the parameter changes.
338      */
339     class Smoother {
340         protected:
341             uint  timeSteps; // The number of time steps to reach the goal
342             uint  currentTimeStep;
343             float goal;
344             float prev;
345 
346         public:
347             /**
348              *
349              * @param time The time (in seconds) to reach the goal
350              * @param sampleRate
351              * @param val The initial value
352              */
353             void trigger(float time, float sampleRate, float val = 0) {
354                 currentTimeStep = timeSteps = time * sampleRate;
355                 prev = goal = val;
356             }
357 
358             /**
359              * Set the current value, which the smoother will not smooth out.
360              * If you want the value to be smoothen out, use update() instead.
361              */
setValue(float val)362             void setValue( float val) {
363                 currentTimeStep = timeSteps;
364                 prev = goal = val;
365             }
366 
367             /**
368              * Sets a new value. The render function will return
369              * values gradually approaching this value.
370              */
update(float val)371             void update(float val) {
372                 if (val == goal) return;
373 
374                 prev = prev + (goal - prev) * (currentTimeStep / (float)timeSteps);
375                 goal = val;
376                 currentTimeStep = 0;
377             }
378 
render()379             float render() {
380                 if (currentTimeStep >= timeSteps) return goal;
381                 return prev + (goal - prev) * (currentTimeStep++ / (float)timeSteps);
382             }
383 
isSmoothingOut()384             bool isSmoothingOut() { return currentTimeStep < timeSteps; }
385 
getGoal()386             float getGoal() { return goal; }
387     };
388 
389     /**
390      * Continuous controller signal unit.
391      * The level of this unit corresponds to the controllers changes
392      * and their influences.
393      */
394     class CCSignalUnit: public SignalUnit {
395         public:
396             /** Listener which will be notified when the level of the unit is changed. */
397             class Listener {
398                 public:
399                     virtual void ValueChanged(CCSignalUnit* pUnit) = 0;
400             };
401 
402             class CC {
403                 public:
404                     uint8_t   Controller;  ///< MIDI controller number.
405                     uint8_t   Value;       ///< Controller Value.
406                     short int Curve;       ///< specifies the curve type
407                     float     Influence;
408                     float     Step;
409 
410                     Smoother* pSmoother;
411 
412                     CC (
413                         uint8_t   Controller = 0,
414                         float     Influence  = 0.0f,
415                         short int Curve      = -1,
416                         Smoother* pSmoother  = NULL,
417                         float     Step       = 0
418                     ) {
419                         this->Controller = Controller;
420                         this->Value = 0;
421                         this->Curve = Curve;
422                         this->Influence = Influence;
423                         this->pSmoother = pSmoother;
424                         this->Step  = Step;
425                     }
426 
CC(const CC & cc)427                     CC(const CC& cc) { Copy(cc); }
428                     void operator=(const CC& cc) { Copy(cc); }
429 
Copy(const CC & cc)430                     void Copy(const CC& cc) {
431                         Controller = cc.Controller;
432                         Value      = cc.Value;
433                         Influence  = cc.Influence;
434                         Curve      = cc.Curve;
435                         pSmoother  = cc.pSmoother;
436                         Step       = cc.Step;
437                     }
438             };
439 
440         protected:
441             RTList<CC>* pCtrls; // The MIDI controllers which modulates this signal unit.
442             Listener* pListener;
443             bool hasSmoothCtrls; // determines whether there are smooth controllers (used for optimization)
444             bool isSmoothingOut; // determines whether there is a CC which is in process of smoothing out (used for optimization)
445 
446         public:
447 
SignalUnit(rack)448             CCSignalUnit(SignalUnitRack* rack, Listener* l = NULL): SignalUnit(rack), pCtrls(NULL) {
449                 pListener = l;
450                 hasSmoothCtrls = isSmoothingOut = false;
451             }
452 
CCSignalUnit(const CCSignalUnit & Unit)453             CCSignalUnit(const CCSignalUnit& Unit): SignalUnit(Unit.pRack), pCtrls(NULL) { Copy(Unit); }
454             void operator=(const CCSignalUnit& Unit) { Copy(Unit); }
455 
~CCSignalUnit()456             virtual ~CCSignalUnit() {
457                 if (pCtrls != NULL) delete pCtrls;
458             }
459 
Copy(const CCSignalUnit & Unit)460             void Copy(const CCSignalUnit& Unit) {
461                 if (pCtrls != NULL) delete pCtrls;
462                 pCtrls = new RTList<CC>(*(Unit.pCtrls));
463                 if (pCtrls->poolIsEmpty() && pCtrls->count() < Unit.pCtrls->count()) {
464                     std::cerr << "Maximum number of CC reached!" << std::endl;
465                 }
466 
467                 pListener = Unit.pListener;
468                 hasSmoothCtrls = Unit.hasSmoothCtrls;
469                 isSmoothingOut = Unit.isSmoothingOut;
470                 SignalUnit::Copy(Unit);
471             }
472 
InitCCList(Pool<CC> * pCCPool,Pool<Smoother> * pSmootherPool)473             virtual void InitCCList(Pool<CC>* pCCPool, Pool<Smoother>* pSmootherPool) {
474                 if (pCtrls != NULL) delete pCtrls;
475                 pCtrls = new RTList<CC>(pCCPool);
476             }
477 
478             void AddCC(uint8_t Controller, float Influence, short int Curve = -1, Smoother* pSmoother = NULL, float Step = 0) {
479                 if(pCtrls->poolIsEmpty()) {
480                     std::cerr << "Maximum number of CC reached!" << std::endl;
481                     return;
482                 }
483                 *(pCtrls->allocAppend()) = CC(Controller, Influence, Curve, pSmoother, Step);
484                 if (pSmoother != NULL) hasSmoothCtrls = true;
485             }
486 
RemoveAllCCs()487             virtual void RemoveAllCCs() { pCtrls->clear(); }
488 
GetCCCount()489             int GetCCCount() { return pCtrls->count(); }
490 
HasCCs()491             bool HasCCs() { return GetCCCount() > 0; }
492 
Increment()493             virtual void Increment() {
494                 if (hasSmoothCtrls && isSmoothingOut) Calculate();
495             }
496 
Trigger()497             virtual void Trigger() {
498                 Calculate();
499                 bActive = Level != 0;
500             }
501 
ProcessCCEvent(uint8_t Controller,uint8_t Value)502             virtual void ProcessCCEvent(uint8_t Controller, uint8_t Value) {
503                 bool recalculate = false;
504 
505                 RTList<CC>::Iterator ctrl = pCtrls->first();
506                 RTList<CC>::Iterator end  = pCtrls->end();
507                 for(; ctrl != end; ++ctrl) {
508                     if (Controller != (*ctrl).Controller) continue;
509                     if ((*ctrl).Value == Value) continue;
510 
511                     (*ctrl).Value = Value;
512 
513                     if ((*ctrl).Step > 0 && (*ctrl).pSmoother != NULL) {
514                         float oldGoal = (*ctrl).pSmoother->getGoal();
515                         float newGoal = Normalize(Value, (*ctrl).Curve) * (*ctrl).Influence;
516                         newGoal = ((int) (newGoal / (*ctrl).Step)) * (*ctrl).Step;
517                         if (oldGoal != newGoal) (*ctrl).pSmoother->update(newGoal);
518                     }
519 
520                     if ((*ctrl).pSmoother != NULL && (*ctrl).Step <= 0) (*ctrl).pSmoother->update(Value);
521                     if (!bActive) bActive = true;
522                     recalculate = true;
523                 }
524 
525                 if (!(hasSmoothCtrls && isSmoothingOut) && recalculate) Calculate();
526             }
527 
Calculate()528             virtual void Calculate() {
529                 float l = 0;
530                 isSmoothingOut = false;
531                 RTList<CC>::Iterator ctrl = pCtrls->first();
532                 RTList<CC>::Iterator end  = pCtrls->end();
533                 for(; ctrl != end; ++ctrl) {
534                     if ((*ctrl).pSmoother == NULL) {
535                         float val = Normalize((*ctrl).Value, (*ctrl).Curve) * (*ctrl).Influence;
536                         if ((*ctrl).Step > 0) val = ( (int)(val / (*ctrl).Step) ) * (*ctrl).Step;
537                         l += val;
538                     } else {
539                         if ((*ctrl).pSmoother->isSmoothingOut()) isSmoothingOut = true;
540 
541                         if ((*ctrl).Step > 0) {
542                             l += (*ctrl).pSmoother->render();
543                         } else {
544                             l += Normalize((*ctrl).pSmoother->render(), (*ctrl).Curve) * (*ctrl).Influence;
545                         }
546                     }
547                 }
548                 if (Level != l) {
549                     Level = l;
550                     if (pListener != NULL) pListener->ValueChanged(this);
551                 }
552             }
553 
554             virtual float Normalize(uint8_t val, short int curve = -1) {
555                 return val / 127.0f;
556             }
557     };
558 
559 } // namespace LinuxSampler
560 
561 #endif	/* __LS_SIGNALUNIT_H__ */
562