/[svn]/linuxsampler/trunk/src/eg_vca.cpp
ViewVC logotype

Contents of /linuxsampler/trunk/src/eg_vca.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 40 - (show annotations) (download)
Tue Mar 30 13:14:58 2004 UTC (20 years ago) by schoenebeck
File size: 12033 byte(s)
* added Envelope Generator 2 and 3 (filter cutoff EG and pitch EG) for
  accurate .gig playback
* fixed accuracy of pitch calculation
* changed filter cutoff range to 100Hz..10kHz with exponential curve, this
  value range can also be adjusted on compile time by setting
  FILTER_CUTOFF_MIN and FILTER_CUTOFF_MAX in src/voice.h to desired
  frequencies
* src/lfo.h: lfo is now generalized to a C++ template, which will be useful
  especially when we implement further engines

1 /***************************************************************************
2 * *
3 * LinuxSampler - modular, streaming capable sampler *
4 * *
5 * Copyright (C) 2003 by Benno Senoner and Christian Schoenebeck *
6 * *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program; if not, write to the Free Software *
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
20 * MA 02111-1307 USA *
21 ***************************************************************************/
22
23 #include "eg_vca.h"
24
25 EG_VCA::EG_VCA(ModulationSystem::destination_t ModulationDestination) {
26 this->ModulationDestination = ModulationDestination;
27 Stage = stage_end;
28 Level = 0.0;
29 }
30
31 /**
32 * Will be called by the voice for every audio fragment to let the EG
33 * queue it's modulation changes for the current audio fragment.
34 *
35 * @param Samples - total number of sample points to be rendered in this
36 * audio fragment cycle by the audio engine
37 * @param pEvents - event list with "release" and "cancel release" events
38 * @param pTriggerEvent - event that caused triggering of the voice (only if
39 * the voices was triggered in the current audio
40 * fragment, NULL otherwise)
41 * @param SamplePos - current playback position
42 * @param CurrentPitch - current pitch value for playback
43 */
44 void EG_VCA::Process(uint Samples, RTEList<ModulationSystem::Event>* pEvents, ModulationSystem::Event* pTriggerEvent, double SamplePos, double CurrentPitch) {
45 ModulationSystem::Event* pTransitionEvent;
46 if (pTriggerEvent) {
47 pEvents->set_current(pTriggerEvent);
48 pTransitionEvent = pEvents->next();
49 }
50 else {
51 pTransitionEvent = pEvents->first();
52 }
53
54 int iSample = TriggerDelay;
55 while (iSample < Samples) {
56 switch (Stage) {
57 case stage_attack: {
58 TriggerDelay = 0;
59 int to_process = Min(Samples - iSample, AttackStepsLeft);
60 int process_end = iSample + to_process;
61 AttackStepsLeft -= to_process;
62 while (iSample < process_end) {
63 Level += AttackCoeff;
64 ModulationSystem::pDestinationParameter[ModulationDestination][iSample++] *= Level;
65 }
66 if (iSample == Samples) { // postpone last transition event for the next audio fragment
67 ModulationSystem::Event* pLastEvent = pEvents->last();
68 if (pLastEvent) ReleasePostponed = (pLastEvent->Type == ModulationSystem::event_type_release);
69 }
70 if (!AttackStepsLeft) Stage = (ReleasePostponed) ? stage_release : (HoldAttack) ? stage_attack_hold : stage_decay1;
71 break;
72 }
73 case stage_attack_hold: {
74 if (SamplePos >= LoopStart) {
75 Stage = stage_decay1;
76 break;
77 }
78 int holdstepsleft = (int) (LoopStart - SamplePos / CurrentPitch); // FIXME: just an approximation, inaccuracy grows with higher audio fragment size, sufficient for usual fragment sizes though
79 int to_process = Min(Samples - iSample, holdstepsleft);
80 int process_end = iSample + to_process;
81 if (pTransitionEvent && pTransitionEvent->FragmentPos() <= process_end) {
82 process_end = pTransitionEvent->FragmentPos();
83 Stage = (pTransitionEvent->Type == ModulationSystem::event_type_release) ? stage_release : (InfiniteSustain) ? stage_sustain : stage_decay2;
84 pTransitionEvent = pEvents->next();
85 }
86 else if (to_process == holdstepsleft) Stage = stage_decay1;
87 while (iSample < process_end) {
88 ModulationSystem::pDestinationParameter[ModulationDestination][iSample++] *= Level;
89 }
90 break;
91 }
92 case stage_decay1: {
93 int to_process = Min(Samples - iSample, Decay1StepsLeft);
94 int process_end = iSample + to_process;
95 if (pTransitionEvent && pTransitionEvent->FragmentPos() <= process_end) {
96 process_end = pTransitionEvent->FragmentPos();
97 Stage = (pTransitionEvent->Type == ModulationSystem::event_type_release) ? stage_release : (InfiniteSustain) ? stage_sustain : stage_decay2;
98 pTransitionEvent = pEvents->next();
99 }
100 else {
101 Decay1StepsLeft -= to_process;
102 if (!Decay1StepsLeft) Stage = (InfiniteSustain) ? stage_sustain : stage_decay2;
103 }
104 while (iSample < process_end) {
105 Level += Level * Decay1Coeff;
106 ModulationSystem::pDestinationParameter[ModulationDestination][iSample++] *= Level;
107 }
108 break;
109 }
110 case stage_decay2: {
111 int process_end;
112 if (pTransitionEvent && pTransitionEvent->Type == ModulationSystem::event_type_release) {
113 process_end = pTransitionEvent->FragmentPos();
114 pTransitionEvent = pEvents->next();
115 Stage = stage_release; // switch to release stage soon
116 }
117 else process_end = Samples;
118 while (iSample < process_end) {
119 Level += Level * Decay2Coeff;
120 ModulationSystem::pDestinationParameter[ModulationDestination][iSample++] *= Level;
121 }
122 if (Level <= EG_ENVELOPE_LIMIT) Stage = stage_end;
123 break;
124 }
125 case stage_sustain: {
126 int process_end;
127 if (pTransitionEvent && pTransitionEvent->Type == ModulationSystem::event_type_release) {
128 process_end = pTransitionEvent->FragmentPos();
129 pTransitionEvent = pEvents->next();
130 Stage = stage_release; // switch to release stage soon
131 }
132 else process_end = Samples;
133 while (iSample < process_end) {
134 ModulationSystem::pDestinationParameter[ModulationDestination][iSample++] *= Level;
135 }
136 break;
137 }
138 case stage_release: {
139 int process_end;
140 if (pTransitionEvent && pTransitionEvent->Type == ModulationSystem::event_type_cancel_release) {
141 process_end = pTransitionEvent->FragmentPos();
142 pTransitionEvent = pEvents->next();
143 Stage = (InfiniteSustain) ? stage_sustain : stage_decay2; // switch back to sustain / decay2 stage soon
144 }
145 else process_end = Samples;
146 while (iSample < process_end) {
147 Level += Level * ReleaseCoeff;
148 ModulationSystem::pDestinationParameter[ModulationDestination][iSample++] *= Level;
149 }
150 if (Level <= EG_ENVELOPE_LIMIT) Stage = stage_end;
151 break;
152 }
153 case stage_end: {
154 while (iSample < Samples) {
155 Level += Level * ReleaseCoeff;
156 ModulationSystem::pDestinationParameter[ModulationDestination][iSample++] *= Level;
157 }
158 break;
159 }
160 }
161 }
162 }
163
164 /**
165 * Will be called by the voice when the key / voice was triggered.
166 *
167 * @param PreAttack - Preattack value for the envelope (0 - 1000 permille)
168 * @param AttackTime - Attack time for the envelope (0.000 - 60.000s)
169 * @param HoldAttack - If true, Decay1 will be postponed until the sample reached the sample loop start.
170 * @param LoopStart - Sample position where sample loop starts (if any)
171 * @param Decay1Time - Decay1 time of the sample amplitude EG (0.000 - 60.000s).
172 * @param Decay2Time - Only if !InfiniteSustain: 2nd decay stage time of the sample amplitude EG (0.000 - 60.000s).
173 * @param InfiniteSustain - If true, instead of going into Decay2 phase, Decay1 level will be hold until note will be released.
174 * @param SustainLevel - Sustain level of the sample amplitude EG (0 - 1000 permille).
175 * @param ReleaseTIme - Release time for the envelope (0.000 - 60.000s)
176 * @param Delay - Number of sample points triggering should be delayed.
177 */
178 void EG_VCA::Trigger(uint PreAttack, double AttackTime, bool HoldAttack, long LoopStart, double Decay1Time, double Decay2Time, bool InfiniteSustain, uint SustainLevel, double ReleaseTime, uint Delay) {
179 this->TriggerDelay = Delay;
180 this->Stage = stage_attack;
181 this->SustainLevel = (SustainLevel) ? (SustainLevel > EG_ENVELOPE_LIMIT) ? (float) SustainLevel / 1000.0 : EG_ENVELOPE_LIMIT : 1.0;
182 this->InfiniteSustain = InfiniteSustain;
183 this->HoldAttack = HoldAttack;
184 this->LoopStart = LoopStart;
185 this->ReleasePostponed = false;
186
187 // calculate attack stage parameters (lin. curve)
188 AttackStepsLeft = (long) (AttackTime * ModulationSystem::SampleRate());
189 if (AttackStepsLeft) {
190 Level = (float) PreAttack / 1000.0;
191 AttackCoeff = (1.0 - Level) / AttackStepsLeft;
192 }
193 else {
194 Level = 1.0;
195 AttackCoeff = 0.0;
196 }
197
198 // calculate decay1 stage parameters (exp. curve)
199 Decay1StepsLeft = (long) (Decay1Time * ModulationSystem::SampleRate());
200 Decay1Coeff = (Decay1StepsLeft) ? exp(log(this->SustainLevel) / (double) Decay1StepsLeft) - 1.0
201 : 0.0;
202
203 // calculate decay2 stage parameters (exp. curve)
204 if (!InfiniteSustain) {
205 if (Decay2Time < EG_MIN_RELEASE_TIME) Decay2Time = EG_MIN_RELEASE_TIME;
206 long Decay2Steps = (long) (Decay2Time * ModulationSystem::SampleRate());
207 Decay2Coeff = (Decay2Steps) ? exp((log(EG_ENVELOPE_LIMIT) - log(this->SustainLevel)) / Decay2Steps + log(this->SustainLevel)) - this->SustainLevel
208 : 0.0;
209 }
210
211 // calcuate release stage parameters (exp. curve)
212 if (ReleaseTime < EG_MIN_RELEASE_TIME) ReleaseTime = EG_MIN_RELEASE_TIME; // to avoid click sounds at the end of the sample playback
213 ReleaseStepsLeft = (long) (ReleaseTime * ModulationSystem::SampleRate());
214 ReleaseCoeff = exp((log(EG_ENVELOPE_LIMIT) - log(this->SustainLevel)) / ReleaseStepsLeft + log(this->SustainLevel)) - this->SustainLevel;
215
216 dmsg(4,("PreAttack=%d, AttackLength=%d, AttackCoeff=%f, Decay1Coeff=%f, Decay2Coeff=%f, ReleaseLength=%d, ReleaseCoeff=%f\n",
217 PreAttack, AttackStepsLeft, AttackCoeff, Decay1Coeff, Decay2Coeff, ReleaseStepsLeft, ReleaseCoeff));
218 }

  ViewVC Help
Powered by ViewVC