/[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 738 - (show annotations) (download)
Tue Aug 16 17:14:25 2005 UTC (18 years, 8 months ago) by schoenebeck
File size: 12798 byte(s)
* extensive synthesis optimization: reimplementation of EGs and LFO(s),
  removed synthesis parameter prerendering and the synthesis parameter
  matrix in general, splitting each audio fragment into subfragments now
  where each subfragment uses constant synthesis parameters
  (everything's still very buggy ATM)

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 stage_end:
78 enterDecay1Part2Stage();
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 enterAttackStage(PreAttack, AttackTime, SampleRate, 0.0, 1.0f);
166
167 if (SustainLevel) {
168 this->SustainLevel = SustainLevel / 1000.0;
169 } else {
170 // sustain level 0 means that voice dies after decay 1
171 this->SustainLevel = CONFIG_EG_BOTTOM;
172 InfiniteSustain = false;
173 Decay2Time = CONFIG_EG_MIN_RELEASE_TIME;
174 }
175 this->InfiniteSustain = InfiniteSustain;
176 this->HoldAttack = HoldAttack;
177 this->LoopStart = LoopStart;
178
179 this->Decay1Time = Decay1Time;
180 this->Decay2Time = Decay2Time;
181
182 invVolume = 1 / Volume;
183 ExpOffset = (0.25 - 1 / 3.55) * invVolume;
184
185 // calculate release stage parameters (lin+exp curve)
186 if (ReleaseTime < CONFIG_EG_MIN_RELEASE_TIME) ReleaseTime = CONFIG_EG_MIN_RELEASE_TIME; // to avoid click sounds at the end of the sample playback
187 const float ReleaseStepsLeft = (long) (ReleaseTime * SampleRate);
188 ReleaseSlope = 1.365 * (0 - 1) / ReleaseStepsLeft;
189 ReleaseCoeff = ReleaseSlope * invVolume;
190 ReleaseSlope *= 3.55;
191 ReleaseCoeff2 = exp(ReleaseSlope);
192 ReleaseCoeff3 = ExpOffset * (1 - ReleaseCoeff2);
193 ReleaseLevel2 = 0.25 * invVolume;
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 if (HoldAttack) enterAttackHoldStage(SamplePos, CurrentPitch);
207 else enterDecay1Part1Stage(SampleRate);
208 }
209 PostponedEvent = (event_t) -1; // init with anything except release or cancel_release
210 }
211
212 void EGADSR::enterAttackHoldStage(const double SamplePos, const float CurrentPitch) {
213 Stage = stage_attack_hold;
214 Segment = segment_lin;
215 Coeff = 0.0f; // don't rise anymore
216 StepsLeft = (int) (LoopStart - SamplePos / CurrentPitch); // FIXME: just an approximation, inaccuracy grows with higher audio fragment size, sufficient for usual fragment sizes though
217 }
218
219 void EGADSR::enterDecay1Part1Stage(const uint SampleRate) {
220 // The decay1 and release stage both consist of two parts,
221 // first a linear curve, f, followed by an exponential curve,
222 // g:
223 //
224 // f(x + d) = f(x) + Coeff
225 // g(x + d) = Coeff2 * g(x) + Coeff3
226 //
227 // (where d is 1/SampleRate). The transition from f to g is
228 // done when f(x) has reached Level2 = 25% of full volume.
229 StepsLeft = (int) (Decay1Time * SampleRate);
230 if (StepsLeft && SustainLevel < 1.0) {
231 Stage = stage_decay1_part1;
232 Segment = segment_lin;
233 Decay1Slope = 1.365 * (SustainLevel - 1.0) / StepsLeft;
234 Coeff = Decay1Slope * invVolume;
235 Decay1Level2 = 0.25 * invVolume;
236 StepsLeft = int((RTMath::Max(Decay1Level2, SustainLevel) - Level) / Coeff);
237 } else {
238 Level = SustainLevel;
239 if (InfiniteSustain) enterSustainStage();
240 else enterDecay2Stage(SampleRate);
241 }
242 }
243
244 void EGADSR::enterDecay1Part2Stage() {
245 Stage = stage_decay1_part2;
246 Segment = segment_exp;
247 Decay1Slope *= 3.55;
248 Coeff = exp(Decay1Slope);
249 Offset = ExpOffset * (1 - Coeff);
250 Level = Decay1Level2;
251 StepsLeft = int(log((SustainLevel - ExpOffset) / (Level - ExpOffset)) / Decay1Slope);
252 }
253
254 void EGADSR::enterDecay2Stage(const uint SampleRate) {
255 Stage = stage_decay2;
256 Segment = segment_lin;
257 Decay2Time = RTMath::Max(Decay2Time, CONFIG_EG_MIN_RELEASE_TIME);
258 StepsLeft = (int) (Decay2Time * SampleRate);
259 Coeff = (-1.03 / StepsLeft) * invVolume;
260 //FIXME: do we really have to calculate 'StepsLeft' two times?
261 StepsLeft = int((CONFIG_EG_BOTTOM - Level) / Coeff);
262 }
263
264 void EGADSR::enterSustainStage() {
265 Stage = stage_sustain;
266 Segment = segment_lin;
267 Coeff = 0.0f; // don't change the envelope level in this stage
268 const int intMax = (unsigned int) -1 >> 1;
269 StepsLeft = intMax; // we use the highest value possible (we refresh StepsLeft in update() in case)
270 }
271
272 void EGADSR::enterReleasePart1Stage() {
273 Stage = stage_release_part1;
274 Segment = segment_lin;
275 StepsLeft = int((ReleaseLevel2 - Level) / ReleaseCoeff);
276 Coeff = ReleaseCoeff;
277 }
278
279 void EGADSR::enterReleasePart2Stage() {
280 Stage = stage_release_part2;
281 Segment = segment_exp;
282 StepsLeft = int(log((CONFIG_EG_BOTTOM - ExpOffset) / (Level - ExpOffset)) / ReleaseSlope);
283 Coeff = ReleaseCoeff2;
284 Offset = ReleaseCoeff3;
285 }
286
287 void EGADSR::enterFadeOutStage() {
288 Stage = stage_fadeout;
289 Segment = segment_lin;
290 StepsLeft = int(Level / (-FadeOutCoeff));
291 Coeff = FadeOutCoeff;
292 }
293
294 void EGADSR::enterEndStage() {
295 Stage = stage_end;
296 Segment = segment_end;
297 }
298
299 }} // namespace LinuxSampler::gig

  ViewVC Help
Powered by ViewVC