--- linuxsampler/trunk/src/engines/gig/EGADSR.h 2005/07/14 12:25:20 688 +++ linuxsampler/trunk/src/engines/gig/EGADSR.h 2005/10/30 08:35:13 796 @@ -24,14 +24,8 @@ #ifndef __LS_GIG_EGADSR_H__ #define __LS_GIG_EGADSR_H__ -#include - #include "../../common/global.h" #include "../../common/RTMath.h" -#include "../../common/Pool.h" -#include "../common/Event.h" -#include "Manipulator.h" -#include "Engine.h" namespace LinuxSampler { namespace gig { @@ -44,58 +38,181 @@ */ class EGADSR { public: + + /** + * Used to define what kind of segment the envelope currently is at. + */ + enum segment_t { + segment_end = 0, ///< final end state of envelope reached + segment_lin = 1, ///< envelope is currently at a linear segment + segment_exp = 2 ///< envelope is currently at a exponental segment + }; + + /** + * Used to inform the EG about an event. + */ + enum event_t { + event_stage_end, + event_release, + event_cancel_release, + event_hold_end + }; + + /** + * Constructor + */ + EGADSR(); + + /** + * Change fade out time. + */ + void CalculateFadeOutCoeff(float FadeOutTime, float SampleRate); + + /** + * Will be called by the voice when the key / voice was triggered. + * + * @param PreAttack - Preattack value for the envelope + * (0 - 1000 permille) + * @param AttackTime - Attack time for the envelope + * (0.000 - 60.000s) + * @param HoldAttack - if true, Decay1 will be postponed until the + * sample reached the sample loop start. + * @param Decay1Time - Decay1 time of the sample amplitude EG + * (0.000 - 60.000s) + * @param Decay2Time - only if !InfiniteSustain: 2nd decay stage + * time of the sample amplitude EG + * (0.000 - 60.000s) + * @param InfiniteSustain - if true, instead of going into Decay2 + * stage, Decay1 level will be hold until note + * will be released + * @param SustainLevel - Sustain level of the sample amplitude EG + * (0 - 1000 permille) + * @param ReleaseTIme - Release time for the envelope + * (0.000 - 60.000s) + * @param Volume - volume the sample will be played at + * (0.0 - 1.0) - used when calculating the + * exponential curve parameters. + * @param SampleRate - sample rate of used audio output driver + */ + void trigger(uint PreAttack, float AttackTime, bool HoldAttack, float Decay1Time, double Decay2Time, bool InfiniteSustain, uint SustainLevel, float ReleaseTime, float Volume, uint SampleRate); //FIXME: we should better use 'float' for SampleRate + + /** + * Returns true in case envelope hasn't reached its final end state yet. + */ + inline bool active() { + return (bool) Segment; + } + + /** + * Returns what kind of segment the envelope currently is at. + */ + inline segment_t getSegmentType() { + return Segment; + } + + /** + * Advance envelope by \a SamplePoints steps. + */ + inline void increment(int SamplePoints) { + StepsLeft = RTMath::Max(0, StepsLeft - SamplePoints); + } + + /** + * Returns amount of steps until the end of current envelope stage. + */ + inline int toStageEndLeft() { + return StepsLeft; + } + + /** + * Should be called to inform the EG about an external event and + * also whenever an envelope stage is completed. This will handle + * the envelope's transition to the respective next stage. + * + * @param Event - what happened + */ + void update(event_t Event, uint SampleRate); + + /** + * Calculates exactly one, the next sample point of EG + * (linear segment). Call this if envelope is currently in a linear + * segment. + * + * @returns next envelope level + */ + inline float processLin() { + return (Level += Coeff); + } + + /** + * Calculates exactly one, the next sample point of EG + * (exponential segment). Call this if envelope is currently in an + * exponential segment. + * + * @returns next envelope level + */ + inline float processExp() { + return (Level = Level * Coeff + Offset); + } + + /** + * Returns current envelope level without modifying anything. This + * might be needed once the envelope reached its final end state, + * because calling processLin() or processExp() at this point will + * result in undesired behavior. + */ + inline float getLevel() { + return Level; + } + + void enterFadeOutStage(); + + private: + enum stage_t { stage_attack, stage_attack_hold, - stage_decay1_init, - stage_decay1, - stage_decay1_part2_init, + stage_decay1_part1, stage_decay1_part2, - stage_decay2_init, stage_decay2, stage_sustain, - stage_release_init, - stage_release, - stage_release_part2_init, + stage_release_part1, stage_release_part2, stage_fadeout, stage_end }; - EGADSR(gig::Engine* pEngine, Event::destination_t ModulationDestination); - void Process(uint TotalSamples, RTList* pEvents, RTList::Iterator itTriggerEvent, double SamplePos, double CurrentPitch, RTList::Iterator itKillEvent = RTList::Iterator()); - void Trigger(uint PreAttack, double AttackTime, bool HoldAttack, long LoopStart, double Decay1Time, double Decay2Time, bool InfiniteSustain, uint SustainLevel, double ReleaseTime, uint Delay, float Volume); - void CalculateFadeOutCoeff(float FadeOutTime, float SampleRate); - inline EGADSR::stage_t GetStage() { return Stage; } - protected: - gig::Engine* pEngine; - Event::destination_t ModulationDestination; - uint TriggerDelay; ///< number of sample points triggering should be delayed - float Level; - stage_t Stage; - float AttackCoeff; - long AttackStepsLeft; ///< number of sample points til end of attack stage - bool HoldAttack; - long LoopStart; - float Decay1Coeff; - float Decay1Coeff2; - float Decay1Coeff3; - float Decay1Level2; - float Decay1Slope; - long Decay1StepsLeft; ///< number of sample points in Decay1 stage - float Decay2Coeff; - long Decay2StepsLeft; - bool InfiniteSustain; - float SustainLevel; - float ReleaseCoeff; - float ReleaseCoeff2; - float ReleaseCoeff3; - float ReleaseLevel2; - float ReleaseSlope; - long ReleaseStepsLeft; ///< number of sample points til end of release stage - bool ReleasePostponed; ///< If a "release" event occured in the previous audio fragment, but wasn't processed yet. - float ExpOffset; - float FadeOutCoeff; ///< very fast ramp down for e.g. voice stealing + float Level; + float Coeff; + float Offset; + int StepsLeft; + segment_t Segment; + stage_t Stage; + bool HoldAttack; + bool InfiniteSustain; + float Decay1Time; + float Decay1Level2; + float Decay1Slope; + float Decay2Time; + float SustainLevel; + float ReleaseCoeff; + float ReleaseCoeff2; + float ReleaseCoeff3; + float ReleaseLevel2; + float ReleaseSlope; + float invVolume; + float ExpOffset; + float FadeOutCoeff; ///< very fast ramp down for e.g. voice stealing + + void enterAttackStage(const uint PreAttack, const float AttackTime, const uint SampleRate); + void enterAttackHoldStage(); + void enterDecay1Part1Stage(const uint SampleRate); + void enterDecay1Part2Stage(const uint SampleRate); + void enterDecay2Stage(const uint SampleRate); + void enterSustainStage(); + void enterReleasePart1Stage(); + void enterReleasePart2Stage(); + void enterEndStage(); }; }} // namespace LinuxSampler::gig