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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 768 - (show 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 /***************************************************************************
2 * *
3 * LinuxSampler - modular, streaming capable sampler *
4 * *
5 * 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 *
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 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 void EGADSR::CalculateFadeOutCoeff(float FadeOutTime, float SampleRate) {
35 const float killSteps = FadeOutTime * SampleRate;
36 FadeOutCoeff = -1.0f / killSteps;
37 }
38
39 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 }
58 break;
59 case stage_attack_hold:
60 switch (Event) {
61 case event_stage_end:
62 enterDecay1Part1Stage(SampleRate);
63 break;
64 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 }
74 break;
75 case stage_decay1_part1:
76 switch (Event) {
77 case event_stage_end:
78 enterDecay1Part2Stage(SampleRate);
79 break;
80 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 }
90 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 }
104 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 }
114 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 }
122 case event_release:
123 enterReleasePart1Stage();
124 break;
125 }
126 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 }
139 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 }
152 break;
153 case stage_fadeout:
154 switch (Event) {
155 case event_stage_end:
156 enterEndStage();
157 break;
158 }
159 break;
160 }
161 }
162
163 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 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 this->InfiniteSustain = InfiniteSustain;
174 this->HoldAttack = HoldAttack;
175 this->LoopStart = LoopStart;
176
177 this->Decay1Time = Decay1Time;
178 this->Decay2Time = Decay2Time;
179
180 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
193 enterAttackStage(PreAttack, AttackTime, SampleRate, 0.0, 1.0f);
194 }
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 // Measurements of GSt output shows that the real attack time
200 // is about 65.5% of the value specified in the gig file.
201 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 Level = 1.0;
207 if (HoldAttack) enterAttackHoldStage(SamplePos, CurrentPitch);
208 else enterDecay1Part1Stage(SampleRate);
209 }
210 PostponedEvent = (event_t) -1; // init with anything except release or cancel_release
211 }
212
213 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
220 void EGADSR::enterDecay1Part1Stage(const uint SampleRate) {
221 // 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 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 Decay1Level2 = 0.25 * invVolume;
237 if (Level < Decay1Level2) enterDecay1Part2Stage(SampleRate);
238 else StepsLeft = int((RTMath::Max(Decay1Level2, SustainLevel) - Level) / Coeff);
239 } else {
240 if (InfiniteSustain) enterSustainStage();
241 else enterDecay2Stage(SampleRate);
242 }
243 }
244
245 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 }
258
259 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 if (StepsLeft == 0) enterEndStage();
268 }
269
270 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 }
277
278 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 if (StepsLeft == 0) enterEndStage();
299 }
300
301 void EGADSR::enterEndStage() {
302 Stage = stage_end;
303 Segment = segment_end;
304 }
305
306 }} // namespace LinuxSampler::gig

  ViewVC Help
Powered by ViewVC