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

Contents of /linuxsampler/trunk/src/engines/common/LFOSawIntMathNew.h

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3625 - (show annotations) (download) (as text)
Thu Oct 3 13:37:25 2019 UTC (4 years, 6 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 7933 byte(s)
* gig format extension: Added support for different LFO wave forms
  (currently either sine [default], triangle, saw or square).

* gig format extension: Added support for LFO phase displacement
  (0°..360°).

* gig format extension: Added support for flipping LFO polarity on LFO 3
  (in the original gig format this was only available for LFO 1 and LFO 2).

* Bumped version (2.1.1.svn22).

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

  ViewVC Help
Powered by ViewVC