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 */ LFOCluster(float Max)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 */ render()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 */ 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)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 */ updateByMIDICtrlValue(const uint16_t & ExtControlValue)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 */ setPhase(float phase)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 setFrequency(float Frequency,unsigned int SampleRate)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 setScriptDepthFactor(float factor,bool isFinal)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 setScriptFrequencyFactor(float factor,unsigned int samplerate)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 setScriptFrequencyFinal(float hz,unsigned int samplerate)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 237