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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 768 - (hide annotations) (download)
Fri Sep 2 20:11:55 2005 UTC (18 years, 7 months ago) by persson
File size: 13171 byte(s)
* bug fixes for the new EG implementation

1 schoenebeck 53 /***************************************************************************
2     * *
3     * LinuxSampler - modular, streaming capable sampler *
4     * *
5 schoenebeck 56 * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 schoenebeck 554 * Copyright (C) 2005 Christian Schoenebeck *
7 schoenebeck 53 * *
8     * 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 *
10     * the Free Software Foundation; either version 2 of the License, or *
11     * (at your option) any later version. *
12     * *
13     * This program is distributed in the hope that it will be useful, *
14     * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16     * GNU General Public License for more details. *
17     * *
18     * You should have received a copy of the GNU General Public License *
19     * along with this program; if not, write to the Free Software *
20     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
21     * MA 02111-1307 USA *
22     ***************************************************************************/
23    
24     #include "EGADSR.h"
25    
26     namespace LinuxSampler { namespace gig {
27    
28 schoenebeck 738 EGADSR::EGADSR() {
29     enterEndStage();
30     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 schoenebeck 688 void EGADSR::CalculateFadeOutCoeff(float FadeOutTime, float SampleRate) {
35     const float killSteps = FadeOutTime * SampleRate;
36     FadeOutCoeff = -1.0f / killSteps;
37 schoenebeck 239 }
38    
39 schoenebeck 738 void EGADSR::update(event_t Event, double SamplePos, float CurrentPitch, uint SampleRate) {
40     switch (Stage) {
41     case stage_attack:
42     if (StepsLeft) {
43     PostponedEvent = Event;
44     } else {
45     if (Event == event_release)
46     enterReleasePart1Stage();
47     else if (Event == event_cancel_release)
48     enterSustainStage();
49     else if (PostponedEvent == event_release)
50     enterReleasePart1Stage();
51     else if (PostponedEvent == event_cancel_release)
52     enterSustainStage();
53     else if (HoldAttack)
54     enterAttackHoldStage(SamplePos, CurrentPitch);
55     else
56     enterDecay1Part1Stage(SampleRate);
57 schoenebeck 53 }
58 schoenebeck 738 break;
59     case stage_attack_hold:
60     switch (Event) {
61     case event_stage_end:
62     enterDecay1Part1Stage(SampleRate);
63 schoenebeck 53 break;
64 schoenebeck 738 case event_release:
65     enterReleasePart1Stage();
66     break;
67     case event_cancel_release:
68     if (InfiniteSustain)
69     enterSustainStage();
70     else
71     enterDecay1Part1Stage(SampleRate);
72     break;
73 schoenebeck 53 }
74 schoenebeck 738 break;
75     case stage_decay1_part1:
76     switch (Event) {
77 persson 768 case event_stage_end:
78     enterDecay1Part2Stage(SampleRate);
79 persson 614 break;
80 schoenebeck 738 case event_release:
81     enterReleasePart1Stage();
82     break;
83     case event_cancel_release:
84     if (InfiniteSustain)
85     enterSustainStage();
86     else
87     enterDecay2Stage(SampleRate);
88     break;
89 persson 614 }
90 schoenebeck 738 break;
91     case stage_decay1_part2:
92     switch (Event) {
93     case event_release:
94     enterReleasePart1Stage();
95     break;
96     case event_stage_end: // fall through
97     case event_cancel_release:
98     if (InfiniteSustain)
99     enterSustainStage();
100     else
101     enterDecay2Stage(SampleRate);
102     break;
103 schoenebeck 53 }
104 schoenebeck 738 break;
105     case stage_decay2:
106     switch (Event) {
107     case event_stage_end:
108     enterFadeOutStage();
109     break;
110     case event_release:
111     enterReleasePart1Stage();
112     break;
113 persson 614 }
114 schoenebeck 738 break;
115     case stage_sustain:
116     switch (Event) {
117     case event_stage_end: {// just refresh time
118     const int intMax = (unsigned int) -1 >> 1;
119     StepsLeft = intMax; // we use the highest possible value
120     break;
121 schoenebeck 53 }
122 schoenebeck 738 case event_release:
123     enterReleasePart1Stage();
124     break;
125 schoenebeck 53 }
126 schoenebeck 738 break;
127     case stage_release_part1:
128     switch (Event) {
129     case event_stage_end:
130     enterReleasePart2Stage();
131     break;
132     case event_cancel_release:
133     if (InfiniteSustain)
134     enterSustainStage();
135     else
136     enterDecay2Stage(SampleRate);
137     break;
138 schoenebeck 53 }
139 schoenebeck 738 break;
140     case stage_release_part2:
141     switch (Event) {
142     case event_stage_end:
143     enterFadeOutStage();
144     break;
145     case event_cancel_release:
146     if (InfiniteSustain)
147     enterSustainStage();
148     else
149     enterDecay2Stage(SampleRate);
150     break;
151 schoenebeck 53 }
152 schoenebeck 738 break;
153     case stage_fadeout:
154     switch (Event) {
155     case event_stage_end:
156     enterEndStage();
157     break;
158 persson 614 }
159 schoenebeck 738 break;
160 schoenebeck 53 }
161     }
162    
163 schoenebeck 738 void EGADSR::trigger(uint PreAttack, float AttackTime, bool HoldAttack, long LoopStart, float Decay1Time, double Decay2Time, bool InfiniteSustain, uint SustainLevel, float ReleaseTime, float Volume, uint SampleRate) {
164    
165 persson 614 if (SustainLevel) {
166     this->SustainLevel = SustainLevel / 1000.0;
167     } else {
168     // sustain level 0 means that voice dies after decay 1
169     this->SustainLevel = CONFIG_EG_BOTTOM;
170     InfiniteSustain = false;
171     Decay2Time = CONFIG_EG_MIN_RELEASE_TIME;
172     }
173 schoenebeck 53 this->InfiniteSustain = InfiniteSustain;
174     this->HoldAttack = HoldAttack;
175     this->LoopStart = LoopStart;
176    
177 schoenebeck 738 this->Decay1Time = Decay1Time;
178     this->Decay2Time = Decay2Time;
179 persson 614
180 schoenebeck 738 invVolume = 1 / Volume;
181     ExpOffset = (0.25 - 1 / 3.55) * invVolume;
182    
183     // calculate release stage parameters (lin+exp curve)
184     if (ReleaseTime < CONFIG_EG_MIN_RELEASE_TIME) ReleaseTime = CONFIG_EG_MIN_RELEASE_TIME; // to avoid click sounds at the end of the sample playback
185     const float ReleaseStepsLeft = (long) (ReleaseTime * SampleRate);
186     ReleaseSlope = 1.365 * (0 - 1) / ReleaseStepsLeft;
187     ReleaseCoeff = ReleaseSlope * invVolume;
188     ReleaseSlope *= 3.55;
189     ReleaseCoeff2 = exp(ReleaseSlope);
190     ReleaseCoeff3 = ExpOffset * (1 - ReleaseCoeff2);
191     ReleaseLevel2 = 0.25 * invVolume;
192 persson 768
193     enterAttackStage(PreAttack, AttackTime, SampleRate, 0.0, 1.0f);
194 schoenebeck 738 }
195    
196     void EGADSR::enterAttackStage(const uint PreAttack, const float AttackTime, const uint SampleRate, const double SamplePos, const float CurrentPitch) {
197     Stage = stage_attack;
198     Segment = segment_lin;
199 persson 614 // Measurements of GSt output shows that the real attack time
200     // is about 65.5% of the value specified in the gig file.
201 schoenebeck 738 StepsLeft = (int) (0.655f * AttackTime * SampleRate);
202     if (StepsLeft) {
203     Level = (float) PreAttack / 1000.0;
204     Coeff = 0.896f * (1.0f - Level) / StepsLeft; // max level is a bit lower if attack != 0
205     } else { // immediately jump to the next stage
206 persson 768 Level = 1.0;
207 schoenebeck 738 if (HoldAttack) enterAttackHoldStage(SamplePos, CurrentPitch);
208     else enterDecay1Part1Stage(SampleRate);
209 schoenebeck 53 }
210 schoenebeck 738 PostponedEvent = (event_t) -1; // init with anything except release or cancel_release
211     }
212 schoenebeck 53
213 schoenebeck 738 void EGADSR::enterAttackHoldStage(const double SamplePos, const float CurrentPitch) {
214     Stage = stage_attack_hold;
215     Segment = segment_lin;
216     Coeff = 0.0f; // don't rise anymore
217     StepsLeft = (int) (LoopStart - SamplePos / CurrentPitch); // FIXME: just an approximation, inaccuracy grows with higher audio fragment size, sufficient for usual fragment sizes though
218     }
219 persson 614
220 schoenebeck 738 void EGADSR::enterDecay1Part1Stage(const uint SampleRate) {
221 persson 614 // The decay1 and release stage both consist of two parts,
222     // first a linear curve, f, followed by an exponential curve,
223     // g:
224     //
225     // f(x + d) = f(x) + Coeff
226     // g(x + d) = Coeff2 * g(x) + Coeff3
227     //
228     // (where d is 1/SampleRate). The transition from f to g is
229     // done when f(x) has reached Level2 = 25% of full volume.
230 schoenebeck 738 StepsLeft = (int) (Decay1Time * SampleRate);
231     if (StepsLeft && SustainLevel < 1.0) {
232     Stage = stage_decay1_part1;
233     Segment = segment_lin;
234     Decay1Slope = 1.365 * (SustainLevel - 1.0) / StepsLeft;
235     Coeff = Decay1Slope * invVolume;
236 persson 614 Decay1Level2 = 0.25 * invVolume;
237 persson 768 if (Level < Decay1Level2) enterDecay1Part2Stage(SampleRate);
238     else StepsLeft = int((RTMath::Max(Decay1Level2, SustainLevel) - Level) / Coeff);
239 schoenebeck 738 } else {
240     if (InfiniteSustain) enterSustainStage();
241     else enterDecay2Stage(SampleRate);
242 persson 614 }
243 schoenebeck 738 }
244 schoenebeck 53
245 persson 768 void EGADSR::enterDecay1Part2Stage(const uint SampleRate) {
246     if (SustainLevel < Decay1Level2) {
247     Stage = stage_decay1_part2;
248     Segment = segment_exp;
249     Decay1Slope *= 3.55;
250     Coeff = exp(Decay1Slope);
251     Offset = ExpOffset * (1 - Coeff);
252     StepsLeft = int(log((SustainLevel - ExpOffset) / (Level - ExpOffset)) / Decay1Slope);
253     } else {
254     if (InfiniteSustain) enterSustainStage();
255     else enterDecay2Stage(SampleRate);
256     }
257 schoenebeck 738 }
258 schoenebeck 53
259 schoenebeck 738 void EGADSR::enterDecay2Stage(const uint SampleRate) {
260     Stage = stage_decay2;
261     Segment = segment_lin;
262     Decay2Time = RTMath::Max(Decay2Time, CONFIG_EG_MIN_RELEASE_TIME);
263     StepsLeft = (int) (Decay2Time * SampleRate);
264     Coeff = (-1.03 / StepsLeft) * invVolume;
265     //FIXME: do we really have to calculate 'StepsLeft' two times?
266     StepsLeft = int((CONFIG_EG_BOTTOM - Level) / Coeff);
267 persson 768 if (StepsLeft == 0) enterEndStage();
268 schoenebeck 738 }
269 schoenebeck 53
270 schoenebeck 738 void EGADSR::enterSustainStage() {
271     Stage = stage_sustain;
272     Segment = segment_lin;
273     Coeff = 0.0f; // don't change the envelope level in this stage
274     const int intMax = (unsigned int) -1 >> 1;
275     StepsLeft = intMax; // we use the highest value possible (we refresh StepsLeft in update() in case)
276 schoenebeck 53 }
277    
278 schoenebeck 738 void EGADSR::enterReleasePart1Stage() {
279     Stage = stage_release_part1;
280     Segment = segment_lin;
281     StepsLeft = int((ReleaseLevel2 - Level) / ReleaseCoeff);
282     Coeff = ReleaseCoeff;
283     }
284    
285     void EGADSR::enterReleasePart2Stage() {
286     Stage = stage_release_part2;
287     Segment = segment_exp;
288     StepsLeft = int(log((CONFIG_EG_BOTTOM - ExpOffset) / (Level - ExpOffset)) / ReleaseSlope);
289     Coeff = ReleaseCoeff2;
290     Offset = ReleaseCoeff3;
291     }
292    
293     void EGADSR::enterFadeOutStage() {
294     Stage = stage_fadeout;
295     Segment = segment_lin;
296     StepsLeft = int(Level / (-FadeOutCoeff));
297     Coeff = FadeOutCoeff;
298 persson 768 if (StepsLeft == 0) enterEndStage();
299 schoenebeck 738 }
300    
301     void EGADSR::enterEndStage() {
302     Stage = stage_end;
303     Segment = segment_end;
304     }
305    
306 schoenebeck 53 }} // namespace LinuxSampler::gig

  ViewVC Help
Powered by ViewVC