/[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 614 - (show annotations) (download)
Mon Jun 6 16:54:20 2005 UTC (18 years, 10 months ago) by persson
File size: 20402 byte(s)
* support for the gig parameters for "release velocity response"
  curves, which means the decay and release times now depends on
  velocity. The softer velocity, the longer release.
* fine tuning of the envelope curves. Decay1 and release now have two
  parts, first linear and then exponential at the end.

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

  ViewVC Help
Powered by ViewVC