/[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 44 - (hide annotations) (download)
Sun Apr 11 17:25:40 2004 UTC (20 years, 1 month ago) by (unknown author)
File size: 12033 byte(s)
This commit was manufactured by cvs2svn to create tag 'v0_1_0'.
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 schoenebeck 40 EG_VCA::EG_VCA(ModulationSystem::destination_t ModulationDestination) {
26     this->ModulationDestination = ModulationDestination;
27 schoenebeck 30 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 schoenebeck 32 *
35 schoenebeck 33 * @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 schoenebeck 30 */
44 schoenebeck 33 void EG_VCA::Process(uint Samples, RTEList<ModulationSystem::Event>* pEvents, ModulationSystem::Event* pTriggerEvent, double SamplePos, double CurrentPitch) {
45 schoenebeck 37 ModulationSystem::Event* pTransitionEvent;
46 schoenebeck 33 if (pTriggerEvent) {
47     pEvents->set_current(pTriggerEvent);
48 schoenebeck 37 pTransitionEvent = pEvents->next();
49 schoenebeck 33 }
50     else {
51 schoenebeck 37 pTransitionEvent = pEvents->first();
52 schoenebeck 33 }
53 schoenebeck 30
54 schoenebeck 32 int iSample = TriggerDelay;
55     while (iSample < Samples) {
56 schoenebeck 30 switch (Stage) {
57     case stage_attack: {
58 schoenebeck 37 TriggerDelay = 0;
59 schoenebeck 33 int to_process = Min(Samples - iSample, AttackStepsLeft);
60     int process_end = iSample + to_process;
61     AttackStepsLeft -= to_process;
62 schoenebeck 32 while (iSample < process_end) {
63 schoenebeck 30 Level += AttackCoeff;
64 schoenebeck 40 ModulationSystem::pDestinationParameter[ModulationDestination][iSample++] *= Level;
65     }
66 schoenebeck 33 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 schoenebeck 37 if (!AttackStepsLeft) Stage = (ReleasePostponed) ? stage_release : (HoldAttack) ? stage_attack_hold : stage_decay1;
71 schoenebeck 30 break;
72     }
73 schoenebeck 33 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 schoenebeck 40 int to_process = Min(Samples - iSample, holdstepsleft);
80     int process_end = iSample + to_process;
81 schoenebeck 37 if (pTransitionEvent && pTransitionEvent->FragmentPos() <= process_end) {
82 schoenebeck 40 process_end = pTransitionEvent->FragmentPos();
83 schoenebeck 37 Stage = (pTransitionEvent->Type == ModulationSystem::event_type_release) ? stage_release : (InfiniteSustain) ? stage_sustain : stage_decay2;
84     pTransitionEvent = pEvents->next();
85     }
86 schoenebeck 40 else if (to_process == holdstepsleft) Stage = stage_decay1;
87 schoenebeck 33 while (iSample < process_end) {
88 schoenebeck 40 ModulationSystem::pDestinationParameter[ModulationDestination][iSample++] *= Level;
89     }
90 schoenebeck 33 break;
91     }
92     case stage_decay1: {
93     int to_process = Min(Samples - iSample, Decay1StepsLeft);
94     int process_end = iSample + to_process;
95 schoenebeck 37 if (pTransitionEvent && pTransitionEvent->FragmentPos() <= process_end) {
96 schoenebeck 40 process_end = pTransitionEvent->FragmentPos();
97 schoenebeck 37 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 schoenebeck 33 while (iSample < process_end) {
105 schoenebeck 38 Level += Level * Decay1Coeff;
106 schoenebeck 40 ModulationSystem::pDestinationParameter[ModulationDestination][iSample++] *= Level;
107     }
108 schoenebeck 33 break;
109     }
110     case stage_decay2: {
111     int process_end;
112 schoenebeck 37 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 schoenebeck 33 }
117     else process_end = Samples;
118     while (iSample < process_end) {
119     Level += Level * Decay2Coeff;
120 schoenebeck 40 ModulationSystem::pDestinationParameter[ModulationDestination][iSample++] *= Level;
121 schoenebeck 33 }
122     if (Level <= EG_ENVELOPE_LIMIT) Stage = stage_end;
123     break;
124     }
125 schoenebeck 30 case stage_sustain: {
126 schoenebeck 33 int process_end;
127 schoenebeck 37 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 schoenebeck 33 }
132     else process_end = Samples;
133     while (iSample < process_end) {
134 schoenebeck 40 ModulationSystem::pDestinationParameter[ModulationDestination][iSample++] *= Level;
135 schoenebeck 33 }
136 schoenebeck 32 break;
137 schoenebeck 30 }
138     case stage_release: {
139 schoenebeck 33 int process_end;
140 schoenebeck 37 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 schoenebeck 33 }
145     else process_end = Samples;
146     while (iSample < process_end) {
147     Level += Level * ReleaseCoeff;
148 schoenebeck 40 ModulationSystem::pDestinationParameter[ModulationDestination][iSample++] *= Level;
149 schoenebeck 30 }
150     if (Level <= EG_ENVELOPE_LIMIT) Stage = stage_end;
151 schoenebeck 33 break;
152 schoenebeck 30 }
153     case stage_end: {
154 schoenebeck 32 while (iSample < Samples) {
155 schoenebeck 33 Level += Level * ReleaseCoeff;
156 schoenebeck 40 ModulationSystem::pDestinationParameter[ModulationDestination][iSample++] *= Level;
157 schoenebeck 30 }
158 schoenebeck 33 break;
159 schoenebeck 30 }
160     }
161     }
162     }
163    
164     /**
165     * Will be called by the voice when the key / voice was triggered.
166     *
167 schoenebeck 33 * @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 schoenebeck 30 */
178 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) {
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 schoenebeck 30
187 schoenebeck 33 // calculate attack stage parameters (lin. curve)
188 schoenebeck 32 AttackStepsLeft = (long) (AttackTime * ModulationSystem::SampleRate());
189 schoenebeck 30 if (AttackStepsLeft) {
190 schoenebeck 33 Level = (float) PreAttack / 1000.0;
191     AttackCoeff = (1.0 - Level) / AttackStepsLeft;
192 schoenebeck 30 }
193     else {
194     Level = 1.0;
195     AttackCoeff = 0.0;
196     }
197    
198 schoenebeck 38 // calculate decay1 stage parameters (exp. curve)
199 schoenebeck 33 Decay1StepsLeft = (long) (Decay1Time * ModulationSystem::SampleRate());
200 schoenebeck 38 Decay1Coeff = (Decay1StepsLeft) ? exp(log(this->SustainLevel) / (double) Decay1StepsLeft) - 1.0
201     : 0.0;
202 schoenebeck 33
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 schoenebeck 30 if (ReleaseTime < EG_MIN_RELEASE_TIME) ReleaseTime = EG_MIN_RELEASE_TIME; // to avoid click sounds at the end of the sample playback
213 schoenebeck 32 ReleaseStepsLeft = (long) (ReleaseTime * ModulationSystem::SampleRate());
214 schoenebeck 33 ReleaseCoeff = exp((log(EG_ENVELOPE_LIMIT) - log(this->SustainLevel)) / ReleaseStepsLeft + log(this->SustainLevel)) - this->SustainLevel;
215 schoenebeck 30
216 schoenebeck 33 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 schoenebeck 30 }

  ViewVC Help
Powered by ViewVC