1 |
schoenebeck |
3612 |
/* |
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 |
|
|
#include "LFO.h" |
11 |
|
|
#include "common/LFOAll.h" |
12 |
|
|
#include <type_traits> // for std::is_same |
13 |
|
|
|
14 |
|
|
namespace LinuxSampler { |
15 |
|
|
|
16 |
|
|
enum lfo_class_t { |
17 |
|
|
lfo_class_sine_signed, |
18 |
|
|
lfo_class_sine_unsigned, |
19 |
|
|
lfo_class_triangle_signed, |
20 |
|
|
lfo_class_triangle_unsigned, |
21 |
|
|
lfo_class_saw_signed, |
22 |
|
|
lfo_class_saw_unsigned, |
23 |
|
|
lfo_class_square_signed, |
24 |
|
|
lfo_class_square_unsigned, |
25 |
|
|
}; |
26 |
|
|
|
27 |
|
|
struct LFOPriv { |
28 |
|
|
LFOPOD* lfo = NULL; |
29 |
|
|
lfo_class_t lfoClass = (lfo_class_t) -1; // some invalid value |
30 |
|
|
|
31 |
|
|
virtual ~LFOPriv() { |
32 |
|
|
if (lfo) delete lfo; |
33 |
|
|
} |
34 |
|
|
}; |
35 |
|
|
|
36 |
|
|
LFO::LFO() { |
37 |
|
|
SELF = new LFOPriv; |
38 |
|
|
} |
39 |
|
|
|
40 |
|
|
LFO::~LFO() { |
41 |
|
|
if (SELF) delete SELF; |
42 |
|
|
} |
43 |
|
|
|
44 |
|
|
template<class T> |
45 |
|
|
static T* createLFO(LFOPriv* SELF, const LFO::SetupOpt& opt) { |
46 |
|
|
if (SELF->lfo) { |
47 |
|
|
delete SELF->lfo; |
48 |
|
|
SELF->lfo = NULL; |
49 |
|
|
} |
50 |
|
|
|
51 |
|
|
const bool flipPolarity = (opt.flipPolarity) ? *opt.flipPolarity : false; |
52 |
|
|
const float maxValue = (opt.maxValue) ? *opt.maxValue : 1.0; |
53 |
|
|
const float frequency = (opt.frequency) ? *opt.frequency : 1.0; |
54 |
|
|
const LFO::start_level_t startLevel = (opt.startLevel) ? *opt.startLevel : LFO::start_level_mid; |
55 |
|
|
const uint16_t internalDepth = (opt.internalDepth) ? *opt.internalDepth : 0; |
56 |
|
|
const uint16_t midiCtrlDepth = (opt.midiControllerDepth) ? *opt.midiControllerDepth : 0; |
57 |
|
|
const float samplerate = (opt.samplerate) ? *opt.samplerate : 44100; |
58 |
|
|
|
59 |
|
|
T* lfo = new T(maxValue); |
60 |
|
|
SELF->lfo = lfo; |
61 |
|
|
|
62 |
|
|
lfo->trigger(frequency, startLevel, internalDepth, midiCtrlDepth, flipPolarity, samplerate); |
63 |
|
|
if (opt.phase) |
64 |
|
|
lfo->setPhase( *opt.phase ); |
65 |
|
|
lfo->updateByMIDICtrlValue(0); |
66 |
|
|
|
67 |
|
|
if (std::is_same<T,LFOSineSigned>::value) |
68 |
|
|
SELF->lfoClass = lfo_class_sine_signed; |
69 |
|
|
else if (std::is_same<T,LFOSineUnsigned>::value) |
70 |
|
|
SELF->lfoClass = lfo_class_sine_unsigned; |
71 |
schoenebeck |
3614 |
else if (std::is_same<T,LFOTriangleSigned>::value) |
72 |
schoenebeck |
3612 |
SELF->lfoClass = lfo_class_triangle_signed; |
73 |
schoenebeck |
3614 |
else if (std::is_same<T,LFOTriangleUnsigned>::value) |
74 |
schoenebeck |
3612 |
SELF->lfoClass = lfo_class_triangle_unsigned; |
75 |
|
|
else if (std::is_same<T,LFOSawSigned>::value) |
76 |
|
|
SELF->lfoClass = lfo_class_saw_signed; |
77 |
|
|
else if (std::is_same<T,LFOSawUnsigned>::value) |
78 |
|
|
SELF->lfoClass = lfo_class_saw_unsigned; |
79 |
|
|
else if (std::is_same<T,LFOSquareSigned>::value) |
80 |
|
|
SELF->lfoClass = lfo_class_square_signed; |
81 |
|
|
else if (std::is_same<T,LFOSquareUnsigned>::value) |
82 |
|
|
SELF->lfoClass = lfo_class_square_unsigned; |
83 |
|
|
else |
84 |
|
|
assert(false); |
85 |
|
|
|
86 |
|
|
return lfo; |
87 |
|
|
} |
88 |
|
|
|
89 |
|
|
void LFO::setup(const SetupOpt& opt) { |
90 |
|
|
const wave_t wave = (opt.waveType) ? *opt.waveType : wave_sine; |
91 |
|
|
const bool isSigned = (opt.rangeType) ? (*opt.rangeType == range_signed) : false; |
92 |
|
|
|
93 |
|
|
switch (wave) { |
94 |
|
|
case wave_sine: |
95 |
|
|
if (isSigned) |
96 |
|
|
createLFO<LFOSineSigned>(SELF, opt); |
97 |
|
|
else |
98 |
|
|
createLFO<LFOSineUnsigned>(SELF, opt); |
99 |
|
|
break; |
100 |
|
|
case wave_triangle: |
101 |
|
|
if (isSigned) |
102 |
schoenebeck |
3614 |
createLFO<LFOTriangleSigned>(SELF, opt); |
103 |
schoenebeck |
3612 |
else |
104 |
schoenebeck |
3614 |
createLFO<LFOTriangleUnsigned>(SELF, opt); |
105 |
schoenebeck |
3612 |
break; |
106 |
|
|
case wave_saw: |
107 |
|
|
if (isSigned) |
108 |
|
|
createLFO<LFOSawSigned>(SELF, opt); |
109 |
|
|
else |
110 |
|
|
createLFO<LFOSawUnsigned>(SELF, opt); |
111 |
|
|
break; |
112 |
|
|
case wave_square: |
113 |
|
|
if (isSigned) |
114 |
|
|
createLFO<LFOSquareSigned>(SELF, opt); |
115 |
|
|
else |
116 |
|
|
createLFO<LFOSquareUnsigned>(SELF, opt); |
117 |
|
|
break; |
118 |
|
|
default: |
119 |
|
|
assert(false); |
120 |
|
|
} |
121 |
|
|
} |
122 |
|
|
|
123 |
|
|
template<class T> |
124 |
|
|
inline float renderLFO(LFOPriv* SELF) { |
125 |
|
|
return static_cast<T*>(SELF->lfo)->render(); |
126 |
|
|
} |
127 |
|
|
|
128 |
|
|
float LFO::render() { |
129 |
|
|
switch (SELF->lfoClass) { |
130 |
|
|
case lfo_class_sine_signed: |
131 |
|
|
return renderLFO<LFOSineSigned>(SELF); |
132 |
|
|
case lfo_class_sine_unsigned: |
133 |
|
|
return renderLFO<LFOSineUnsigned>(SELF); |
134 |
|
|
case lfo_class_triangle_signed: |
135 |
schoenebeck |
3614 |
return renderLFO<LFOTriangleSigned>(SELF); |
136 |
schoenebeck |
3612 |
case lfo_class_triangle_unsigned: |
137 |
schoenebeck |
3614 |
return renderLFO<LFOTriangleUnsigned>(SELF); |
138 |
schoenebeck |
3612 |
case lfo_class_saw_signed: |
139 |
|
|
return renderLFO<LFOSawSigned>(SELF); |
140 |
|
|
case lfo_class_saw_unsigned: |
141 |
|
|
return renderLFO<LFOSawUnsigned>(SELF); |
142 |
|
|
case lfo_class_square_signed: |
143 |
|
|
return renderLFO<LFOSquareSigned>(SELF); |
144 |
|
|
case lfo_class_square_unsigned: |
145 |
|
|
return renderLFO<LFOSquareUnsigned>(SELF); |
146 |
|
|
} |
147 |
|
|
return 0; |
148 |
|
|
} |
149 |
|
|
|
150 |
|
|
template<class T> |
151 |
|
|
inline void setLFOMidiCtrlValue(LFOPriv* SELF, uint16_t value) { |
152 |
|
|
return static_cast<T*>(SELF->lfo)->updateByMIDICtrlValue(value); |
153 |
|
|
} |
154 |
|
|
|
155 |
|
|
void LFO::setMIDICtrlValue(uint8_t midiCCValue) { |
156 |
|
|
switch (SELF->lfoClass) { |
157 |
|
|
case lfo_class_sine_signed: |
158 |
|
|
return setLFOMidiCtrlValue<LFOSineSigned>(SELF, midiCCValue); |
159 |
|
|
case lfo_class_sine_unsigned: |
160 |
|
|
return setLFOMidiCtrlValue<LFOSineUnsigned>(SELF, midiCCValue); |
161 |
|
|
case lfo_class_triangle_signed: |
162 |
schoenebeck |
3614 |
return setLFOMidiCtrlValue<LFOTriangleSigned>(SELF, midiCCValue); |
163 |
schoenebeck |
3612 |
case lfo_class_triangle_unsigned: |
164 |
schoenebeck |
3614 |
return setLFOMidiCtrlValue<LFOTriangleUnsigned>(SELF, midiCCValue); |
165 |
schoenebeck |
3612 |
case lfo_class_saw_signed: |
166 |
|
|
return setLFOMidiCtrlValue<LFOSawSigned>(SELF, midiCCValue); |
167 |
|
|
case lfo_class_saw_unsigned: |
168 |
|
|
return setLFOMidiCtrlValue<LFOSawUnsigned>(SELF, midiCCValue); |
169 |
|
|
case lfo_class_square_signed: |
170 |
|
|
return setLFOMidiCtrlValue<LFOSquareSigned>(SELF, midiCCValue); |
171 |
|
|
case lfo_class_square_unsigned: |
172 |
|
|
return setLFOMidiCtrlValue<LFOSquareUnsigned>(SELF, midiCCValue); |
173 |
|
|
} |
174 |
|
|
} |
175 |
|
|
|
176 |
|
|
} // namespace LinuxSampler |