/[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 563 - (show annotations) (download)
Sun May 22 20:43:32 2005 UTC (18 years, 10 months ago) by schoenebeck
File size: 15175 byte(s)
* (re)implemented voice stealing algorithm "oldestvoiceonkey" and made it
  the default voice stealing algorithm
* added new LSCP command "GET SERVER INFO" which currently returns
  description and version about this sampler
* added some API documentation comments
* minor cleanup

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 : (HoldAttack) ? stage_attack_hold : stage_decay1;
94 break;
95 }
96 case stage_attack_hold: {
97 if (SamplePos >= LoopStart) {
98 Stage = stage_decay1;
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 : (InfiniteSustain) ? stage_sustain : stage_decay2;
107 ++itTransitionEvent;
108 }
109 else if (to_process == holdstepsleft) Stage = stage_decay1;
110 while (iSample < process_end) {
111 pEngine->pSynthesisParameters[ModulationDestination][iSample++] *= Level;
112 }
113 break;
114 }
115 case stage_decay1: {
116 int to_process = RTMath::Min(Samples - iSample, Decay1StepsLeft);
117 int process_end = iSample + to_process;
118 if (itTransitionEvent && itTransitionEvent->FragmentPos() <= process_end) {
119 process_end = itTransitionEvent->FragmentPos();
120 Stage = (itTransitionEvent->Type == Event::type_release) ? stage_release : (InfiniteSustain) ? stage_sustain : stage_decay2;
121 ++itTransitionEvent;
122 }
123 else {
124 Decay1StepsLeft -= to_process;
125 if (!Decay1StepsLeft) Stage = (InfiniteSustain) ? stage_sustain : stage_decay2;
126 }
127 while (iSample < process_end) {
128 Level += Level * Decay1Coeff;
129 pEngine->pSynthesisParameters[ModulationDestination][iSample++] *= Level;
130 }
131 break;
132 }
133 case stage_decay2: {
134 int process_end;
135 if (itTransitionEvent && itTransitionEvent->Type == Event::type_release && itTransitionEvent->FragmentPos() <= Samples) {
136 process_end = itTransitionEvent->FragmentPos();
137 ++itTransitionEvent;
138 Stage = stage_release; // switch to release stage soon
139 }
140 else process_end = Samples;
141 while (iSample < process_end) {
142 Level += Level * Decay2Coeff;
143 pEngine->pSynthesisParameters[ModulationDestination][iSample++] *= Level;
144 }
145 if (Level <= CONFIG_EG_BOTTOM) Stage = stage_fadeout;
146 break;
147 }
148 case stage_sustain: {
149 int process_end;
150 if (itTransitionEvent && itTransitionEvent->Type == Event::type_release && itTransitionEvent->FragmentPos() <= Samples) {
151 process_end = itTransitionEvent->FragmentPos();
152 ++itTransitionEvent;
153 Stage = stage_release; // switch to release stage soon
154 }
155 else process_end = Samples;
156 while (iSample < process_end) {
157 pEngine->pSynthesisParameters[ModulationDestination][iSample++] *= Level;
158 }
159 break;
160 }
161 case stage_release: {
162 int process_end;
163 if (itTransitionEvent && itTransitionEvent->Type == Event::type_cancel_release && itTransitionEvent->FragmentPos() <= Samples) {
164 process_end = itTransitionEvent->FragmentPos();
165 ++itTransitionEvent;
166 Stage = (InfiniteSustain) ? stage_sustain : stage_decay2; // switch back to sustain / decay2 stage soon
167 }
168 else process_end = Samples;
169 while (iSample < process_end) {
170 Level += Level * ReleaseCoeff;
171 pEngine->pSynthesisParameters[ModulationDestination][iSample++] *= Level;
172 }
173 if (Level <= CONFIG_EG_BOTTOM) Stage = stage_fadeout;
174 break;
175 }
176 case stage_fadeout: {
177 int to_process = RTMath::Min(int(Level / (-FadeOutCoeff)), TotalSamples - iSample);
178 int process_end = iSample + to_process;
179 while (iSample < process_end) {
180 Level += FadeOutCoeff;
181 pEngine->pSynthesisParameters[ModulationDestination][iSample++] *= Level;
182 }
183 Stage = stage_end;
184 if (Level > -FadeOutCoeff) dmsg(1,("EGADSR: Warning, final fade out level too high, may result in click sound!\n"));
185 } //Fall through here instead of breaking otherwise we can get back into stage_fadeout and loop forever!
186 case stage_end: {
187 while (iSample < TotalSamples) {
188 pEngine->pSynthesisParameters[ModulationDestination][iSample++] = 0.0f;
189 }
190 break;
191 }
192 }
193 }
194
195 #if CONFIG_DEVMODE
196 if (itKillEvent && Stage != stage_end) { // just a sanity check for debugging
197 dmsg(1,("EGADSR: ERROR, voice killing not completed !!!\n"));
198 dmsg(1,("EGADSR: Stage=%d,iSample=%d,Samples=%d, TotalSamples=%d, MaxFadoutPos=%d\n",Stage,iSample,Samples,TotalSamples,pEngine->MaxFadeOutPos));
199 }
200 #endif // CONFIG_DEVMODE
201 }
202
203 /**
204 * Will be called by the voice when the key / voice was triggered.
205 *
206 * @param PreAttack - Preattack value for the envelope (0 - 1000 permille)
207 * @param AttackTime - Attack time for the envelope (0.000 - 60.000s)
208 * @param HoldAttack - If true, Decay1 will be postponed until the sample reached the sample loop start.
209 * @param LoopStart - Sample position where sample loop starts (if any)
210 * @param Decay1Time - Decay1 time of the sample amplitude EG (0.000 - 60.000s).
211 * @param Decay2Time - Only if !InfiniteSustain: 2nd decay stage time of the sample amplitude EG (0.000 - 60.000s).
212 * @param InfiniteSustain - If true, instead of going into Decay2 phase, Decay1 level will be hold until note will be released.
213 * @param SustainLevel - Sustain level of the sample amplitude EG (0 - 1000 permille).
214 * @param ReleaseTIme - Release time for the envelope (0.000 - 60.000s)
215 * @param Delay - Number of sample points triggering should be delayed.
216 */
217 void EGADSR::Trigger(uint PreAttack, double AttackTime, bool HoldAttack, long LoopStart, double Decay1Time, double Decay2Time, bool InfiniteSustain, uint SustainLevel, double ReleaseTime, uint Delay) {
218 this->TriggerDelay = Delay;
219 this->Stage = stage_attack;
220 this->SustainLevel = (SustainLevel) ? (SustainLevel > CONFIG_EG_BOTTOM) ? (float) SustainLevel / 1000.0 : CONFIG_EG_BOTTOM : 1.0;
221 this->InfiniteSustain = InfiniteSustain;
222 this->HoldAttack = HoldAttack;
223 this->LoopStart = LoopStart;
224 this->ReleasePostponed = false;
225
226 // calculate attack stage parameters (lin. curve)
227 AttackStepsLeft = (long) (AttackTime * pEngine->pAudioOutputDevice->SampleRate());
228 if (AttackStepsLeft) {
229 Level = (float) PreAttack / 1000.0;
230 AttackCoeff = (1.0 - Level) / AttackStepsLeft;
231 }
232 else {
233 Level = 1.0;
234 AttackCoeff = 0.0;
235 }
236
237 // calculate decay1 stage parameters (exp. curve)
238 Decay1StepsLeft = (long) (Decay1Time * pEngine->pAudioOutputDevice->SampleRate());
239 Decay1Coeff = (Decay1StepsLeft) ? exp(log(this->SustainLevel) / (double) Decay1StepsLeft) - 1.0
240 : 0.0;
241
242 // calculate decay2 stage parameters (exp. curve)
243 if (!InfiniteSustain) {
244 if (Decay2Time < CONFIG_EG_MIN_RELEASE_TIME) Decay2Time = CONFIG_EG_MIN_RELEASE_TIME;
245 long Decay2Steps = (long) (Decay2Time * pEngine->pAudioOutputDevice->SampleRate());
246 Decay2Coeff = (Decay2Steps) ? exp((log(CONFIG_EG_BOTTOM) - log(this->SustainLevel)) / Decay2Steps + log(this->SustainLevel)) - this->SustainLevel
247 : 0.0;
248 }
249
250 // calculate release stage parameters (exp. curve)
251 if (ReleaseTime < CONFIG_EG_MIN_RELEASE_TIME) ReleaseTime = CONFIG_EG_MIN_RELEASE_TIME; // to avoid click sounds at the end of the sample playback
252 ReleaseStepsLeft = (long) (ReleaseTime * pEngine->pAudioOutputDevice->SampleRate());
253 ReleaseCoeff = exp((log(CONFIG_EG_BOTTOM) - log(this->SustainLevel)) / ReleaseStepsLeft + log(this->SustainLevel)) - this->SustainLevel;
254
255 dmsg(4,("PreAttack=%d, AttackLength=%d, AttackCoeff=%f, Decay1Coeff=%f, Decay2Coeff=%f, ReleaseLength=%d, ReleaseCoeff=%f\n",
256 PreAttack, AttackStepsLeft, AttackCoeff, Decay1Coeff, Decay2Coeff, ReleaseStepsLeft, ReleaseCoeff));
257 }
258
259 }} // namespace LinuxSampler::gig

  ViewVC Help
Powered by ViewVC