--- linuxsampler/trunk/src/engines/common/SignalUnit.h 2011/07/15 15:43:49 2207 +++ linuxsampler/trunk/src/engines/common/SignalUnit.h 2011/08/05 17:59:10 2230 @@ -28,6 +28,54 @@ namespace LinuxSampler { + template + class FixedArray { + public: + FixedArray(int capacity) { + iSize = 0; + iCapacity = capacity; + pData = new T[iCapacity]; + } + + ~FixedArray() { + delete pData; + pData = NULL; + } + + inline int size() const { return iSize; } + inline int capacity() { return iCapacity; } + + void add(T element) { + if (iSize >= iCapacity) throw Exception("Array out of bounds"); + pData[iSize++] = element; + } + + + T increment() { + if (iSize >= iCapacity) throw Exception("Array out of bounds"); + return pData[iSize++]; + } + + void clear() { iSize = 0; } + + void copy(const FixedArray& array) { + if(array.size() >= capacity()) throw Exception("Not enough space to copy array"); + for (int i = 0; i < array.size(); i++) pData[i] = array[i]; + iSize = array.size(); + } + + inline T& operator[](int idx) const { + return pData[idx]; + } + + private: + T* pData; + int iSize; + int iCapacity; + }; + + class SignalUnitRack; + /** * A signal unit consist of internal signal generator (like envelope generator, * low frequency oscillator, etc) with a number of generator parameters which @@ -81,7 +129,7 @@ Parameter(const Parameter& Prm) { Copy(Prm); } void operator=(const Parameter& Prm) { Copy(Prm); } - virtual void Copy(const Parameter& Prm) { + void Copy(const Parameter& Prm) { if (this == &Prm) return; pUnit = Prm.pUnit; @@ -115,11 +163,11 @@ public: ArrayList Params; // The list of parameters which are modulating the signal unit - SignalUnit() : bActive(false), Level(0.0f), bCalculating(false), uiDelayTrigger(0) { } - SignalUnit(const SignalUnit& Unit) { Copy(Unit); } + SignalUnit(SignalUnitRack* rack): pRack(rack), bActive(false), Level(0.0f), bCalculating(false), uiDelayTrigger(0) { } + SignalUnit(const SignalUnit& Unit): pRack(Unit.pRack) { Copy(Unit); } void operator=(const SignalUnit& Unit) { Copy(Unit); } - virtual void Copy(const SignalUnit& Unit) { + void Copy(const SignalUnit& Unit) { if (this == &Unit) return; bActive = Unit.bActive; @@ -200,7 +248,15 @@ */ virtual uint DelayTrigger() { return uiDelayTrigger; } + /** + * A helper method which checks whether the delay + * stage is finished. + */ + bool DelayStage(); + protected: + SignalUnitRack* const pRack; + bool bActive; /* Don't use it to check the active state of the unit!!! * Use Active() instead! */ float Level; @@ -213,8 +269,10 @@ }; - class EndpointSignalUnit: virtual public SignalUnit { + class EndpointSignalUnit: public SignalUnit { public: + EndpointSignalUnit(SignalUnitRack* rack): SignalUnit(rack) { } + /** * Gets the volume modulation value * for the current time step (sample point). @@ -239,107 +297,126 @@ */ virtual float GetResonance() = 0; - virtual float CalculateFilterCutoff(float cutoff) = 0; - - virtual float CalculatePitch(float pitch) = 0; + /** Should return value in the range [-100, 100] (L <-> R) */ + virtual float GetPan() = 0; - virtual float CalculateResonance(float res) = 0; - }; - - - class SignalUnitRack; - - template - class SignalUnitBase: virtual public SignalUnit { - public: - SignalUnitBase() : pOwner(NULL) { } - SignalUnitBase(const SignalUnitBase& Unit) { Copy(Unit); } - void operator=(const SignalUnitBase& Unit) { Copy(Unit); } - - virtual void Copy(const SignalUnitBase& Unit) { - if (this == &Unit) return; - - pOwner = Unit.pOwner; - SignalUnit::Copy(Unit); + virtual float CalculateFilterCutoff(float cutoff) { + cutoff *= GetFilterCutoff(); + return cutoff > 13500 ? 13500 : cutoff; } - - protected: - O* pOwner; // The owner to which this rack belongs. - - SignalUnitRack* GetSignalUnitRack() { return pOwner->GetSignalUnitRack(); } - - public: + virtual float CalculatePitch(float pitch) { + return GetPitch() * pitch; + } - /** - * The owner of the unit is set by the rack - * just before the call to the unit's trigger method. - */ - void SetOwner(O* Owner) { pOwner = Owner; } + virtual float CalculateResonance(float res) { + return GetResonance() * res; + } - /** - * A helper method which checks whether the delay - * stage is finished. - */ - bool DelayStage() { - return (DelayTrigger() >= GetSignalUnitRack()->GetCurrentStep()); + /** Should return value in the range [0, 127] (L <-> R) */ + virtual uint8_t CaluclatePan(uint8_t pan) { + int p = pan + GetPan() * 0.63; + if (p < 0) return 0; + if (p > 127) return 127; + return p; } }; /** * Continuous controller signal unit. - * The level of this unit corresponds to the controller changes - * and is normalized to be in the range from -1 to +1. + * The level of this unit corresponds to the controllers changes + * and their influences. */ - template - class CCSignalUnit: public SignalUnitBase { - private: - uint8_t Ctrl; // The number of the MIDI controller which modulates this signal unit. + class CCSignalUnit: public SignalUnit { + public: + /** Listener which will be notified when the level of the unit is changed. */ + class Listener { + public: + virtual void ValueChanged(CCSignalUnit* pUnit) = 0; + }; + + protected: + class CC { + public: + uint8_t Controller; ///< MIDI controller number. + uint8_t Value; ///< Controller Value. + short int Curve; ///< specifies the curve type + float Influence; + + CC(uint8_t Controller = 0, float Influence = 0.0f, short int Curve = -1) { + this->Controller = Controller; + this->Value = 0; + this->Curve = Curve; + this->Influence = Influence; + } + + CC(const CC& cc) { Copy(cc); } + void operator=(const CC& cc) { Copy(cc); } + + void Copy(const CC& cc) { + Controller = cc.Controller; + Value = cc.Value; + Influence = cc.Influence; + Curve = cc.Curve; + } + }; + + FixedArray Ctrls; // The MIDI controllers which modulates this signal unit. + Listener* pListener; public: - CCSignalUnit(uint8_t Controller) { - Ctrl = Controller; + + CCSignalUnit(SignalUnitRack* rack, Listener* l = NULL): SignalUnit(rack), Ctrls(128) { + pListener = l; } - CCSignalUnit(const CCSignalUnit& Unit) { Copy(Unit); } + CCSignalUnit(const CCSignalUnit& Unit): SignalUnit(Unit.pRack), Ctrls(128) { Copy(Unit); } void operator=(const CCSignalUnit& Unit) { Copy(Unit); } - virtual void Copy(const CCSignalUnit& Unit) { - SignalUnitBase::Copy(Unit); - Ctrl = Unit.Ctrl; + void Copy(const CCSignalUnit& Unit) { + Ctrls.copy(Unit.Ctrls); + pListener = Unit.pListener; + SignalUnit::Copy(Unit); + } + + void AddCC(uint8_t Controller, float Influence, short int Curve = -1) { + Ctrls.add(CC(Controller, Influence, Curve)); + } + + void RemoveAllCCs() { + Ctrls.clear(); } virtual void Increment() { } + virtual void Trigger() { + Calculate(); + bActive = Level != 0; + } + virtual void ProcessCCEvent(uint8_t Controller, uint8_t Value) { - if (Controller != Ctrl) return; + bool recalculate = false; - // Normalize the value so it belongs to the interval [-1, +1] - SignalUnitBase::Level = 2 * Value; - SignalUnitBase::Level = SignalUnitBase::Level/127.0f - 1.0f; + for (int i = 0; i < Ctrls.size(); i++) { + if (Controller != Ctrls[i].Controller) continue; + if (Ctrls[i].Value == Value) continue; + Ctrls[i].Value = Value; + if (!bActive) bActive = true; + recalculate = true; + } - if (!SignalUnitBase::bActive) SignalUnitBase::bActive = true; - } - }; - - /** - * Endpoint signal unit. - */ - template - class EndpointSignalUnitBase : public SignalUnitBase, public EndpointSignalUnit { - public: - - virtual float CalculateFilterCutoff(float cutoff) { - cutoff *= GetFilterCutoff(); - return cutoff > 13500 ? 13500 : cutoff; - } - - virtual float CalculatePitch(float pitch) { - return GetPitch() * pitch; + if (recalculate) { + Calculate(); + if (pListener!= NULL) pListener->ValueChanged(this); + } } - virtual float CalculateResonance(float res) { - return GetResonance() * res; + virtual void Calculate() { + Level = 0; + for (int i = 0; i < Ctrls.size(); i++) { + if (Ctrls[i].Value == 0) continue; + Level += (Ctrls[i].Value / 127.0f) * Ctrls[i].Influence; + } } };