/[svn]/linuxsampler/trunk/src/lfo.h
ViewVC logotype

Contents of /linuxsampler/trunk/src/lfo.h

Parent Directory Parent Directory | Revision Log Revision Log


Revision 40 - (show annotations) (download) (as text)
Tue Mar 30 13:14:58 2004 UTC (20 years ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 13075 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 #ifndef __LFO_H__
24 #define __LFO_H__
25
26 #include "global.h"
27 #include "rtmath.h"
28 #include "rtelmemorypool.h"
29 #include "modulationsystem.h"
30 #include "gig.h"
31
32 /**
33 * Low Frequency Oscillator
34 *
35 * Synthesizes a triangular wave for arbitrary usage. This LFO class is a
36 * generalization; it takes a class as template parameter (T_Manipulator)
37 * which is actually responsible to do something with the wave levels of the
38 * oscillator. The class given with T_Manipulator has to provide a
39 *
40 * void ApplyLevel(float Level, int iSample);
41 *
42 * method. This method will be called by the LFO whenever the level of the
43 * oscillator wave changes, where parameter 'Level' is the new level of the
44 * wave and 'iSample' is the index of the corresponding sample point in the
45 * current audio fragment.
46 */
47 template<class T_Manipulator>
48 class LFO {
49 public:
50
51 // *************** types ***************
52 // *
53
54 /**
55 * Defines the position of the LFO wave within the given value range
56 * and from which value to start when the LFO is triggered.
57 */
58 enum propagation_t {
59 propagation_top_down, ///< Wave level starts from given max. and grows down with growing oscillator depth.
60 propagation_middle_balanced, ///< Wave level starts from the middle of the given value range and grows in both directions with growing oscillator depth.
61 propagation_bottom_up ///< Wave level starts from given min. and grows up with growing oscillator depth.
62 };
63
64
65 // *************** attributes ***************
66 // *
67
68 T_Manipulator Manipulator; ///< Instance of the specific manipulator class given by template parameter T_Manipulator.
69 uint8_t ExtController; ///< MIDI control change controller number if the LFO is controlled by an external controller, 0 otherwise.
70
71
72 // *************** methods ***************
73 // *
74
75 /**
76 * Constructor
77 *
78 * @param Min - minimum value of the output level
79 * @param Max - maximum value of the output level
80 * @param Propagation - defines from which level the wave starts and which direction it grows with growing oscillator depth
81 * @param pEventPool - reference to an event pool which will be used to allocate Event objects
82 */
83 LFO(float Min, float Max, propagation_t Propagation, RTELMemoryPool<ModulationSystem::Event>* pEventPool) {
84 this->Propagation = Propagation;
85 this->pEvents = new RTEList<ModulationSystem::Event>(pEventPool);
86 this->ExtController = 0;
87 this->Min = Min;
88 this->Max = Max;
89 this->Range = Max - Min;
90 }
91
92 ~LFO() {
93 if (pEvents) delete pEvents;
94 }
95
96 /**
97 * Will be called by the voice for every audio fragment to let the LFO write it's modulation changes to the synthesis parameter matrix for the current audio fragment.
98 *
99 * @param Samples - total number of sample points to be rendered in
100 * this audio fragment cycle by the audio engine
101 */
102 void Process(uint Samples) {
103 ModulationSystem::Event* pCtrlEvent = pEvents->first();
104 int iSample = TriggerDelay;
105 while (iSample < Samples) {
106 int process_break = Samples;
107 if (pCtrlEvent && pCtrlEvent->FragmentPos() <= process_break) process_break = pCtrlEvent->FragmentPos();
108
109 if (Coeff > 0.0f) { // level going up
110 while (iSample < process_break && Level <= CurrentMax) {
111 Manipulator.ApplyLevel(Level, iSample);
112 iSample++;
113 Level += Coeff;
114 }
115 if (Level > CurrentMax) {
116 Coeff = -Coeff; // invert direction
117 Level += 2.0f * Coeff;
118 }
119 }
120 else if (Coeff < 0.0f) { // level going down
121 while (iSample < process_break && Level >= CurrentMin) {
122 Manipulator.ApplyLevel(Level, iSample);
123 iSample++;
124 Level += Coeff;
125 }
126 if (Level < CurrentMin) {
127 Coeff = -Coeff; // invert direction
128 Level += 2.0f * Coeff;
129 }
130 }
131 else { // no modulation at all (Coeff = 0.0)
132 switch (Propagation) {
133 case propagation_top_down:
134 Level = Max;
135 break;
136 case propagation_middle_balanced:
137 Level = Min + 0.5f * Range;
138 break;
139 case propagation_bottom_up:
140 Level = Min;
141 break;
142 }
143 while (iSample < process_break) {
144 Manipulator.ApplyLevel(Level, iSample);
145 iSample++;
146 }
147 }
148
149 if (pCtrlEvent) {
150 RecalculateCoeff(pCtrlEvent->Value);
151 pCtrlEvent = pEvents->next();
152 }
153 }
154 TriggerDelay = 0;
155 pEvents->clear();
156 }
157
158 /**
159 * Will be called by the voice when the key / voice was triggered.
160 *
161 * @param Frequency - frequency of the oscillator in Hz
162 * @param InternalDepth - firm, internal oscillator amplitude
163 * @param ExtControlDepth - defines how strong the external MIDI
164 * controller has influence on the
165 * oscillator amplitude
166 * @param ExtControlValue - current MIDI value of the external
167 * controller for the time when the voice
168 * was triggered
169 * @param FlipPhase - inverts the oscillator wave
170 * @param Delay - number of sample points triggering should
171 * be delayed
172 */
173 void Trigger(float Frequency, uint16_t InternalDepth, uint16_t ExtControlDepth, uint16_t ExtControlValue, bool FlipPhase, uint Delay) {
174 this->Coeff = 0.0f;
175 this->InternalDepth = (InternalDepth / 1200.0f) * Range;
176 this->ExtControlDepthCoeff = (((float) ExtControlDepth / 1200.0f) / 127.0f) * Range;
177 this->TriggerDelay = Delay;
178 this->FrequencyCoeff = (2.0f * Frequency) / (float) ModulationSystem::SampleRate();
179
180 if (ExtController) RecalculateCoeff(ExtControlValue);
181 else RecalculateCoeff(0);
182
183 switch (Propagation) {
184 case propagation_top_down: {
185 if (FlipPhase) {
186 Level = CurrentMin;
187 }
188 else { // normal case
189 Level = Max;
190 Coeff = -Coeff; // level starts at max. thus has to go down now
191 }
192 break;
193 }
194 case propagation_middle_balanced: {
195 Level = Min + 0.5f * Range;
196 if (FlipPhase) Coeff = -Coeff; // invert direction (going down)
197 break;
198 }
199 case propagation_bottom_up: {
200 if (FlipPhase) {
201 Level = CurrentMax;
202 Coeff = -Coeff; // level starts at max. thus has to go down now
203 }
204 else { // normal case
205 Level = Min;
206 }
207 break;
208 }
209 }
210 }
211
212 /**
213 * Will be called by the voice to inform the LFO about a change of
214 * the external controller's value.
215 *
216 * @param pEvent - control change event of external controller
217 */
218 inline void SendEvent(ModulationSystem::Event* pEvent) {
219 if (ExtController && pEvent->FragmentPos() >= this->TriggerDelay) pEvents->alloc_assign(*pEvent);
220 }
221
222 /**
223 * Should always be called when the voice was killed.
224 */
225 void Reset() {
226 pEvents->clear();
227 }
228
229 protected:
230 RTEList<ModulationSystem::Event>* pEvents;
231 propagation_t Propagation;
232 int TriggerDelay;
233 float Min;
234 float Max;
235 float CurrentMin;
236 float CurrentMax;
237 float FrequencyCoeff;
238 float ExtControlDepthCoeff;
239 float InternalDepth;
240 float Range;
241 float Coeff;
242 float Level;
243
244 inline void RecalculateCoeff(uint16_t ExtControlValue) {
245 float currentrange = InternalDepth + ExtControlValue * ExtControlDepthCoeff;
246 if (currentrange > Range) currentrange = Range;
247 Coeff = (Coeff < 0) ? -(currentrange * FrequencyCoeff)
248 : currentrange * FrequencyCoeff;
249 switch (Propagation) {
250 case propagation_top_down: {
251 CurrentMax = Max;
252 CurrentMin = Max - currentrange;
253 break;
254 }
255 case propagation_middle_balanced: {
256 float rangediff = (Range - currentrange) * 0.5f;
257 CurrentMax = Max - rangediff;
258 CurrentMin = Min + rangediff;
259 break;
260 }
261 case propagation_bottom_up: {
262 CurrentMax = Max - currentrange;
263 CurrentMin = Min;
264 break;
265 }
266 }
267 }
268 };
269
270 /** Amplification Manipulator
271 *
272 * Specialized manipulator for writing volume parameters to the synthesis
273 * parameter matrix.
274 */
275 class VCAManipulator {
276 public:
277 inline void ApplyLevel(float& Level, int& iSample) {
278 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][iSample] *= Level;
279 }
280 };
281
282 /** Filter Cutoff Frequency Manipulator
283 *
284 * Specialized manipulator for writing filter cutoff frequency parameters to
285 * the synthesis parameter matrix.
286 */
287 class VCFCManipulator {
288 public:
289 inline void ApplyLevel(float& Level, int& iSample) {
290 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vcfc][iSample] *= Level;
291 }
292 };
293
294 /** Pitch Manipulator
295 *
296 * Specialized manipulator for writing pitch parameters to the synthesis
297 * parameter matrix.
298 */
299 class VCOManipulator {
300 public:
301 inline void ApplyLevel(float& Level, int& iSample) {
302 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vco][iSample] *= RTMath::CentsToFreqRatio(Level);
303 }
304 };
305
306 #endif // __LFO_H__

  ViewVC Help
Powered by ViewVC