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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 40 - (hide annotations) (download) (as text)
Tue Mar 30 13:14:58 2004 UTC (20 years, 1 month 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 schoenebeck 39 /***************************************************************************
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 schoenebeck 40 #include "rtmath.h"
28 schoenebeck 39 #include "rtelmemorypool.h"
29     #include "modulationsystem.h"
30     #include "gig.h"
31    
32     /**
33     * Low Frequency Oscillator
34     *
35 schoenebeck 40 * 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 schoenebeck 39 */
47 schoenebeck 40 template<class T_Manipulator>
48 schoenebeck 39 class LFO {
49     public:
50 schoenebeck 40
51     // *************** types ***************
52     // *
53    
54 schoenebeck 39 /**
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 schoenebeck 40 // *************** 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 schoenebeck 39 /**
76 schoenebeck 40 * 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 schoenebeck 39 * 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 schoenebeck 40
222     /**
223     * Should always be called when the voice was killed.
224     */
225     void Reset() {
226     pEvents->clear();
227     }
228    
229 schoenebeck 39 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 schoenebeck 40 /** 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 schoenebeck 39 #endif // __LFO_H__

  ViewVC Help
Powered by ViewVC