/[svn]/linuxsampler/tags/v0_1_0/src/lfo.h
ViewVC logotype

Annotation of /linuxsampler/tags/v0_1_0/src/lfo.h

Parent Directory Parent Directory | Revision Log Revision Log


Revision 41 - (hide annotations) (download) (as text)
Wed Mar 31 10:28:42 2004 UTC (20 years, 2 months ago) by schoenebeck
Original Path: linuxsampler/trunk/src/lfo.h
File MIME type: text/x-c++hdr
File size: 13030 byte(s)
removed unnecessary dependencies

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

  ViewVC Help
Powered by ViewVC