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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 319 - (hide 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 schoenebeck 53 /***************************************************************************
2     * *
3     * LinuxSampler - modular, streaming capable sampler *
4     * *
5 schoenebeck 56 * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 schoenebeck 53 * *
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 schoenebeck 271 LFO(float Min, float Max, propagation_t Propagation, T_Manipulator* pManipulator, Pool<Event>* pEventPool) {
89 schoenebeck 53 this->Propagation = Propagation;
90 schoenebeck 271 this->pEvents = new RTList<Event>(pEventPool);
91 schoenebeck 53 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 schoenebeck 319 * @returns true if modulation is active (LFO depth <> 0.0)
108 schoenebeck 53 */
109 schoenebeck 319 bool Process(uint Samples) {
110 schoenebeck 271 RTList<Event>::Iterator itCtrlEvent = pEvents->first();
111 schoenebeck 53 int iSample = TriggerDelay;
112 schoenebeck 319 bool result;
113 schoenebeck 53 while (iSample < Samples) {
114     int process_break = Samples;
115 schoenebeck 271 if (itCtrlEvent && itCtrlEvent->FragmentPos() <= process_break) process_break = itCtrlEvent->FragmentPos();
116 schoenebeck 53
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 schoenebeck 319 result = true; // modulation active
128 schoenebeck 53 }
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 schoenebeck 319 result = true; // modulation active
140 schoenebeck 53 }
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 schoenebeck 319 result = false; // modulation inactive
158 schoenebeck 53 }
159    
160 schoenebeck 271 if (itCtrlEvent) {
161     RecalculateCoeff(itCtrlEvent->Param.CC.Value);
162     ++itCtrlEvent;
163 schoenebeck 53 }
164     }
165     TriggerDelay = 0;
166     pEvents->clear();
167 schoenebeck 319 return result;
168 schoenebeck 53 }
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 schoenebeck 271 inline void SendEvent(Pool<Event>::Iterator itEvent) {
233     if (ExtController && itEvent->FragmentPos() >= this->TriggerDelay && !pEvents->poolIsEmpty()) *pEvents->allocAppend() = *itEvent;
234 schoenebeck 53 }
235    
236     /**
237     * Should always be called when the voice was killed.
238     */
239     void Reset() {
240     pEvents->clear();
241     }
242    
243     protected:
244 schoenebeck 271 RTList<Event>* pEvents;
245 schoenebeck 53 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