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_SAWLFOINTOLD_H__
23 #define __LS_SAWLFOINTOLD_H__
24 
25 #include "LFOBase.h"
26 
27 namespace LinuxSampler {
28 
29     /** @brief Saw LFO (int math implementation)
30      *
31      * This is a saw Low Frequency Oscillator which uses pure integer
32      * math (without branches) to synthesize the saw wave.
33      */
34     template<LFO::range_type_t RANGE, bool SAWUP>
35     class LFOSawIntMathOld : public LFOBase<RANGE> {
36         public:
37 
38             /**
39              * Constructor
40              *
41              * @param Max - maximum value of the output levels
42              */
LFOSawIntMathOld(float Max)43             LFOSawIntMathOld(float Max) : LFOBase<RANGE>::LFOBase(Max) {
44                 //NOTE: DO NOT add any custom initialization here, since it would break LFOCluster construction !
45             }
46 
47             /**
48              * Calculates exactly one sample point of the LFO wave.
49              *
50              * @returns next LFO level
51              */
render()52             inline float render() {
53                 const unsigned int intLimit = (unsigned int) -1; // all 0xFFFF...
54 
55                 uiLevel += c;
56                 if (RANGE == LFO::range_unsigned)
57                     return normalizer * (float) (SAWUP ? uiLevel : intLimit - uiLevel);
58                 else /* signed range */
59                     return normalizer * (float) (SAWUP ? uiLevel : intLimit - uiLevel) + offset;
60             }
61 
62             /**
63              * Update LFO depth with a new external controller value.
64              *
65              * @param ExtControlValue - new external controller value
66              */
updateByMIDICtrlValue(const uint16_t & ExtControlValue)67             inline void updateByMIDICtrlValue(const uint16_t& ExtControlValue) {
68                 this->ExtControlValue = ExtControlValue;
69 
70                 const unsigned int intLimit = (unsigned int) -1; // all 0xFFFF...
71                 const float max = (this->InternalDepth + ExtControlValue * this->ExtControlDepthCoeff) * this->ScriptDepthFactor;
72                 if (RANGE == LFO::range_unsigned) {
73                     normalizer = max / (float) intLimit;
74                 } else { // signed range
75                     normalizer = max / (float) intLimit * 2.0f;
76                     offset     = -max;
77                 }
78             }
79 
80             /**
81              * Will be called by the voice when the key / voice was triggered.
82              *
83              * @param Frequency       - frequency of the oscillator in Hz
84              * @param StartLevel      - not implemented
85              * @param InternalDepth   - firm, internal oscillator amplitude
86              * @param ExtControlDepth - defines how strong the external MIDI
87              *                          controller has influence on the
88              *                          oscillator amplitude
89              * @param FlipPhase       - not implemented
90              * @param SampleRate      - current sample rate of the engines
91              *                          audio output signal
92              */
trigger(float Frequency,LFO::start_level_t StartLevel,uint16_t InternalDepth,uint16_t ExtControlDepth,bool FlipPhase,unsigned int SampleRate)93             virtual void trigger(float Frequency, LFO::start_level_t StartLevel, uint16_t InternalDepth, uint16_t ExtControlDepth, bool FlipPhase, unsigned int SampleRate) {
94                 this->Frequency            = Frequency;
95                 this->InternalDepth        = (InternalDepth / 1200.0f) * this->Max;
96                 this->ExtControlDepthCoeff = (((float) ExtControlDepth / 1200.0f) / 127.0f) * this->Max;
97                 this->ScriptFrequencyFactor = this->ScriptDepthFactor = 1.f; // reset for new voice
98                 this->pFinalDepth = NULL;
99                 this->pFinalFrequency = NULL;
100 
101                 const unsigned int intLimit = (unsigned int) -1; // all 0xFFFF...
102                 const float freq = Frequency * this->ScriptFrequencyFactor;
103                 const float r = freq / (float) SampleRate; // frequency alteration quotient
104                 c = (int) (intLimit * r);
105 
106                 uiLevel = 0;
107             }
108 
109             /**
110              * Should be invoked after the LFO is triggered.
111              * @param phase From 0 to 360 degrees.
112              */
setPhase(float phase)113             void setPhase(float phase) {
114                 if (phase < 0) phase = 0;
115                 if (phase > 360) phase = 360;
116                 phase /= 360.0f;
117                 const unsigned int intLimit = (unsigned int) -1; // all 0xFFFF...
118                 uiLevel = intLimit * phase;
119             }
120 
setFrequency(float Frequency,unsigned int SampleRate)121             void setFrequency(float Frequency, unsigned int SampleRate) {
122                 this->Frequency = Frequency;
123                 const float freq = Frequency * this->ScriptFrequencyFactor;
124                 const unsigned int intLimit = (unsigned int) -1; // all 0xFFFF...
125                 float r = freq / (float) SampleRate; // frequency alteration quotient
126                 c = (int) (intLimit * r);
127             }
128 
setScriptDepthFactor(float factor,bool isFinal)129             void setScriptDepthFactor(float factor, bool isFinal) {
130                 this->ScriptDepthFactor = factor;
131                 // set or reset this script depth parameter to be the sole
132                 // source for the LFO depth
133                 if (isFinal && !this->pFinalDepth)
134                     this->pFinalDepth = &this->ScriptDepthFactor;
135                 else if (!isFinal && this->pFinalDepth == &this->ScriptDepthFactor)
136                     this->pFinalDepth = NULL;
137                 // recalculate upon new depth
138                 updateByMIDICtrlValue(this->ExtControlValue);
139             }
140 
setScriptFrequencyFactor(float factor,unsigned int SampleRate)141             void setScriptFrequencyFactor(float factor, unsigned int SampleRate) {
142                 this->ScriptFrequencyFactor = factor;
143                 // in case script frequency was set as "final" value before,
144                 // reset it so that all sources are processed from now on
145                 if (this->pFinalFrequency == &this->ScriptFrequencyFactor)
146                     this->pFinalFrequency = NULL;
147                 // recalculate upon new frequency
148                 setFrequency(this->Frequency, SampleRate);
149             }
150 
setScriptFrequencyFinal(float hz,unsigned int SampleRate)151             void setScriptFrequencyFinal(float hz, unsigned int SampleRate) {
152                 this->ScriptFrequencyFactor = hz;
153                 // assign script's given frequency as sole source for the LFO
154                 // frequency, thus ignore all other sources
155                 if (!this->pFinalFrequency)
156                     this->pFinalFrequency = &this->ScriptFrequencyFactor;
157                 // recalculate upon new frequency
158                 setFrequency(this->Frequency, SampleRate);
159             }
160 
161         protected:
162             unsigned int uiLevel;
163             int   c;
164             float offset; ///< only needed for signed range
165             float normalizer;
166     };
167 
168 
169     template<LFO::range_type_t RANGE>
170     class SawUpLFO : public LFOSawIntMathOld<RANGE, true> {
171         public:
SawUpLFO(float Max)172             SawUpLFO(float Max) : LFOSawIntMathOld<RANGE, true>::LFOSawIntMathOld(Max) { }
173     };
174 
175     template<LFO::range_type_t RANGE>
176     class SawDownLFO : public LFOSawIntMathOld<RANGE, false> {
177         public:
SawDownLFO(float Max)178             SawDownLFO(float Max) : LFOSawIntMathOld<RANGE, false>::LFOSawIntMathOld(Max) { }
179     };
180 
181 } // namespace LinuxSampler
182 
183 #endif // __LS_SAWLFOINTOLD_H__
184