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 #include "LFO.h"
11 #include "common/LFOAll.h"
12 #include <type_traits> // for std::is_same
13 #include <assert.h>
14 
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 
~LFOPrivLinuxSampler::LFOPriv32     virtual ~LFOPriv() {
33         if (lfo) delete lfo;
34     }
35 };
36 
LFO()37 LFO::LFO() {
38     SELF = new LFOPriv;
39 }
40 
~LFO()41 LFO::~LFO() {
42     if (SELF) delete SELF;
43 }
44 
45 template<class T>
createLFO(LFOPriv * SELF,const LFO::SetupOpt & opt)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     else if (std::is_same<T,LFOTriangleSigned>::value)
73         SELF->lfoClass = lfo_class_triangle_signed;
74     else if (std::is_same<T,LFOTriangleUnsigned>::value)
75         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 
setup(const SetupOpt & opt)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                 createLFO<LFOTriangleSigned>(SELF, opt);
104             else
105                 createLFO<LFOTriangleUnsigned>(SELF, opt);
106             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>
renderLFO(LFOPriv * SELF)125 inline float renderLFO(LFOPriv* SELF) {
126     return static_cast<T*>(SELF->lfo)->render();
127 }
128 
render()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             return renderLFO<LFOTriangleSigned>(SELF);
137         case lfo_class_triangle_unsigned:
138             return renderLFO<LFOTriangleUnsigned>(SELF);
139         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>
setLFOMidiCtrlValue(LFOPriv * SELF,uint16_t value)152 inline void setLFOMidiCtrlValue(LFOPriv* SELF, uint16_t value) {
153     return static_cast<T*>(SELF->lfo)->updateByMIDICtrlValue(value);
154 }
155 
setMIDICtrlValue(uint8_t midiCCValue)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             return setLFOMidiCtrlValue<LFOTriangleSigned>(SELF, midiCCValue);
164         case lfo_class_triangle_unsigned:
165             return setLFOMidiCtrlValue<LFOTriangleUnsigned>(SELF, midiCCValue);
166         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
178