1 /***************************************************************************
2  *                                                                         *
3  *   Copyright (C) 2005 Christian Schoenebeck                              *
4  *   Copyright (C) 2011 Christian Schoenebeck and Grigor Iliev             *
5  *                                                                         *
6  *   This library is free software; you can redistribute it and/or modify  *
7  *   it under the terms of the GNU General Public License as published by  *
8  *   the Free Software Foundation; either version 2 of the License, or     *
9  *   (at your option) any later version.                                   *
10  *                                                                         *
11  *   This library is distributed in the hope that it will be useful,       *
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
14  *   GNU General Public License for more details.                          *
15  *                                                                         *
16  *   You should have received a copy of the GNU General Public License     *
17  *   along with this library; if not, write to the Free Software           *
18  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston,                 *
19  *   MA  02111-1307  USA                                                   *
20  ***************************************************************************/
21 
22 #ifndef __LS_SINELFO_BUILTIN_H__
23 #define __LS_SINELFO_BUILTIN_H__
24 
25 #include "LFOBase.h"
26 
27 namespace LinuxSampler {
28 
29     /** @brief Sine LFO (using built-in sin() function as implementation)
30      */
31     template<LFO::range_type_t RANGE>
32     class LFOSineBuiltinFn : public LFOBase<RANGE> {
33         public:
34 
35             /**
36              * Constructor
37              *
38              * @param Max - maximum value of the output levels
39              */
LFOSineBuiltinFn(float Max)40             LFOSineBuiltinFn(float Max) : LFOBase<RANGE>::LFOBase(Max) {
41                 //NOTE: DO NOT add any custom initialization here, since it would break LFOCluster construction !
42             }
43 
44             /**
45              * Calculates exactly one sample point of the LFO wave.
46              *
47              * @returns next LFO level
48              */
render()49             inline float render() {
50                 uiLevel += c;
51                 if (RANGE == LFO::range_unsigned)
52                     return normalizer * (sin(c2 * (float)uiLevel) + 1.0f);
53                 else /* signed range */
54                     return normalizer * sin(c2 * (float)uiLevel);
55             }
56 
57             /**
58              * Update LFO depth with a new external controller value.
59              *
60              * @param ExtControlValue - new external controller value
61              */
updateByMIDICtrlValue(const uint16_t & ExtControlValue)62             inline void updateByMIDICtrlValue(const uint16_t& ExtControlValue) {
63                 this->ExtControlValue = ExtControlValue;
64 
65                 //const unsigned int intLimit = (unsigned int) -1; // all 0xFFFF...
66                 const float max = (this->InternalDepth + ExtControlValue * this->ExtControlDepthCoeff) * this->ScriptDepthFactor;
67                 if (RANGE == LFO::range_unsigned) {
68                     normalizer = max / 2.0f;
69                 } else { // signed range
70                     normalizer = max;
71                 }
72             }
73 
74             /**
75              * Will be called by the voice when the key / voice was triggered.
76              *
77              * @param Frequency       - frequency of the oscillator in Hz
78              * @param StartLevel      - not implemented
79              * @param InternalDepth   - firm, internal oscillator amplitude
80              * @param ExtControlDepth - defines how strong the external MIDI
81              *                          controller has influence on the
82              *                          oscillator amplitude
83              * @param FlipPhase       - not implemented
84              * @param SampleRate      - current sample rate of the engines
85              *                          audio output signal
86              */
trigger(float Frequency,LFO::start_level_t StartLevel,uint16_t InternalDepth,uint16_t ExtControlDepth,bool FlipPhase,unsigned int SampleRate)87             virtual void trigger(float Frequency, LFO::start_level_t StartLevel, uint16_t InternalDepth, uint16_t ExtControlDepth, bool FlipPhase, unsigned int SampleRate) {
88                 this->Frequency            = Frequency;
89                 this->InternalDepth        = (InternalDepth / 1200.0f) * this->Max;
90                 this->ExtControlDepthCoeff = (((float) ExtControlDepth / 1200.0f) / 127.0f) * this->Max;
91                 this->ScriptFrequencyFactor = this->ScriptDepthFactor = 1.f; // reset for new voice
92                 this->pFinalDepth = NULL;
93                 this->pFinalFrequency = NULL;
94 
95                 const unsigned int intLimit = (unsigned int) -1; // all 0xFFFF...
96                 const float freq = Frequency * this->ScriptFrequencyFactor;
97                 const float r = freq / (float) SampleRate; // frequency alteration quotient
98                 c = (int) (intLimit * r);
99                 c2 = (2.0f * M_PI) / (float) intLimit;
100 
101                 uiLevel = 0;
102             }
103 
104             /**
105              * @param phase 0 to 360 degrees
106              */
setPhase(float phase)107             void setPhase(float phase) {
108                 if (phase < 0) phase = 0;
109                 if (phase > 360) phase = 360;
110                 phase /= 360.0f;
111                 const unsigned int intLimit = (unsigned int) -1; // all 0xFFFF...
112                 uiLevel = intLimit * phase;
113             }
114 
setFrequency(float Frequency,unsigned int SampleRate)115             void setFrequency(float Frequency, unsigned int SampleRate) {
116                 this->Frequency = Frequency;
117                 const float freq = Frequency * this->ScriptFrequencyFactor;
118                 const unsigned int intLimit = (unsigned int) -1; // all 0xFFFF...
119                 float r = freq / (float) SampleRate; // frequency alteration quotient
120                 c = (int) (intLimit * r);
121             }
122 
setScriptDepthFactor(float factor,bool isFinal)123             void setScriptDepthFactor(float factor, bool isFinal) {
124                 this->ScriptDepthFactor = factor;
125                 // set or reset this script depth parameter to be the sole
126                 // source for the LFO depth
127                 if (isFinal && !this->pFinalDepth)
128                     this->pFinalDepth = &this->ScriptDepthFactor;
129                 else if (!isFinal && this->pFinalDepth == &this->ScriptDepthFactor)
130                     this->pFinalDepth = NULL;
131                 // recalculate upon new depth
132                 updateByMIDICtrlValue(this->ExtControlValue);
133             }
134 
setScriptFrequencyFactor(float factor,unsigned int SampleRate)135             void setScriptFrequencyFactor(float factor, unsigned int SampleRate) {
136                 this->ScriptFrequencyFactor = factor;
137                 // in case script frequency was set as "final" value before,
138                 // reset it so that all sources are processed from now on
139                 if (this->pFinalFrequency == &this->ScriptFrequencyFactor)
140                     this->pFinalFrequency = NULL;
141                 // recalculate upon new frequency
142                 setFrequency(this->Frequency, SampleRate);
143             }
144 
setScriptFrequencyFinal(float hz,unsigned int SampleRate)145             void setScriptFrequencyFinal(float hz, unsigned int SampleRate) {
146                 this->ScriptFrequencyFactor = hz;
147                 // assign script's given frequency as sole source for the LFO
148                 // frequency, thus ignore all other sources
149                 if (!this->pFinalFrequency)
150                     this->pFinalFrequency = &this->ScriptFrequencyFactor;
151                 // recalculate upon new frequency
152                 setFrequency(this->Frequency, SampleRate);
153             }
154 
155         protected:
156             unsigned int uiLevel;
157             int   c;
158             float c2;
159             float normalizer;
160     };
161 
162 } // namespace LinuxSampler
163 
164 #endif // __LS_SINELFO_BUILTIN_H__
165