/[svn]/linuxsampler/trunk/src/engines/common/LFO.h
ViewVC logotype

Contents of /linuxsampler/trunk/src/engines/common/LFO.h

Parent Directory Parent Directory | Revision Log Revision Log


Revision 319 - (show annotations) (download) (as text)
Mon Dec 13 00:46:42 2004 UTC (19 years, 4 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 13241 byte(s)
* introduced 'synthesis mode' to reduce the amount of code and conditionals
  for the current synthesis case in the main synthesis loop
* support for MMX and SSE(1) in the core synthesis algorithms (CPU feature
  detection at runtime, only x86 so far)

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

  ViewVC Help
Powered by ViewVC