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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 2207 by iliev, Fri Jul 15 15:43:49 2011 UTC revision 2251 by iliev, Sat Aug 20 10:38:31 2011 UTC
# Line 24  Line 24 
24  #define __LS_SIGNALUNIT_H__  #define __LS_SIGNALUNIT_H__
25    
26  #include "../../common/ArrayList.h"  #include "../../common/ArrayList.h"
27    #include "../../common/Pool.h"
28    
29    
30  namespace LinuxSampler {  namespace LinuxSampler {
31    
32        template<typename T>
33        class FixedArray {
34            public:
35                FixedArray(int capacity) {
36                    iSize = 0;
37                    iCapacity = capacity;
38                    pData = new T[iCapacity];
39                }
40                
41                ~FixedArray() {
42                    delete[] pData;
43                    pData = NULL;
44                }
45                
46                inline int size() const { return iSize; }
47                inline int capacity() { return iCapacity; }
48                
49                void add(T element) {
50                    if (iSize >= iCapacity) throw Exception("Array out of bounds");
51                    pData[iSize++] = element;
52                }
53                
54                
55                T& increment() {
56                    if (iSize >= iCapacity) throw Exception("Array out of bounds");
57                    return pData[iSize++];
58                }
59                
60                void clear() { iSize = 0; }
61                
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,       * A signal unit consist of internal signal generator (like envelope generator,
82       * low frequency oscillator, etc) with a number of generator parameters which       * low frequency oscillator, etc) with a number of generator parameters which
# Line 81  namespace LinuxSampler { Line 130  namespace LinuxSampler {
130                  Parameter(const Parameter& Prm) { Copy(Prm); }                  Parameter(const Parameter& Prm) { Copy(Prm); }
131                  void operator=(const Parameter& Prm) { Copy(Prm); }                  void operator=(const Parameter& Prm) { Copy(Prm); }
132                            
133                  virtual void Copy(const Parameter& Prm) {                  void Copy(const Parameter& Prm) {
134                      if (this == &Prm) return;                      if (this == &Prm) return;
135    
136                      pUnit = Prm.pUnit;                      pUnit = Prm.pUnit;
# Line 115  namespace LinuxSampler { Line 164  namespace LinuxSampler {
164          public:          public:
165              ArrayList<SignalUnit::Parameter> Params; // The list of parameters which are modulating the signal unit              ArrayList<SignalUnit::Parameter> Params; // The list of parameters which are modulating the signal unit
166                            
167              SignalUnit() : bActive(false), Level(0.0f), bCalculating(false), uiDelayTrigger(0) { }              SignalUnit(SignalUnitRack* rack): pRack(rack), bActive(false), Level(0.0f), bRecalculate(true), bCalculating(false), uiDelayTrigger(0) { }
168              SignalUnit(const SignalUnit& Unit) { Copy(Unit); }              SignalUnit(const SignalUnit& Unit): pRack(Unit.pRack) { Copy(Unit); }
169              void operator=(const SignalUnit& Unit) { Copy(Unit); }              void operator=(const SignalUnit& Unit) { Copy(Unit); }
170                virtual ~SignalUnit() { }
171                            
172              virtual void Copy(const SignalUnit& Unit) {              void Copy(const SignalUnit& Unit) {
173                  if (this == &Unit) return;                  if (this == &Unit) return;
174    
175                  bActive = Unit.bActive;                  bActive = Unit.bActive;
# Line 154  namespace LinuxSampler { Line 204  namespace LinuxSampler {
204               * the parameters, their levels are calculated too.               * the parameters, their levels are calculated too.
205               */               */
206              virtual float GetLevel() {              virtual float GetLevel() {
207                  if (!bRecalculate) return Level;                  if (Params.empty() || !bRecalculate) return Level;
208    
209                  if (bCalculating) {                  if (bCalculating) {
210                      std::cerr << "SignalUnit: Loop detected. Aborted!";                      std::cerr << "SignalUnit: Loop detected. Aborted!";
# Line 200  namespace LinuxSampler { Line 250  namespace LinuxSampler {
250               */               */
251              virtual uint DelayTrigger() { return uiDelayTrigger; }              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:          protected:
260                SignalUnitRack* const pRack;
261    
262              bool   bActive; /* Don't use it to check the active state of the unit!!!              bool   bActive; /* Don't use it to check the active state of the unit!!!
263                               * Use Active() instead! */                               * Use Active() instead! */
264              float  Level;              float  Level;
# Line 213  namespace LinuxSampler { Line 271  namespace LinuxSampler {
271                    
272      };      };
273            
274      class EndpointSignalUnit: virtual public SignalUnit {      class EndpointSignalUnit: public SignalUnit {
275          public:          public:
276                EndpointSignalUnit(SignalUnitRack* rack): SignalUnit(rack) { }
277    
278              /**              /**
279               * Gets the volume modulation value               * Gets the volume modulation value
280               * for the current time step (sample point).               * for the current time step (sample point).
# Line 239  namespace LinuxSampler { Line 299  namespace LinuxSampler {
299               */               */
300              virtual float GetResonance() = 0;              virtual float GetResonance() = 0;
301                            
302              virtual float CalculateFilterCutoff(float cutoff) = 0;              /** Should return value in the range [-100, 100] (L <-> R) */
303                virtual float GetPan() = 0;
304                            
305              virtual float CalculatePitch(float pitch) = 0;              virtual float CalculateFilterCutoff(float cutoff) {
306                    cutoff *= GetFilterCutoff();
307                    return cutoff > 13500 ? 13500 : cutoff;
308                }
309                            
310              virtual float CalculateResonance(float res) = 0;              virtual float CalculatePitch(float pitch) {
311      };                  return GetPitch() * pitch;
312                    }
   
     class SignalUnitRack;  
   
     template <class O /* The signal unit's owner */>  
     class SignalUnitBase: virtual public SignalUnit {  
         public:  
             SignalUnitBase() : pOwner(NULL) { }  
             SignalUnitBase(const SignalUnitBase& Unit) { Copy(Unit); }  
             void operator=(const SignalUnitBase& Unit) { Copy(Unit); }  
313                            
314              virtual void Copy(const SignalUnitBase& Unit) {              virtual float CalculateResonance(float res) {
315                  if (this == &Unit) return;                  return GetResonance() * res;
   
                 pOwner = Unit.pOwner;  
                 SignalUnit::Copy(Unit);  
316              }              }
317                
318                /** Should return value in the range [0, 127] (L <-> R) */
319                virtual uint8_t CaluclatePan(uint8_t 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        /**
328         * Used to smooth out the parameter changes.
329         */
330        class Smoother {
331          protected:          protected:
332              O* pOwner; // The owner to which this rack belongs.              uint    timeSteps; // The number of time steps to reach the goal
333                uint    currentTimeStep;
334                uint8_t goal; // 0 - 127
335                uint8_t prev; // 0 - 127
336                            
             SignalUnitRack* GetSignalUnitRack() { return pOwner->GetSignalUnitRack(); }  
           
337          public:          public:
338                            /**
339                 *
340                 * @param time The time (in seconds) to reach the goal
341                 * @param sampleRate
342                 * @param val The initial value
343                 */
344                void trigger(float time, float sampleRate, uint8_t val = 0) {
345                    currentTimeStep = timeSteps = time * sampleRate;
346                    prev = goal = val;
347                }
348                            
349              /**              /**
350               * The owner of the unit is set by the rack               * Set the current value, which the smoother will not smooth out.
351               * just before the call to the unit's trigger method.               * If you want the value to be smoothen out, use update() instead.
352               */               */
353              void SetOwner(O* Owner) { pOwner = Owner; }              void setValue( uint8_t val) {
354                    currentTimeStep = timeSteps;
355                    prev = goal = val;
356                }
357                            
358              /**              /**
359               * A helper method which checks whether the delay               * Sets a new value. The render function will return
360               * stage is finished.               * values gradually approaching this value.
361               */               */
362              bool DelayStage() {              void update(uint8_t val) {
363                  return (DelayTrigger() >= GetSignalUnitRack()->GetCurrentStep());                  if (val == goal) return;
364                    
365                    prev = prev + (goal - prev) * (currentTimeStep / (float)timeSteps);
366                    goal = val;
367                    currentTimeStep = 0;
368              }              }
369                
370                uint8_t render() {
371                    if (currentTimeStep >= timeSteps) return goal;
372                    return prev + (goal - prev) * (currentTimeStep++ / (float)timeSteps);
373                }
374                
375                bool isSmoothingOut() { return currentTimeStep < timeSteps; }
376      };      };
377            
378      /**      /**
379       * Continuous controller signal unit.       * Continuous controller signal unit.
380       * The level of this unit corresponds to the controller changes       * The level of this unit corresponds to the controllers changes
381       * and is normalized to be in the range from -1 to +1.       * and their influences.
382       */       */
383      template<class O>      class CCSignalUnit: public SignalUnit {
384      class CCSignalUnit: public SignalUnitBase<O> {          public:
385          private:              /** Listener which will be notified when the level of the unit is changed. */
386              uint8_t Ctrl; // The number of the MIDI controller which modulates this signal unit.              class Listener {
387                    public:
388                        virtual void ValueChanged(CCSignalUnit* pUnit) = 0;
389                };
390                
391                class CC {
392                    public:
393                        uint8_t   Controller;  ///< MIDI controller number.
394                        uint8_t   Value;       ///< Controller Value.
395                        short int Curve;       ///< specifies the curve type
396                        float     Influence;
397                        
398                        Smoother* pSmoother;
399                        
400                        CC(uint8_t Controller = 0, float Influence = 0.0f, short int Curve = -1, Smoother* pSmoother = NULL) {
401                            this->Controller = Controller;
402                            this->Value = 0;
403                            this->Curve = Curve;
404                            this->Influence = Influence;
405                            this->pSmoother = pSmoother;
406                        }
407                        
408                        CC(const CC& cc) { Copy(cc); }
409                        void operator=(const CC& cc) { Copy(cc); }
410                        
411                        void Copy(const CC& cc) {
412                            Controller = cc.Controller;
413                            Value = cc.Value;
414                            Influence = cc.Influence;
415                            Curve = cc.Curve;
416                            pSmoother = cc.pSmoother;
417                        }
418                };
419                
420            protected:
421                RTList<CC>* pCtrls; // The MIDI controllers which modulates this signal unit.
422                Listener* pListener;
423                bool hasSmoothCtrls; // determines whether there are smooth controllers (used for optimization)
424                bool isSmoothingOut; // determines whether there is a CC which is in process of smoothing out (used for optimization)
425    
426          public:          public:
427              CCSignalUnit(uint8_t Controller) {              
428                  Ctrl = Controller;              CCSignalUnit(SignalUnitRack* rack, Listener* l = NULL): SignalUnit(rack), pCtrls(NULL) {
429                    pListener = l;
430                    hasSmoothCtrls = isSmoothingOut = false;
431              }              }
432                            
433              CCSignalUnit(const CCSignalUnit& Unit) { Copy(Unit); }              CCSignalUnit(const CCSignalUnit& Unit): SignalUnit(Unit.pRack), pCtrls(NULL) { Copy(Unit); }
434              void operator=(const CCSignalUnit& Unit) { Copy(Unit); }              void operator=(const CCSignalUnit& Unit) { Copy(Unit); }
435                            
436              virtual void Copy(const CCSignalUnit& Unit) {              virtual ~CCSignalUnit() {
437                  SignalUnitBase<O>::Copy(Unit);                  if (pCtrls != NULL) delete pCtrls;
438                  Ctrl = Unit.Ctrl;              }
439                
440                void Copy(const CCSignalUnit& Unit) {
441                    if (pCtrls != NULL) delete pCtrls;
442                    pCtrls = new RTList<CC>(*(Unit.pCtrls));
443                    if (pCtrls->poolIsEmpty() && pCtrls->count() < Unit.pCtrls->count()) {
444                        std::cerr << "Maximum number of CC reached!" << std::endl;
445                    }
446                    
447                    pListener = Unit.pListener;
448                    hasSmoothCtrls = Unit.hasSmoothCtrls;
449                    isSmoothingOut = Unit.isSmoothingOut;
450                    SignalUnit::Copy(Unit);
451                }
452                
453                virtual void InitCCList(Pool<CC>* pCCPool, Pool<Smoother>* pSmootherPool) {
454                    if (pCtrls != NULL) delete pCtrls;
455                    pCtrls = new RTList<CC>(pCCPool);
456              }              }
457                            
458              virtual void Increment() { }              void AddCC(uint8_t Controller, float Influence, short int Curve = -1, Smoother* pSmoother = NULL) {
459                    if(pCtrls->poolIsEmpty()) {
460                        std::cerr << "Maximum number of CC reached!" << std::endl;
461                        return;
462                    }
463                    *(pCtrls->allocAppend()) = CC(Controller, Influence, Curve, pSmoother);
464                    if (pSmoother != NULL) hasSmoothCtrls = true;
465                }
466                
467                virtual void RemoveAllCCs() { pCtrls->clear(); }
468                
469                int GetCCCount() { return pCtrls->count(); }
470                
471                virtual void Increment() {
472                    if (hasSmoothCtrls && isSmoothingOut) Calculate();
473                }
474                
475                virtual void Trigger() {
476                    Calculate();
477                    bActive = Level != 0;
478                }
479                            
480              virtual void ProcessCCEvent(uint8_t Controller, uint8_t Value) {              virtual void ProcessCCEvent(uint8_t Controller, uint8_t Value) {
481                  if (Controller != Ctrl) return;                  bool recalculate = false;
482                                    
483                  // Normalize the value so it belongs to the interval [-1, +1]                  RTList<CC>::Iterator ctrl = pCtrls->first();
484                  SignalUnitBase<O>::Level = 2 * Value;                  RTList<CC>::Iterator end  = pCtrls->end();
485                  SignalUnitBase<O>::Level = SignalUnitBase<O>::Level/127.0f - 1.0f;                  for(; ctrl != end; ++ctrl) {
486                        if (Controller != (*ctrl).Controller) continue;
487                        if ((*ctrl).Value == Value) continue;
488                        (*ctrl).Value = Value;
489                        if ((*ctrl).pSmoother != NULL) (*ctrl).pSmoother->update(Value);
490                        if (!bActive) bActive = true;
491                        recalculate = true;
492                    }
493                                    
494                  if (!SignalUnitBase<O>::bActive) SignalUnitBase<O>::bActive = true;                  if (!(hasSmoothCtrls && isSmoothingOut) && recalculate) Calculate();
             }  
     };  
   
     /**  
      * Endpoint signal unit.  
      */  
     template<class O>  
     class EndpointSignalUnitBase : public SignalUnitBase<O>, public EndpointSignalUnit {  
         public:  
   
             virtual float CalculateFilterCutoff(float cutoff) {  
                 cutoff *= GetFilterCutoff();  
                 return cutoff > 13500 ? 13500 : cutoff;  
495              }              }
496                            
497              virtual float CalculatePitch(float pitch) {              virtual void Calculate() {
498                  return GetPitch() * pitch;                  float l = 0;
499                    isSmoothingOut = false;
500                    RTList<CC>::Iterator ctrl = pCtrls->first();
501                    RTList<CC>::Iterator end  = pCtrls->end();
502                    for(; ctrl != end; ++ctrl) {
503                        if ((*ctrl).pSmoother == NULL) {
504                            l += Normalize((*ctrl).Value, (*ctrl).Curve) * (*ctrl).Influence;
505                        } else {
506                            if ((*ctrl).pSmoother->isSmoothingOut()) isSmoothingOut = true;
507                            l += Normalize((*ctrl).pSmoother->render(), (*ctrl).Curve) * (*ctrl).Influence;
508                        }
509                    }
510                    if (Level != l) {
511                        Level = l;
512                        if (pListener != NULL) pListener->ValueChanged(this);
513                    }
514              }              }
515                            
516              virtual float CalculateResonance(float res) {              virtual float Normalize(uint8_t val, short int curve = -1) {
517                  return GetResonance() * res;                  return val / 127.0f;
518              }              }
519      };      };
520            

Legend:
Removed from v.2207  
changed lines
  Added in v.2251

  ViewVC Help
Powered by ViewVC