/[svn]/linuxsampler/tags/v0_1_0/src/eg_vca.cpp
ViewVC logotype

Annotation of /linuxsampler/tags/v0_1_0/src/eg_vca.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 37 - (hide annotations) (download)
Wed Mar 10 22:01:36 2004 UTC (20 years, 2 months ago) by schoenebeck
Original Path: linuxsampler/trunk/src/eg_vca.cpp
File size: 12372 byte(s)
* src/eg_vca.cpp: added following transitions to the envelope generator:
  'Attack_Hold' -> 'Release', 'Decay_1' -> 'Release' in case of a release
  event
* EG1 parameters 'Attack Time', 'Release Time' and 'Sustain Time' are now
  controllable by a MIDI controller defined in the .gig file
* src/voice.cpp: fixed bug in pitch calculation which caused new triggered
  voices to be played back without honoring the current pitch bend value

1 schoenebeck 30 /***************************************************************************
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() {
26     Stage = stage_end;
27     Level = 0.0;
28     }
29    
30     /**
31     * Will be called by the voice for every audio fragment to let the EG
32     * queue it's modulation changes for the current audio fragment.
33 schoenebeck 32 *
34 schoenebeck 33 * @param Samples - total number of sample points to be rendered in this
35     * audio fragment cycle by the audio engine
36     * @param pEvents - event list with "release" and "cancel release" events
37     * @param pTriggerEvent - event that caused triggering of the voice (only if
38     * the voices was triggered in the current audio
39     * fragment, NULL otherwise)
40     * @param SamplePos - current playback position
41     * @param CurrentPitch - current pitch value for playback
42 schoenebeck 30 */
43 schoenebeck 33 void EG_VCA::Process(uint Samples, RTEList<ModulationSystem::Event>* pEvents, ModulationSystem::Event* pTriggerEvent, double SamplePos, double CurrentPitch) {
44 schoenebeck 37 ModulationSystem::Event* pTransitionEvent;
45 schoenebeck 33 if (pTriggerEvent) {
46     pEvents->set_current(pTriggerEvent);
47 schoenebeck 37 pTransitionEvent = pEvents->next();
48 schoenebeck 33 }
49     else {
50 schoenebeck 37 pTransitionEvent = pEvents->first();
51 schoenebeck 33 }
52 schoenebeck 30
53 schoenebeck 32 int iSample = TriggerDelay;
54     while (iSample < Samples) {
55 schoenebeck 30 switch (Stage) {
56     case stage_attack: {
57 schoenebeck 37 TriggerDelay = 0;
58 schoenebeck 33 int to_process = Min(Samples - iSample, AttackStepsLeft);
59     int process_end = iSample + to_process;
60     AttackStepsLeft -= to_process;
61 schoenebeck 32 while (iSample < process_end) {
62 schoenebeck 30 Level += AttackCoeff;
63 schoenebeck 32 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][iSample++] *= Level;
64 schoenebeck 37 }
65 schoenebeck 33 if (iSample == Samples) { // postpone last transition event for the next audio fragment
66     ModulationSystem::Event* pLastEvent = pEvents->last();
67     if (pLastEvent) ReleasePostponed = (pLastEvent->Type == ModulationSystem::event_type_release);
68     }
69 schoenebeck 37 if (!AttackStepsLeft) Stage = (ReleasePostponed) ? stage_release : (HoldAttack) ? stage_attack_hold : stage_decay1;
70 schoenebeck 30 break;
71     }
72 schoenebeck 33 case stage_attack_hold: {
73     if (SamplePos >= LoopStart) {
74     Stage = stage_decay1;
75     break;
76     }
77     int holdstepsleft = (int) (LoopStart - SamplePos / CurrentPitch); // FIXME: just an approximation, inaccuracy grows with higher audio fragment size, sufficient for usual fragment sizes though
78 schoenebeck 37 int to_process = Min(Samples - iSample, holdstepsleft);
79     int process_end = iSample + to_process;
80     if (pTransitionEvent && pTransitionEvent->FragmentPos() <= process_end) {
81     process_end = pTransitionEvent->FragmentPos();
82     Stage = (pTransitionEvent->Type == ModulationSystem::event_type_release) ? stage_release : (InfiniteSustain) ? stage_sustain : stage_decay2;
83     pTransitionEvent = pEvents->next();
84     }
85     else if (to_process == holdstepsleft) Stage = stage_decay1;
86 schoenebeck 33 while (iSample < process_end) {
87     ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][iSample++] *= Level;
88 schoenebeck 37 }
89 schoenebeck 33 break;
90     }
91     case stage_decay1: {
92     int to_process = Min(Samples - iSample, Decay1StepsLeft);
93     int process_end = iSample + to_process;
94 schoenebeck 37 if (pTransitionEvent && pTransitionEvent->FragmentPos() <= process_end) {
95     process_end = pTransitionEvent->FragmentPos();
96     Stage = (pTransitionEvent->Type == ModulationSystem::event_type_release) ? stage_release : (InfiniteSustain) ? stage_sustain : stage_decay2;
97     pTransitionEvent = pEvents->next();
98     }
99     else {
100     Decay1StepsLeft -= to_process;
101     if (!Decay1StepsLeft) Stage = (InfiniteSustain) ? stage_sustain : stage_decay2;
102     }
103 schoenebeck 33 while (iSample < process_end) {
104     Level += Decay1Coeff;
105     ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][iSample++] *= Level;
106 schoenebeck 37 }
107 schoenebeck 33 break;
108     }
109     case stage_decay2: {
110     int process_end;
111 schoenebeck 37 if (pTransitionEvent && pTransitionEvent->Type == ModulationSystem::event_type_release) {
112     process_end = pTransitionEvent->FragmentPos();
113     pTransitionEvent = pEvents->next();
114     Stage = stage_release; // switch to release stage soon
115 schoenebeck 33 }
116     else process_end = Samples;
117     while (iSample < process_end) {
118     Level += Level * Decay2Coeff;
119     ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][iSample++] *= Level;
120     }
121     if (Level <= EG_ENVELOPE_LIMIT) Stage = stage_end;
122     break;
123     }
124 schoenebeck 30 case stage_sustain: {
125 schoenebeck 33 int process_end;
126 schoenebeck 37 if (pTransitionEvent && pTransitionEvent->Type == ModulationSystem::event_type_release) {
127     process_end = pTransitionEvent->FragmentPos();
128     pTransitionEvent = pEvents->next();
129     Stage = stage_release; // switch to release stage soon
130 schoenebeck 33 }
131     else process_end = Samples;
132     while (iSample < process_end) {
133     ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][iSample++] *= Level;
134     }
135 schoenebeck 32 break;
136 schoenebeck 30 }
137     case stage_release: {
138 schoenebeck 33 int process_end;
139 schoenebeck 37 if (pTransitionEvent && pTransitionEvent->Type == ModulationSystem::event_type_cancel_release) {
140     process_end = pTransitionEvent->FragmentPos();
141     pTransitionEvent = pEvents->next();
142     Stage = (InfiniteSustain) ? stage_sustain : stage_decay2; // switch back to sustain / decay2 stage soon
143 schoenebeck 33 }
144     else process_end = Samples;
145     while (iSample < process_end) {
146     Level += Level * ReleaseCoeff;
147 schoenebeck 32 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][iSample++] *= Level;
148 schoenebeck 30 }
149     if (Level <= EG_ENVELOPE_LIMIT) Stage = stage_end;
150 schoenebeck 33 break;
151 schoenebeck 30 }
152     case stage_end: {
153 schoenebeck 32 while (iSample < Samples) {
154 schoenebeck 33 Level += Level * ReleaseCoeff;
155 schoenebeck 32 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][iSample++] *= Level;
156 schoenebeck 30 }
157 schoenebeck 33 break;
158 schoenebeck 30 }
159     }
160     }
161     }
162    
163     /**
164     * Will be called by the voice when the key / voice was triggered.
165     *
166 schoenebeck 33 * @param PreAttack - Preattack value for the envelope (0 - 1000 permille)
167     * @param AttackTime - Attack time for the envelope (0.000 - 60.000s)
168     * @param HoldAttack - If true, Decay1 will be postponed until the sample reached the sample loop start.
169     * @param LoopStart - Sample position where sample loop starts (if any)
170     * @param Decay1Time - Decay1 time of the sample amplitude EG (0.000 - 60.000s).
171     * @param Decay2Time - Only if !InfiniteSustain: 2nd decay stage time of the sample amplitude EG (0.000 - 60.000s).
172     * @param InfiniteSustain - If true, instead of going into Decay2 phase, Decay1 level will be hold until note will be released.
173     * @param SustainLevel - Sustain level of the sample amplitude EG (0 - 1000 permille).
174     * @param ReleaseTIme - Release time for the envelope (0.000 - 60.000s)
175     * @param Delay - Number of sample points triggering should be delayed.
176 schoenebeck 30 */
177 schoenebeck 33 void EG_VCA::Trigger(uint PreAttack, double AttackTime, bool HoldAttack, long LoopStart, double Decay1Time, double Decay2Time, bool InfiniteSustain, uint SustainLevel, double ReleaseTime, uint Delay) {
178     this->TriggerDelay = Delay;
179     this->Stage = stage_attack;
180     this->SustainLevel = (SustainLevel) ? (SustainLevel > EG_ENVELOPE_LIMIT) ? (float) SustainLevel / 1000.0 : EG_ENVELOPE_LIMIT : 1.0;
181     this->InfiniteSustain = InfiniteSustain;
182     this->HoldAttack = HoldAttack;
183     this->LoopStart = LoopStart;
184     this->ReleasePostponed = false;
185 schoenebeck 30
186 schoenebeck 33 // calculate attack stage parameters (lin. curve)
187 schoenebeck 32 AttackStepsLeft = (long) (AttackTime * ModulationSystem::SampleRate());
188 schoenebeck 30 if (AttackStepsLeft) {
189 schoenebeck 33 Level = (float) PreAttack / 1000.0;
190     AttackCoeff = (1.0 - Level) / AttackStepsLeft;
191 schoenebeck 30 }
192     else {
193     Level = 1.0;
194     AttackCoeff = 0.0;
195     }
196    
197 schoenebeck 33 // calculate decay1 stage parameters (lin. curve)
198     Decay1StepsLeft = (long) (Decay1Time * ModulationSystem::SampleRate());
199     Decay1Coeff = (Decay1StepsLeft) ? (this->SustainLevel - 1.0) / Decay1StepsLeft : 0.0;
200    
201     // calculate decay2 stage parameters (exp. curve)
202     if (!InfiniteSustain) {
203     if (Decay2Time < EG_MIN_RELEASE_TIME) Decay2Time = EG_MIN_RELEASE_TIME;
204     long Decay2Steps = (long) (Decay2Time * ModulationSystem::SampleRate());
205     Decay2Coeff = (Decay2Steps) ? exp((log(EG_ENVELOPE_LIMIT) - log(this->SustainLevel)) / Decay2Steps + log(this->SustainLevel)) - this->SustainLevel
206     : 0.0;
207     }
208    
209     // calcuate release stage parameters (exp. curve)
210 schoenebeck 30 if (ReleaseTime < EG_MIN_RELEASE_TIME) ReleaseTime = EG_MIN_RELEASE_TIME; // to avoid click sounds at the end of the sample playback
211 schoenebeck 32 ReleaseStepsLeft = (long) (ReleaseTime * ModulationSystem::SampleRate());
212 schoenebeck 33 //ReleaseCoeff = exp(log(EG_ENVELOPE_LIMIT) / (double) ReleaseStepsLeft) - 1.0; // <- this is only accurate for a curve start level of exactly 1.0, otherwise we have to use the following calculation for the coefficient...
213     ReleaseCoeff = exp((log(EG_ENVELOPE_LIMIT) - log(this->SustainLevel)) / ReleaseStepsLeft + log(this->SustainLevel)) - this->SustainLevel;
214 schoenebeck 30
215 schoenebeck 33 dmsg(4,("PreAttack=%d, AttackLength=%d, AttackCoeff=%f, Decay1Coeff=%f, Decay2Coeff=%f, ReleaseLength=%d, ReleaseCoeff=%f\n",
216     PreAttack, AttackStepsLeft, AttackCoeff, Decay1Coeff, Decay2Coeff, ReleaseStepsLeft, ReleaseCoeff));
217 schoenebeck 30 }

  ViewVC Help
Powered by ViewVC