/[svn]/linuxsampler/trunk/src/engines/gig/EGADSR.cpp
ViewVC logotype

Diff of /linuxsampler/trunk/src/engines/gig/EGADSR.cpp

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

revision 237 by senkov, Sun Sep 12 01:59:40 2004 UTC revision 1147 by persson, Tue Apr 3 17:39:52 2007 UTC
# Line 3  Line 3 
3   *   LinuxSampler - modular, streaming capable sampler                     *   *   LinuxSampler - modular, streaming capable sampler                     *
4   *                                                                         *   *                                                                         *
5   *   Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck   *   *   Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck   *
6     *   Copyright (C) 2005 Christian Schoenebeck                              *
7   *                                                                         *   *                                                                         *
8   *   This program is free software; you can redistribute it and/or modify  *   *   This program is free software; you can redistribute it and/or modify  *
9   *   it under the terms of the GNU General Public License as published by  *   *   it under the terms of the GNU General Public License as published by  *
# Line 24  Line 25 
25    
26  namespace LinuxSampler { namespace gig {  namespace LinuxSampler { namespace gig {
27    
28      EGADSR::EGADSR(gig::Engine* pEngine, Event::destination_t ModulationDestination) {      EGADSR::EGADSR() {
29          this->pEngine = pEngine;          enterEndStage();
         this->ModulationDestination = ModulationDestination;  
         Stage = stage_end;  
30          Level = 0.0;          Level = 0.0;
31            CalculateFadeOutCoeff(CONFIG_EG_MIN_RELEASE_TIME, 44100.0); // even if the sample rate will be 192kHz it won't hurt at all
32      }      }
33    
34      /**      void EGADSR::CalculateFadeOutCoeff(float FadeOutTime, float SampleRate) {
35       * Will be called by the voice for every audio fragment to let the EG          const float killSteps = FadeOutTime * SampleRate / CONFIG_DEFAULT_SUBFRAGMENT_SIZE;
36       * queue it's modulation changes for the current audio fragment.          FadeOutCoeff = -1.0f / killSteps;
37       *      }
      * @param Samples       - total number of sample points to be rendered in this  
      *                        audio fragment cycle by the audio engine  
      * @param pEvents       - event list with "release" and "cancel release" events  
      * @param pTriggerEvent - event that caused triggering of the voice (only if  
      *                        the voices was triggered in the current audio  
      *                        fragment, NULL otherwise)  
      * @param SamplePos     - current playback position  
      * @param CurrentPitch  - current pitch value for playback  
      */  
     void EGADSR::Process(uint Samples, RTEList<Event>* pEvents, Event* pTriggerEvent, double SamplePos, double CurrentPitch) {  
         Event* pTransitionEvent;  
         if (pTriggerEvent) {  
             pEvents->set_current(pTriggerEvent);  
             pTransitionEvent = pEvents->next();  
         }  
         else {  
             pTransitionEvent = pEvents->first();  
         }  
38    
39          int iSample = TriggerDelay;      void EGADSR::update(event_t Event, uint SampleRate) {
40          while (iSample < Samples) {          if (Event == event_hold_end) HoldAttack = false;
41              switch (Stage) {  
42                  case stage_attack: {          switch (Stage) {
43                      TriggerDelay = 0;              case stage_attack:
44                      int to_process   = RTMath::Min(AttackStepsLeft, Samples - iSample);                  switch (Event) {
45                      int process_end  = iSample + to_process;                      case event_release:
46                      AttackStepsLeft -= to_process;                          enterReleasePart1Stage();
47                      while (iSample < process_end) {                          break;
48                          Level += AttackCoeff;                      case event_cancel_release:
49                          pEngine->pSynthesisParameters[ModulationDestination][iSample++] *= Level;                          enterSustainStage();
50                      }                          break;
51                      if (iSample == Samples) { // postpone last transition event for the next audio fragment                      case event_stage_end:
52                          Event* pLastEvent = pEvents->last();                          if (HoldAttack)
53                          if (pLastEvent) ReleasePostponed = (pLastEvent->Type == Event::type_release);                              enterAttackHoldStage();
54                      }                          else
55                      if (!AttackStepsLeft) Stage = (ReleasePostponed) ? stage_release : (HoldAttack) ? stage_attack_hold : stage_decay1;                              enterDecay1Part1Stage(SampleRate);
56                      break;                          break;
57                  }                  }
58                  case stage_attack_hold: {                  break;
59                      if (SamplePos >= LoopStart) {              case stage_attack_hold:
60                          Stage = stage_decay1;                  switch (Event) {
61                        case event_stage_end: {// just refresh time
62                            const int intMax = (unsigned int) -1 >> 1;
63                            StepsLeft = intMax; // we use the highest possible value
64                          break;                          break;
65                      }                      }
66                      int holdstepsleft = (int) (LoopStart - SamplePos / CurrentPitch); // FIXME: just an approximation, inaccuracy grows with higher audio fragment size, sufficient for usual fragment sizes though                      case event_hold_end:
67                      int to_process    = RTMath::Min(holdstepsleft, Samples - iSample);                          enterDecay1Part1Stage(SampleRate);
68                      int process_end   = iSample + to_process;                          break;
69                      if (pTransitionEvent && pTransitionEvent->FragmentPos() <= process_end) {                      case event_release:
70                          process_end      = pTransitionEvent->FragmentPos();                          enterReleasePart1Stage();
71                          Stage            = (pTransitionEvent->Type == Event::type_release) ? stage_release : (InfiniteSustain) ? stage_sustain : stage_decay2;                          break;
72                          pTransitionEvent = pEvents->next();                      case event_cancel_release:
73                      }                          if (InfiniteSustain)
74                      else if (to_process == holdstepsleft) Stage = stage_decay1;                              enterSustainStage();
75                      while (iSample < process_end) {                          else
76                          pEngine->pSynthesisParameters[ModulationDestination][iSample++] *= Level;                              enterDecay1Part1Stage(SampleRate);
77                      }                          break;
                     break;  
78                  }                  }
79                  case stage_decay1: {                  break;
80                      int to_process   = RTMath::Min(Samples - iSample, Decay1StepsLeft);              case stage_decay1_part1:
81                      int process_end  = iSample + to_process;                  switch (Event) {
82                      if (pTransitionEvent && pTransitionEvent->FragmentPos() <= process_end) {                      case event_stage_end:
83                          process_end      = pTransitionEvent->FragmentPos();                          enterDecay1Part2Stage(SampleRate);
84                          Stage            = (pTransitionEvent->Type == Event::type_release) ? stage_release : (InfiniteSustain) ? stage_sustain : stage_decay2;                          break;
85                          pTransitionEvent = pEvents->next();                      case event_release:
86                      }                          enterReleasePart1Stage();
87                      else {                          break;
88                          Decay1StepsLeft -= to_process;                      case event_cancel_release:
89                          if (!Decay1StepsLeft) Stage = (InfiniteSustain) ? stage_sustain : stage_decay2;                          if (InfiniteSustain)
90                      }                              enterSustainStage();
91                      while (iSample < process_end) {                          else
92                          Level += Level * Decay1Coeff;                              enterDecay2Stage(SampleRate);
93                          pEngine->pSynthesisParameters[ModulationDestination][iSample++] *= Level;                          break;
                     }  
                     break;  
94                  }                  }
95                  case stage_decay2: {                  break;
96                      int process_end;              case stage_decay1_part2:
97                      if (pTransitionEvent && pTransitionEvent->Type == Event::type_release && pTransitionEvent->FragmentPos() <= Samples) {                  switch (Event) {
98                          process_end      = pTransitionEvent->FragmentPos();                      case event_release:
99                          pTransitionEvent = pEvents->next();                          enterReleasePart1Stage();
100                          Stage            = stage_release; // switch to release stage soon                          break;
101                      }                      case event_stage_end: // fall through
102                      else process_end = Samples;                      case event_cancel_release:
103                      while (iSample < process_end) {                          if (Level < CONFIG_EG_BOTTOM)
104                          Level += Level * Decay2Coeff;                              enterEndStage();
105                          pEngine->pSynthesisParameters[ModulationDestination][iSample++] *= Level;                          else if (InfiniteSustain)
106                      }                              enterSustainStage();
107                      if (Level <= EG_ENVELOPE_LIMIT) Stage = stage_end;                          else
108                      break;                              enterDecay2Stage(SampleRate);
109                            break;
110                  }                  }
111                  case stage_sustain: {                  break;
112                      int process_end;              case stage_decay2:
113                      if (pTransitionEvent && pTransitionEvent->Type == Event::type_release && pTransitionEvent->FragmentPos() <= Samples) {                  switch (Event) {
114                          process_end      = pTransitionEvent->FragmentPos();                      case event_stage_end:
115                          pTransitionEvent = pEvents->next();                          enterFadeOutStage();
116                          Stage            = stage_release; // switch to release stage soon                          break;
117                      }                      case event_release:
118                      else process_end = Samples;                          enterReleasePart1Stage();
119                      while (iSample < process_end) {                          break;
120                         pEngine->pSynthesisParameters[ModulationDestination][iSample++] *= Level;                      case event_hold_end:
121                      }                          enterDecay1Part1Stage(SampleRate);
122                      break;                          break;
123                  }                  }
124                  case stage_release: {                  break;
125                      int process_end;              case stage_sustain:
126                      if (pTransitionEvent && pTransitionEvent->Type == Event::type_cancel_release && pTransitionEvent->FragmentPos() <= Samples) {                  switch (Event) {
127                          process_end      = pTransitionEvent->FragmentPos();                      case event_stage_end: {// just refresh time
128                          pTransitionEvent = pEvents->next();                          const int intMax = (unsigned int) -1 >> 1;
129                          Stage            = (InfiniteSustain) ? stage_sustain : stage_decay2; // switch back to sustain / decay2 stage soon                          StepsLeft = intMax; // we use the highest possible value
130                      }                          break;
                     else process_end = Samples;  
                     while (iSample < process_end) {  
                         Level += Level * ReleaseCoeff;  
                         pEngine->pSynthesisParameters[ModulationDestination][iSample++] *= Level;  
131                      }                      }
132                      if (Level <= EG_ENVELOPE_LIMIT) Stage = stage_end;                      case event_release:
133                      break;                          enterReleasePart1Stage();
134                            break;
135                        case event_hold_end:
136                            enterDecay1Part1Stage(SampleRate);
137                            break;
138                  }                  }
139                  case stage_end: {                  break;
140                      while (iSample < Samples) {              case stage_release_part1:
141                          Level += Level * ReleaseCoeff;                  switch (Event) {
142                          pEngine->pSynthesisParameters[ModulationDestination][iSample++] *= Level;                      case event_stage_end:
143                      }                          enterReleasePart2Stage();
144                      break;                          break;
145                        case event_cancel_release:
146                            if (InfiniteSustain)
147                                enterSustainStage();
148                            else
149                                enterDecay2Stage(SampleRate);
150                            break;
151                    }
152                    break;
153                case stage_release_part2:
154                    switch (Event) {
155                        case event_stage_end:
156                            enterFadeOutStage();
157                            break;
158                        case event_cancel_release:
159                            if (InfiniteSustain)
160                                enterSustainStage();
161                            else
162                                enterDecay2Stage(SampleRate);
163                            break;
164                  }                  }
165              }                  break;
166                case stage_fadeout:
167                    switch (Event) {
168                        case event_stage_end:
169                            enterEndStage();
170                            break;
171                    }
172                    break;
173          }          }
174      }      }
175    
176      /**      void EGADSR::trigger(uint PreAttack, float AttackTime, bool HoldAttack, float Decay1Time, double Decay2Time, bool InfiniteSustain, uint SustainLevel, float ReleaseTime, float Volume, uint SampleRate) {
177       * Will be called by the voice when the key / voice was triggered.          this->SustainLevel     = SustainLevel / 1000.0;
      *  
      * @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 LoopStart       - Sample position where sample loop starts (if any)  
      * @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 phase, 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 Delay           - Number of sample points triggering should be delayed.  
      */  
     void EGADSR::Trigger(uint PreAttack, double AttackTime, bool HoldAttack, long LoopStart, double Decay1Time, double Decay2Time, bool InfiniteSustain, uint SustainLevel, double ReleaseTime, uint Delay) {  
         this->TriggerDelay     = Delay;  
         this->Stage            = stage_attack;  
         this->SustainLevel     = (SustainLevel) ? (SustainLevel > EG_ENVELOPE_LIMIT) ? (float) SustainLevel / 1000.0 : EG_ENVELOPE_LIMIT : 1.0;  
178          this->InfiniteSustain  = InfiniteSustain;          this->InfiniteSustain  = InfiniteSustain;
179          this->HoldAttack       = HoldAttack;          this->HoldAttack       = HoldAttack;
         this->LoopStart        = LoopStart;  
         this->ReleasePostponed = false;  
180    
181          // calculate attack stage parameters (lin. curve)          this->Decay1Time = Decay1Time;
182          AttackStepsLeft = (long) (AttackTime * pEngine->pAudioOutputDevice->SampleRate());          this->Decay2Time = Decay2Time;
183          if (AttackStepsLeft) {  
184              Level       = (float) PreAttack / 1000.0;          invVolume = 1 / Volume;
185              AttackCoeff = (1.0 - Level) / AttackStepsLeft;          ExpOffset = (0.25 - 1 / 3.55) * invVolume;
186    
187            // calculate release stage parameters (lin+exp curve)
188            if (ReleaseTime < CONFIG_EG_MIN_RELEASE_TIME) ReleaseTime = CONFIG_EG_MIN_RELEASE_TIME;  // to avoid click sounds at the end of the sample playback
189            const float ReleaseStepsLeft = (long) (ReleaseTime * SampleRate);
190            ReleaseSlope  = 1.365 * (0 - 1) / ReleaseStepsLeft;
191            ReleaseCoeff  = ReleaseSlope * invVolume;
192            ReleaseSlope  *= 3.55;
193            ReleaseCoeff2 = exp(ReleaseSlope);
194            ReleaseCoeff3 = ExpOffset * (1 - ReleaseCoeff2);
195            ReleaseLevel2 = 0.25 * invVolume;
196    
197            enterAttackStage(PreAttack, AttackTime, SampleRate);
198        }
199    
200        void EGADSR::enterAttackStage(const uint PreAttack, const float AttackTime, const uint SampleRate) {
201            Stage   = stage_attack;
202            Segment = segment_lin;
203    
204            if (AttackTime >= 0.0005f) {
205                // Measurements of GSt output shows that the real attack time
206                // is about 65.5% of the value specified in the gig file.
207                // The minimum attack value used is 0.032.
208                StepsLeft = int(0.655f * RTMath::Max(AttackTime, 0.032f) * SampleRate);
209                Level = (float) PreAttack / 1000.0;
210                Coeff = 0.896f * (1.0f - Level) / StepsLeft; // max level is a bit lower if attack != 0
211            } else { // attack is zero - immediately jump to the next stage
212                Level = 1.029f; // a bit higher than max sustain
213                if (HoldAttack) enterAttackHoldStage();
214                else            enterDecay1Part1Stage(SampleRate);
215          }          }
216          else {      }
217              Level       = 1.0;  
218              AttackCoeff = 0.0;      void EGADSR::enterAttackHoldStage() {
219            Stage     = stage_attack_hold;
220            Segment   = segment_lin;
221            Coeff     = 0.0f; // don't rise anymore
222            const int intMax = (unsigned int) -1 >> 1;
223            StepsLeft = intMax; // we use the highest value possible (we refresh StepsLeft in update() in case)
224        }
225    
226        void EGADSR::enterDecay1Part1Stage(const uint SampleRate) {
227            // The decay1 and release stage both consist of two parts,
228            // first a linear curve, f, followed by an exponential curve,
229            // g:
230            //
231            // f(x + d) = f(x) + Coeff
232            // g(x + d) = Coeff2 * g(x) + Coeff3
233            //
234            // (where d is 1/SampleRate). The transition from f to g is
235            // done when f(x) has reached Level2 = 25% of full volume.
236            StepsLeft = (int) (Decay1Time * SampleRate);
237            if (StepsLeft && Level > SustainLevel) {
238                Stage        = stage_decay1_part1;
239                Segment      = segment_lin;
240                Decay1Slope = (1.347f * SustainLevel - 1.361f) / StepsLeft;
241                Coeff        = Decay1Slope * invVolume;
242                Decay1Level2 = 0.25 * invVolume;
243                StepsLeft = int((RTMath::Max(Decay1Level2, SustainLevel) - Level) / Coeff);
244                if (StepsLeft <= 0) enterDecay1Part2Stage(SampleRate);
245            } else {
246                if (InfiniteSustain) enterSustainStage();
247                else                 enterDecay2Stage(SampleRate);
248          }          }
249        }
250    
251          // calculate decay1 stage parameters (exp. curve)      void EGADSR::enterDecay1Part2Stage(const uint SampleRate) {
252          Decay1StepsLeft = (long) (Decay1Time * pEngine->pAudioOutputDevice->SampleRate());          if (SustainLevel < Decay1Level2) {
253          Decay1Coeff     = (Decay1StepsLeft) ? exp(log(this->SustainLevel) / (double) Decay1StepsLeft) - 1.0              Stage   = stage_decay1_part2;
254                                              : 0.0;              Segment = segment_exp;
255                Decay1Slope *= 3.55;
256          // calculate decay2 stage parameters (exp. curve)              Coeff  = exp(Decay1Slope);
257          if (!InfiniteSustain) {              Offset = ExpOffset * (1 - Coeff);
258              if (Decay2Time < EG_MIN_RELEASE_TIME) Decay2Time = EG_MIN_RELEASE_TIME;              StepsLeft = int(log((SustainLevel - ExpOffset) / (Level - ExpOffset)) / Decay1Slope);
259              long Decay2Steps = (long) (Decay2Time * pEngine->pAudioOutputDevice->SampleRate());              if (StepsLeft > 0) return;
             Decay2Coeff      = (Decay2Steps) ? exp((log(EG_ENVELOPE_LIMIT) - log(this->SustainLevel)) / Decay2Steps + log(this->SustainLevel)) - this->SustainLevel  
                                             : 0.0;  
260          }          }
261            if (InfiniteSustain) enterSustainStage();
262            else                 enterDecay2Stage(SampleRate);
263        }
264    
265        void EGADSR::enterDecay2Stage(const uint SampleRate) {
266            Stage      = stage_decay2;
267            Segment    = segment_lin;
268            Decay2Time = RTMath::Max(Decay2Time, 0.05f);
269            StepsLeft  = (int) (Decay2Time * SampleRate);
270            Coeff      = (-1.03 / StepsLeft) * invVolume;
271            //FIXME: do we really have to calculate 'StepsLeft' two times?
272            StepsLeft  = int((CONFIG_EG_BOTTOM - Level) / Coeff);
273            if (StepsLeft <= 0) enterEndStage();
274        }
275    
276          // calcuate release stage parameters (exp. curve)      void EGADSR::enterSustainStage() {
277          if (ReleaseTime < EG_MIN_RELEASE_TIME) ReleaseTime = EG_MIN_RELEASE_TIME;  // to avoid click sounds at the end of the sample playback          Stage   = stage_sustain;
278          ReleaseStepsLeft = (long) (ReleaseTime * pEngine->pAudioOutputDevice->SampleRate());          Segment = segment_lin;
279          ReleaseCoeff     = exp((log(EG_ENVELOPE_LIMIT) - log(this->SustainLevel)) / ReleaseStepsLeft + log(this->SustainLevel)) - this->SustainLevel;          Coeff   = 0.0f; // don't change the envelope level in this stage
280            const int intMax = (unsigned int) -1 >> 1;
281            StepsLeft = intMax; // we use the highest value possible (we refresh StepsLeft in update() in case)
282        }
283    
284        void EGADSR::enterReleasePart1Stage() {
285            Stage     = stage_release_part1;
286            Segment   = segment_lin;
287            StepsLeft = int((ReleaseLevel2 - Level) / ReleaseCoeff);
288            Coeff     = ReleaseCoeff;
289            if (StepsLeft <= 0) enterReleasePart2Stage();
290        }
291    
292        void EGADSR::enterReleasePart2Stage() {
293            Stage     = stage_release_part2;
294            Segment   = segment_exp;
295            StepsLeft = int(log((CONFIG_EG_BOTTOM - ExpOffset) / (Level - ExpOffset)) / ReleaseSlope);
296            Coeff     = ReleaseCoeff2;
297            Offset    = ReleaseCoeff3;
298            if (StepsLeft <= 0) enterFadeOutStage();
299        }
300    
301        void EGADSR::enterFadeOutStage() {
302            Stage     = stage_fadeout;
303            Segment   = segment_lin;
304            StepsLeft = int(Level / (-FadeOutCoeff));
305            Coeff     = FadeOutCoeff;
306            if (StepsLeft <= 0) enterEndStage();
307        }
308    
309          dmsg(4,("PreAttack=%d, AttackLength=%d, AttackCoeff=%f, Decay1Coeff=%f, Decay2Coeff=%f, ReleaseLength=%d, ReleaseCoeff=%f\n",      void EGADSR::enterEndStage() {
310                  PreAttack, AttackStepsLeft, AttackCoeff, Decay1Coeff, Decay2Coeff, ReleaseStepsLeft, ReleaseCoeff));          Stage   = stage_end;
311            Segment = segment_end;
312            Level   = 0;
313      }      }
314    
315  }} // namespace LinuxSampler::gig  }} // namespace LinuxSampler::gig

Legend:
Removed from v.237  
changed lines
  Added in v.1147

  ViewVC Help
Powered by ViewVC