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