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_LFO_CLUSTER_H |
11 |
#define LS_LFO_CLUSTER_H |
12 |
|
13 |
#include "LFOAll.h" |
14 |
#include <type_traits> // for std::conditional |
15 |
|
16 |
namespace LinuxSampler { |
17 |
|
18 |
/** @brief Low Frequency Oscillator (sampler internal template class). |
19 |
* |
20 |
* This is a generalized cluster class providing all our LFO implementations |
21 |
* encapsulated as one single class. This is thus a C++ template variant of the |
22 |
* similar public API C++ class LFO. Even though LFOCluster and LFO serve a |
23 |
* similar purpose, you should however always use this template variant instead |
24 |
* of the public API LFO class for sampler internal code. LFOCluster has a |
25 |
* higher potential for the compiler to optimize the finally emitted |
26 |
* instructions, however it requires direct access to our individual LFO |
27 |
* implementations' code (which are subject to change at any time for |
28 |
* performance reasons). Hence this template class is not suitable for public |
29 |
* API purposes (that is for third party apps), hence the reason for the |
30 |
+ existence of the separate public API LFO class. The latter has the priority |
31 |
* for API & ABI stability for the price of slightly reduced runtime efficiency |
32 |
* though. |
33 |
*/ |
34 |
template<LFO::range_type_t RANGE> |
35 |
class LFOCluster { |
36 |
public: |
37 |
uint8_t& ExtController = sine.ExtController; /// redirect to union |
38 |
|
39 |
/** |
40 |
* Constructor |
41 |
* |
42 |
* @param Max - maximum value of the output levels |
43 |
*/ |
44 |
LFOCluster(float Max) : |
45 |
wave(LFO::wave_sine), |
46 |
sine(Max) // union-like class: use any union member's constructor (one for all, all for one) |
47 |
{ |
48 |
} |
49 |
|
50 |
/** |
51 |
* Calculates exactly one sample point of the LFO wave. |
52 |
* |
53 |
* @returns next LFO level |
54 |
*/ |
55 |
inline float render() { |
56 |
switch (wave) { |
57 |
case LFO::wave_sine: return sine.render(); |
58 |
case LFO::wave_triangle: return triangle.render(); |
59 |
case LFO::wave_saw: return saw.render(); |
60 |
case LFO::wave_square: return square.render(); |
61 |
} |
62 |
return 0.f; |
63 |
} |
64 |
|
65 |
/** |
66 |
* Will be called by the voice when the key / voice was triggered. |
67 |
* |
68 |
* @param Wave - wave form to be used (e.g. sine, saw, square) |
69 |
* @param Frequency - frequency of the oscillator in Hz |
70 |
* @param Phase - phase displacement of wave form's start level |
71 |
* (0��..360��) |
72 |
* @param StartLevel - on which level the wave should start |
73 |
* @param InternalDepth - firm, internal oscillator amplitude |
74 |
* @param ExtControlDepth - defines how strong the external MIDI |
75 |
* controller has influence on the |
76 |
* oscillator amplitude |
77 |
* @param FlipPhase - inverts the oscillator wave against |
78 |
* a horizontal axis |
79 |
* @param SampleRate - current sample rate of the engines |
80 |
* audio output signal |
81 |
*/ |
82 |
void trigger(LFO::wave_t Wave, float Frequency, float Phase, LFO::start_level_t StartLevel, uint16_t InternalDepth, uint16_t ExtControlDepth, bool FlipPhase, unsigned int SampleRate) { |
83 |
wave = Wave; |
84 |
switch (Wave) { |
85 |
case LFO::wave_sine: |
86 |
sine.trigger(Frequency, StartLevel, InternalDepth, ExtControlDepth, FlipPhase, SampleRate); |
87 |
sine.setPhase(Phase); |
88 |
break; |
89 |
case LFO::wave_triangle: |
90 |
triangle.trigger(Frequency, StartLevel, InternalDepth, ExtControlDepth, FlipPhase, SampleRate); |
91 |
triangle.setPhase(Phase); |
92 |
break; |
93 |
case LFO::wave_saw: |
94 |
saw.trigger(Frequency, StartLevel, InternalDepth, ExtControlDepth, FlipPhase, SampleRate); |
95 |
saw.setPhase(Phase); |
96 |
break; |
97 |
case LFO::wave_square: |
98 |
square.trigger(Frequency, StartLevel, InternalDepth, ExtControlDepth, FlipPhase, SampleRate); |
99 |
square.setPhase(Phase); |
100 |
break; |
101 |
} |
102 |
} |
103 |
|
104 |
/** |
105 |
* Update LFO depth with a new external controller value. |
106 |
* |
107 |
* @param ExtControlValue - new external controller value |
108 |
*/ |
109 |
void updateByMIDICtrlValue(const uint16_t& ExtControlValue) { |
110 |
switch (wave) { |
111 |
case LFO::wave_sine: |
112 |
sine.updateByMIDICtrlValue(ExtControlValue); |
113 |
break; |
114 |
case LFO::wave_triangle: |
115 |
triangle.updateByMIDICtrlValue(ExtControlValue); |
116 |
break; |
117 |
case LFO::wave_saw: |
118 |
saw.updateByMIDICtrlValue(ExtControlValue); |
119 |
break; |
120 |
case LFO::wave_square: |
121 |
square.updateByMIDICtrlValue(ExtControlValue); |
122 |
break; |
123 |
} |
124 |
} |
125 |
|
126 |
/** |
127 |
* Should be invoked after the LFO is triggered. |
128 |
* @param phase From 0 to 360 degrees. |
129 |
*/ |
130 |
void setPhase(float phase) { |
131 |
switch (wave) { |
132 |
case LFO::wave_sine: |
133 |
sine.setPhase(phase); |
134 |
break; |
135 |
case LFO::wave_triangle: |
136 |
triangle.setPhase(phase); |
137 |
break; |
138 |
case LFO::wave_saw: |
139 |
saw.setPhase(phase); |
140 |
break; |
141 |
case LFO::wave_square: |
142 |
square.setPhase(phase); |
143 |
break; |
144 |
} |
145 |
} |
146 |
|
147 |
void setFrequency(float Frequency, unsigned int SampleRate) { |
148 |
switch (wave) { |
149 |
case LFO::wave_sine: |
150 |
sine.setFrequency(Frequency, SampleRate); |
151 |
break; |
152 |
case LFO::wave_triangle: |
153 |
triangle.setFrequency(Frequency, SampleRate); |
154 |
break; |
155 |
case LFO::wave_saw: |
156 |
saw.setFrequency(Frequency, SampleRate); |
157 |
break; |
158 |
case LFO::wave_square: |
159 |
square.setFrequency(Frequency, SampleRate); |
160 |
break; |
161 |
} |
162 |
} |
163 |
|
164 |
void setScriptDepthFactor(float factor, bool isFinal) { |
165 |
switch (wave) { |
166 |
case LFO::wave_sine: |
167 |
sine.setScriptDepthFactor(factor, isFinal); |
168 |
break; |
169 |
case LFO::wave_triangle: |
170 |
triangle.setScriptDepthFactor(factor, isFinal); |
171 |
break; |
172 |
case LFO::wave_saw: |
173 |
saw.setScriptDepthFactor(factor, isFinal); |
174 |
break; |
175 |
case LFO::wave_square: |
176 |
square.setScriptDepthFactor(factor, isFinal); |
177 |
break; |
178 |
} |
179 |
} |
180 |
|
181 |
void setScriptFrequencyFactor(float factor, unsigned int samplerate) { |
182 |
switch (wave) { |
183 |
case LFO::wave_sine: |
184 |
sine.setScriptFrequencyFactor(factor, samplerate); |
185 |
break; |
186 |
case LFO::wave_triangle: |
187 |
triangle.setScriptFrequencyFactor(factor, samplerate); |
188 |
break; |
189 |
case LFO::wave_saw: |
190 |
saw.setScriptFrequencyFactor(factor, samplerate); |
191 |
break; |
192 |
case LFO::wave_square: |
193 |
square.setScriptFrequencyFactor(factor, samplerate); |
194 |
break; |
195 |
} |
196 |
} |
197 |
|
198 |
void setScriptFrequencyFinal(float hz, unsigned int samplerate) { |
199 |
switch (wave) { |
200 |
case LFO::wave_sine: |
201 |
sine.setScriptFrequencyFinal(hz, samplerate); |
202 |
break; |
203 |
case LFO::wave_triangle: |
204 |
triangle.setScriptFrequencyFinal(hz, samplerate); |
205 |
break; |
206 |
case LFO::wave_saw: |
207 |
saw.setScriptFrequencyFinal(hz, samplerate); |
208 |
break; |
209 |
case LFO::wave_square: |
210 |
square.setScriptFrequencyFinal(hz, samplerate); |
211 |
break; |
212 |
} |
213 |
} |
214 |
|
215 |
protected: |
216 |
typedef LFOSineNumericComplexNr<RANGE> Sine; |
217 |
typedef typename std::conditional<RANGE == LFO::range_signed, LFOTriangleSigned, LFOTriangleUnsigned>::type Triangle; |
218 |
typedef LFOSawIntMathNew<RANGE> Saw; |
219 |
typedef LFOSquareIntMath<RANGE> Square; |
220 |
|
221 |
private: |
222 |
LFO::wave_t wave; |
223 |
union { |
224 |
Sine sine; |
225 |
Triangle triangle; |
226 |
Saw saw; |
227 |
Square square; |
228 |
}; |
229 |
}; |
230 |
|
231 |
typedef LFOCluster<LFO::range_signed> LFOClusterSigned; |
232 |
typedef LFOCluster<LFO::range_unsigned> LFOClusterUnsigned; |
233 |
|
234 |
} // namespace LinuxSampler |
235 |
|
236 |
#endif // LS_LFO_CLUSTER_H |