/[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 688 - (show annotations) (download)
Thu Jul 14 12:25:20 2005 UTC (18 years, 9 months ago) by schoenebeck
File size: 20390 byte(s)
* if period time of chosen audio device is too small (< MIN_RELEASE_TIME)
  then simply show a warning about possible click sounds and reduce the
  volume ramp down appropriately instead of cancelling the audio device
  connection

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 void EGADSR::CalculateFadeOutCoeff(float FadeOutTime, float SampleRate) {
29 const float killSteps = FadeOutTime * SampleRate;
30 FadeOutCoeff = -1.0f / killSteps;
31 }
32
33 EGADSR::EGADSR(gig::Engine* pEngine, Event::destination_t ModulationDestination) {
34 this->pEngine = pEngine;
35 this->ModulationDestination = ModulationDestination;
36 Stage = stage_end;
37 Level = 0.0;
38 CalculateFadeOutCoeff(CONFIG_EG_MIN_RELEASE_TIME, 44100.0); // even if the sample rate will be 192kHz it won't hurt at all
39 }
40
41 /**
42 * Will be called by the voice for every audio fragment to let the EG
43 * queue it's modulation changes for the current audio fragment.
44 *
45 * @param TotalSamples - total number of sample points to be rendered in this
46 * audio fragment cycle by the audio engine
47 * @param pEvents - event list with "release" and "cancel release" events
48 * @param itTriggerEvent - event that caused triggering of the voice (only if
49 * the voice was triggered in the current audio
50 * fragment, NULL otherwise)
51 * @param SamplePos - current playback position
52 * @param CurrentPitch - current pitch value for playback
53 * @param itKillEvent - (optional) event which caused this voice to be killed
54 */
55 void EGADSR::Process(uint TotalSamples, RTList<Event>* pEvents, RTList<Event>::Iterator itTriggerEvent, double SamplePos, double CurrentPitch, RTList<Event>::Iterator itKillEvent) {
56 // skip all events which occured before this voice was triggered
57 RTList<Event>::Iterator itTransitionEvent = (itTriggerEvent) ? ++itTriggerEvent : pEvents->first();
58
59 // if the voice was killed in this fragment we only process the time before this kill event, then switch to 'stage_fadeout'
60 int Samples = (itKillEvent) ? RTMath::Min(itKillEvent->FragmentPos(), pEngine->MaxFadeOutPos) : (int) TotalSamples;
61
62 int iSample = TriggerDelay;
63
64 #if CONFIG_DEVMODE
65 if (TriggerDelay > TotalSamples) { // just a sanity check for debugging
66 dmsg(1,("EGADSR: ERROR, TriggerDelay > Totalsamples\n"));
67 int* i = NULL;
68 (*i)++; // force a segfault
69 }
70 #endif // CONFIG_DEVMODE
71
72 while (iSample < TotalSamples) {
73
74 // if the voice was killed in this fragment and we already processed the time before this kill event
75 if (itKillEvent && iSample >= Samples) Stage = stage_fadeout;
76
77 switch (Stage) {
78 case stage_attack: {
79 TriggerDelay = 0;
80 int to_process = RTMath::Min(AttackStepsLeft, Samples - iSample);
81 int process_end = iSample + to_process;
82 AttackStepsLeft -= to_process;
83 while (iSample < process_end) {
84 Level += AttackCoeff;
85 pEngine->pSynthesisParameters[ModulationDestination][iSample++] *= Level;
86 }
87 if (iSample == TotalSamples && itTransitionEvent) { // postpone last transition event for the next audio fragment
88 RTList<Event>::Iterator itLastEvent = pEvents->last();
89 if (itLastEvent) ReleasePostponed = (itLastEvent->Type == Event::type_release);
90 }
91 if (!AttackStepsLeft) Stage = (ReleasePostponed) ? stage_release_init : (HoldAttack) ? stage_attack_hold : stage_decay1_init;
92 break;
93 }
94 case stage_attack_hold: {
95 if (SamplePos >= LoopStart) {
96 Stage = stage_decay1_init;
97 break;
98 }
99 int holdstepsleft = (int) (LoopStart - SamplePos / CurrentPitch); // FIXME: just an approximation, inaccuracy grows with higher audio fragment size, sufficient for usual fragment sizes though
100 int to_process = RTMath::Min(holdstepsleft, Samples - iSample);
101 int process_end = iSample + to_process;
102 if (itTransitionEvent && itTransitionEvent->FragmentPos() <= process_end) {
103 process_end = itTransitionEvent->FragmentPos();
104 Stage = (itTransitionEvent->Type == Event::type_release) ? stage_release_init : (InfiniteSustain) ? stage_sustain : stage_decay2_init;
105 ++itTransitionEvent;
106 }
107 else if (to_process == holdstepsleft) Stage = stage_decay1_init;
108 while (iSample < process_end) {
109 pEngine->pSynthesisParameters[ModulationDestination][iSample++] *= Level;
110 }
111 break;
112 }
113 case stage_decay1_init: {
114 if (Decay1StepsLeft) {
115 if (SustainLevel < 1.0) {
116 Decay1StepsLeft = int((RTMath::Max(Decay1Level2, SustainLevel) - Level) / Decay1Coeff);
117 } else {
118 Stage = (InfiniteSustain) ? stage_sustain : stage_decay2_init;
119 break;
120 }
121 } else {
122 Level = SustainLevel;
123 Stage = (InfiniteSustain) ? stage_sustain : stage_decay2_init;
124 break;
125 }
126 Stage = stage_decay1;
127 }
128 case stage_decay1: {
129 int to_process = RTMath::Min(Samples - iSample, Decay1StepsLeft);
130 int process_end = iSample + to_process;
131 if (itTransitionEvent && itTransitionEvent->FragmentPos() <= process_end) {
132 process_end = itTransitionEvent->FragmentPos();
133 Stage = (itTransitionEvent->Type == Event::type_release) ? stage_release_init : (InfiniteSustain) ? stage_sustain : stage_decay2_init;
134 ++itTransitionEvent;
135 }
136 else {
137 Decay1StepsLeft -= to_process;
138 if (!Decay1StepsLeft) Stage = stage_decay1_part2_init;
139 }
140 while (iSample < process_end) {
141 Level += Decay1Coeff;
142 pEngine->pSynthesisParameters[ModulationDestination][iSample++] *= Level;
143 }
144 break;
145 }
146 case stage_decay1_part2_init:
147 Decay1StepsLeft = int(log((SustainLevel - ExpOffset) / (Level - ExpOffset)) / Decay1Slope);
148 Stage = stage_decay1_part2;
149 case stage_decay1_part2: {
150 int to_process = RTMath::Min(Samples - iSample, Decay1StepsLeft);
151 int process_end = iSample + to_process;
152 if (itTransitionEvent && itTransitionEvent->FragmentPos() <= process_end) {
153 process_end = itTransitionEvent->FragmentPos();
154 Stage = (itTransitionEvent->Type == Event::type_release) ? stage_release_init : (InfiniteSustain) ? stage_sustain : stage_decay2_init;
155 ++itTransitionEvent;
156 }
157 else {
158 Decay1StepsLeft -= to_process;
159 if (!Decay1StepsLeft) Stage = (InfiniteSustain) ? stage_sustain : stage_decay2_init;
160 }
161 while (iSample < process_end) {
162 Level = Level * Decay1Coeff2 + Decay1Coeff3;
163 pEngine->pSynthesisParameters[ModulationDestination][iSample++] *= Level;
164 }
165 break;
166 }
167 case stage_decay2_init:
168 Decay2StepsLeft = int((CONFIG_EG_BOTTOM - Level) / Decay2Coeff);
169 Stage = stage_decay2;
170 case stage_decay2: {
171 int to_process = RTMath::Min(Samples - iSample, Decay2StepsLeft);
172 int process_end = iSample + to_process;
173 if (itTransitionEvent && itTransitionEvent->Type == Event::type_release && itTransitionEvent->FragmentPos() <= process_end) {
174 process_end = itTransitionEvent->FragmentPos();
175 ++itTransitionEvent;
176 Stage = stage_release_init; // switch to release stage soon
177 }
178 else {
179 Decay2StepsLeft -= to_process;
180 if (!Decay2StepsLeft) Stage = stage_fadeout;
181 }
182 while (iSample < process_end) {
183 Level += Decay2Coeff;
184 pEngine->pSynthesisParameters[ModulationDestination][iSample++] *= Level;
185 }
186 break;
187 }
188 case stage_sustain: {
189 int process_end;
190 if (itTransitionEvent && itTransitionEvent->Type == Event::type_release && itTransitionEvent->FragmentPos() <= Samples) {
191 process_end = itTransitionEvent->FragmentPos();
192 ++itTransitionEvent;
193 Stage = stage_release_init; // switch to release stage soon
194 }
195 else process_end = Samples;
196 while (iSample < process_end) {
197 pEngine->pSynthesisParameters[ModulationDestination][iSample++] *= Level;
198 }
199 break;
200 }
201 case stage_release_init:
202 ReleaseStepsLeft = int((ReleaseLevel2 - Level) / ReleaseCoeff);
203 Stage = stage_release;
204 case stage_release: {
205 int to_process = RTMath::Min(Samples - iSample, ReleaseStepsLeft);
206 int process_end = iSample + to_process;
207 if (itTransitionEvent && itTransitionEvent->Type == Event::type_cancel_release && itTransitionEvent->FragmentPos() <= process_end) {
208 process_end = itTransitionEvent->FragmentPos();
209 ++itTransitionEvent;
210 Stage = (InfiniteSustain) ? stage_sustain : stage_decay2_init; // switch back to sustain / decay2 stage soon
211 }
212 else {
213 ReleaseStepsLeft -= to_process;
214 if (!ReleaseStepsLeft) Stage = stage_release_part2_init;
215 }
216 while (iSample < process_end) {
217 Level += ReleaseCoeff;
218 pEngine->pSynthesisParameters[ModulationDestination][iSample++] *= Level;
219 }
220 break;
221 }
222 case stage_release_part2_init:
223 ReleaseStepsLeft = int(log((CONFIG_EG_BOTTOM - ExpOffset) / (Level - ExpOffset)) / ReleaseSlope);
224 Stage = stage_release_part2;
225 case stage_release_part2: {
226 int to_process = RTMath::Min(Samples - iSample, ReleaseStepsLeft);
227 int process_end = iSample + to_process;
228 if (itTransitionEvent && itTransitionEvent->Type == Event::type_cancel_release && itTransitionEvent->FragmentPos() <= process_end) {
229 process_end = itTransitionEvent->FragmentPos();
230 ++itTransitionEvent;
231 Stage = (InfiniteSustain) ? stage_sustain : stage_decay2_init; // switch back to sustain / decay2 stage soon
232 }
233 else {
234 ReleaseStepsLeft -= to_process;
235 if (!ReleaseStepsLeft) Stage = stage_fadeout;
236 }
237 while (iSample < process_end) {
238 Level = Level * ReleaseCoeff2 + ReleaseCoeff3;
239 pEngine->pSynthesisParameters[ModulationDestination][iSample++] *= Level;
240 }
241 break;
242 }
243 case stage_fadeout: {
244 int to_process = RTMath::Min(int(Level / (-FadeOutCoeff)), TotalSamples - iSample);
245 int process_end = iSample + to_process;
246 while (iSample < process_end) {
247 Level += FadeOutCoeff;
248 pEngine->pSynthesisParameters[ModulationDestination][iSample++] *= Level;
249 }
250 Stage = stage_end;
251 if (Level > -FadeOutCoeff) dmsg(2,("EGADSR: Warning, final fade out level too high, may result in click sound!\n"));
252 } //Fall through here instead of breaking otherwise we can get back into stage_fadeout and loop forever!
253 case stage_end: {
254 while (iSample < TotalSamples) {
255 pEngine->pSynthesisParameters[ModulationDestination][iSample++] = 0.0f;
256 }
257 break;
258 }
259 }
260 }
261
262 #if CONFIG_DEVMODE
263 if (itKillEvent && Stage != stage_end) { // just a sanity check for debugging
264 dmsg(1,("EGADSR: ERROR, voice killing not completed !!!\n"));
265 dmsg(1,("EGADSR: Stage=%d,iSample=%d,Samples=%d, TotalSamples=%d, MaxFadoutPos=%d\n",Stage,iSample,Samples,TotalSamples,pEngine->MaxFadeOutPos));
266 }
267 #endif // CONFIG_DEVMODE
268 }
269
270 /**
271 * Will be called by the voice when the key / voice was triggered.
272 *
273 * @param PreAttack - Preattack value for the envelope (0 - 1000 permille)
274 * @param AttackTime - Attack time for the envelope (0.000 - 60.000s)
275 * @param HoldAttack - If true, Decay1 will be postponed until the sample reached the sample loop start.
276 * @param LoopStart - Sample position where sample loop starts (if any)
277 * @param Decay1Time - Decay1 time of the sample amplitude EG (0.000 - 60.000s).
278 * @param Decay2Time - Only if !InfiniteSustain: 2nd decay stage time of the sample amplitude EG (0.000 - 60.000s).
279 * @param InfiniteSustain - If true, instead of going into Decay2 phase, Decay1 level will be hold until note will be released.
280 * @param SustainLevel - Sustain level of the sample amplitude EG (0 - 1000 permille).
281 * @param ReleaseTIme - Release time for the envelope (0.000 - 60.000s)
282 * @param Delay - Number of sample points triggering should be delayed.
283 * @param Volume - Volume the sample will be played at (0.0 - 1.0). Used when calculating the exponential curve parameters.
284 */
285 void EGADSR::Trigger(uint PreAttack, double AttackTime, bool HoldAttack, long LoopStart, double Decay1Time, double Decay2Time, bool InfiniteSustain, uint SustainLevel, double ReleaseTime, uint Delay, float Volume) {
286 this->TriggerDelay = Delay;
287 this->Stage = stage_attack;
288 if (SustainLevel) {
289 this->SustainLevel = SustainLevel / 1000.0;
290 } else {
291 // sustain level 0 means that voice dies after decay 1
292 this->SustainLevel = CONFIG_EG_BOTTOM;
293 InfiniteSustain = false;
294 Decay2Time = CONFIG_EG_MIN_RELEASE_TIME;
295 }
296 this->InfiniteSustain = InfiniteSustain;
297 this->HoldAttack = HoldAttack;
298 this->LoopStart = LoopStart;
299 this->ReleasePostponed = false;
300
301 // calculate attack stage parameters (lin. curve)
302
303 // Measurements of GSt output shows that the real attack time
304 // is about 65.5% of the value specified in the gig file.
305 AttackStepsLeft = (long) (0.655 * AttackTime * pEngine->pAudioOutputDevice->SampleRate());
306 if (AttackStepsLeft) {
307 Level = (float) PreAttack / 1000.0;
308 AttackCoeff = 0.896 * (1.0 - Level) / AttackStepsLeft; // max level is a bit lower if attack != 0
309 }
310 else {
311 Level = 1.0;
312 AttackCoeff = 0.0;
313 }
314
315 const float invVolume = 1 / Volume;
316 ExpOffset = (0.25 - 1 / 3.55) * invVolume;
317
318 // The decay1 and release stage both consist of two parts,
319 // first a linear curve, f, followed by an exponential curve,
320 // g:
321 //
322 // f(x + d) = f(x) + Coeff
323 // g(x + d) = Coeff2 * g(x) + Coeff3
324 //
325 // (where d is 1/SampleRate). The transition from f to g is
326 // done when f(x) has reached Level2 = 25% of full volume.
327
328 // calculate decay1 stage parameters (lin+exp curve)
329 Decay1StepsLeft = (long) (Decay1Time * pEngine->pAudioOutputDevice->SampleRate());
330 if (Decay1StepsLeft) {
331 Decay1Slope = 1.365 * (this->SustainLevel - 1.0) / Decay1StepsLeft;
332 Decay1Coeff = Decay1Slope * invVolume;
333 Decay1Slope *= 3.55;
334 Decay1Coeff2 = exp(Decay1Slope);
335 Decay1Coeff3 = ExpOffset * (1 - Decay1Coeff2);
336 Decay1Level2 = 0.25 * invVolume;
337 }
338
339 // calculate decay2 stage parameters (lin. curve)
340 if (!InfiniteSustain) {
341 if (Decay2Time < CONFIG_EG_MIN_RELEASE_TIME) Decay2Time = CONFIG_EG_MIN_RELEASE_TIME;
342 long Decay2Steps = (long) (Decay2Time * pEngine->pAudioOutputDevice->SampleRate());
343 Decay2Coeff = (-1.03 / Decay2Steps) * invVolume;
344 }
345
346 // calculate release stage parameters (lin+exp curve)
347 if (ReleaseTime < CONFIG_EG_MIN_RELEASE_TIME) ReleaseTime = CONFIG_EG_MIN_RELEASE_TIME; // to avoid click sounds at the end of the sample playback
348 ReleaseStepsLeft = (long) (ReleaseTime * pEngine->pAudioOutputDevice->SampleRate());
349 ReleaseSlope = 1.365 * (0 - 1) / ReleaseStepsLeft;
350 ReleaseCoeff = ReleaseSlope * invVolume;
351 ReleaseSlope *= 3.55;
352 ReleaseCoeff2 = exp(ReleaseSlope);
353 ReleaseCoeff3 = ExpOffset * (1 - ReleaseCoeff2);
354 ReleaseLevel2 = 0.25 * invVolume;
355
356 dmsg(4,("PreAttack=%d, AttackLength=%d, AttackCoeff=%f, Decay1Coeff=%f, Decay2Coeff=%f, ReleaseLength=%d, ReleaseCoeff=%f\n",
357 PreAttack, AttackStepsLeft, AttackCoeff, Decay1Coeff, Decay2Coeff, ReleaseStepsLeft, ReleaseCoeff));
358 }
359
360 }} // namespace LinuxSampler::gig

  ViewVC Help
Powered by ViewVC