WE Core
Loading...
Searching...
No Matches
RichterLFO.h
Go to the documentation of this file.
1/*
2 * File: RichterLFO.h
3 *
4 * Created: 18/01/2015
5 *
6 * This file is part of WECore.
7 *
8 * WECore is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * WECore is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with WECore. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22#pragma once
23
24#include "RichterParameters.h"
25#include "RichterWavetables.h"
27
28namespace WECore::Richter {
29
30 class RichterLFOPair;
31
44 class RichterLFO : public ModulationSource<double> {
45
46 public:
47
54 inline RichterLFO();
55
56 virtual ~RichterLFO() override = default;
57
58 friend class RichterLFOPair;
59
62 bool getBypassSwitch() const { return _bypassSwitch; }
63 bool getPhaseSyncSwitch() const { return _phaseSyncSwitch; }
64 bool getTempoSyncSwitch() const { return _tempoSyncSwitch; }
65 bool getInvertSwitch() const { return _invertSwitch; }
66 int getWave() const { return _wave; }
67 int getOutputMode() { return _outputMode; }
68 double getTempoNumer() const { return _tempoNumer; }
69 double getTempoDenom() const { return _tempoDenom; }
70 double getFreq() { return _rawFreq; }
71 double getModulatedFreqValue() const { return _modulatedFreqValue; }
72 double getDepth() { return _rawDepth; }
74 double getManualPhase() const { return _manualPhase; }
80 void setBypassSwitch(bool val) { _bypassSwitch = val; }
81 void setPhaseSyncSwitch(bool val) { _phaseSyncSwitch = val; }
82 void setTempoSyncSwitch(bool val) { _tempoSyncSwitch = val; }
83 void setInvertSwitch(bool val) { _invertSwitch = val; }
84 inline void setWave(int val);
86 void setTempoNumer(int val) { _tempoNumer = Parameters::TEMPONUMER.BoundsCheck(val); }
87 void setTempoDenom (int val) { _tempoDenom = Parameters::TEMPODENOM.BoundsCheck(val); }
88 void setFreq(double val) { _rawFreq = Parameters::FREQ.BoundsCheck(val); }
89 void setDepth(double val) { _rawDepth = Parameters::DEPTH.BoundsCheck(val); }
90 void setManualPhase(double val) { _manualPhase = Parameters::PHASE.BoundsCheck(val); }
91 void setSampleRate(double val) { _sampleRate = val; }
94 inline bool addFreqModulationSource(std::shared_ptr<ModulationSource> source);
95 inline bool removeFreqModulationSource(std::shared_ptr<ModulationSource> source);
96 inline bool setFreqModulationAmount(size_t index, double amount);
97 std::vector<ModulationSourceWrapper<double>> getFreqModulationSources() const { return _freqModulationSources; }
98
99 inline bool addDepthModulationSource(std::shared_ptr<ModulationSource> source);
100 inline bool removeDepthModulationSource(std::shared_ptr<ModulationSource> source);
101 inline bool setDepthModulationAmount(size_t index, double amount);
102 std::vector<ModulationSourceWrapper<double>> getDepthModulationSources() const { return _depthModulationSources; }
103
104 inline bool addPhaseModulationSource(std::shared_ptr<ModulationSource> source);
105 inline bool removePhaseModulationSource(std::shared_ptr<ModulationSource> source);
106 inline bool setPhaseModulationAmount(size_t index, double amount);
107 std::vector<ModulationSourceWrapper<double>> getPhaseModulationSources() const { return _phaseModulationSources; }
108
117 inline void prepareForNextBuffer(double bpm, double timeInSeconds);
118
121
122 protected:
123 int _wave,
126
132
144
145 const double* _waveArrayPointer;
146
147 std::vector<ModulationSourceWrapper<double>> _freqModulationSources,
150
158 inline void _calcPhaseOffset(double timeInSeconds);
159
166 inline double _calcFreq(double modAmount);
167
177 inline double _calcLFOValue(double freq, double phaseModValue);
178
187 inline double _getNextOutputImpl(double inSample) override;
188
192 virtual inline void _resetImpl() override;
193 };
194
195 RichterLFO::RichterLFO() : _wave(Parameters::WAVE.defaultValue),
196 _indexOffset(0),
197 _outputMode(Parameters::OUTPUTMODE.defaultValue),
198 _bypassSwitch(Parameters::LFOSWITCH_DEFAULT),
199 _tempoSyncSwitch(Parameters::TEMPOSYNC_DEFAULT),
200 _phaseSyncSwitch(Parameters::PHASESYNC_DEFAULT),
201 _invertSwitch(Parameters::INVERT_DEFAULT),
202 _needsSeekOffsetCalc(true),
203 _tempoNumer(Parameters::TEMPONUMER.defaultValue),
204 _tempoDenom(Parameters::TEMPODENOM.defaultValue),
205 _rawFreq(Parameters::FREQ.defaultValue),
206 _modulatedFreqValue(0),
207 _rawDepth(Parameters::DEPTH.defaultValue),
208 _modulatedDepthValue(0),
209 _manualPhase(Parameters::PHASE.defaultValue),
210 _modulatedPhaseValue(0),
211 _sampleRate(44100),
212 _bpm(0),
213 _wavetablePosition(0),
214 _waveArrayPointer(Wavetables::getInstance()->getSine()) {
215 }
216
230
231 bool RichterLFO::addFreqModulationSource(std::shared_ptr<ModulationSource> source) {
232 // Check if the source is already in the list
233 for (const ModulationSourceWrapper<double>& existingSource : _freqModulationSources) {
234 if (existingSource.source == source) {
235 return false;
236 }
237 }
238
239 _freqModulationSources.push_back({source, 0});
240 return true;
241 }
242
243 bool RichterLFO::removeFreqModulationSource(std::shared_ptr<ModulationSource> source) {
244 for (auto it = _freqModulationSources.begin(); it != _freqModulationSources.end(); it++) {
245 if ((*it).source == source) {
246 _freqModulationSources.erase(it);
247 return true;
248 }
249 }
250
251 return false;
252 }
253
254 bool RichterLFO::setFreqModulationAmount(size_t index, double amount) {
255 if (index >= _freqModulationSources.size()) {
256 return false;
257 }
258
259 _freqModulationSources[index].amount = amount;
260 return true;
261 }
262
263 bool RichterLFO::addDepthModulationSource(std::shared_ptr<ModulationSource> source) {
264 // Check if the source is already in the list
265 for (const ModulationSourceWrapper<double>& existingSource : _depthModulationSources) {
266 if (existingSource.source == source) {
267 return false;
268 }
269 }
270
271 _depthModulationSources.push_back({source, 0});
272 return true;
273 }
274
275 bool RichterLFO::removeDepthModulationSource(std::shared_ptr<ModulationSource> source) {
276 for (auto it = _depthModulationSources.begin(); it != _depthModulationSources.end(); it++) {
277 if ((*it).source == source) {
278 _depthModulationSources.erase(it);
279 return true;
280 }
281 }
282
283 return false;
284 }
285
286 bool RichterLFO::setDepthModulationAmount(size_t index, double amount) {
287 if (index >= _depthModulationSources.size()) {
288 return false;
289 }
290
291 _depthModulationSources[index].amount = amount;
292 return true;
293 }
294
295 bool RichterLFO::addPhaseModulationSource(std::shared_ptr<ModulationSource> source) {
296 // Check if the source is already in the list
297 for (const ModulationSourceWrapper<double>& existingSource : _phaseModulationSources) {
298 if (existingSource.source == source) {
299 return false;
300 }
301 }
302
303 _phaseModulationSources.push_back({source, 0});
304 return true;
305 }
306
307 bool RichterLFO::removePhaseModulationSource(std::shared_ptr<ModulationSource> source) {
308 for (auto it = _phaseModulationSources.begin(); it != _phaseModulationSources.end(); it++) {
309 if ((*it).source == source) {
310 _phaseModulationSources.erase(it);
311 return true;
312 }
313 }
314
315 return false;
316 }
317
318 bool RichterLFO::setPhaseModulationAmount(size_t index, double amount) {
319 if (index >= _phaseModulationSources.size()) {
320 return false;
321 }
322
323 _phaseModulationSources[index].amount = amount;
324 return true;
325 }
326
328 double timeInSeconds) {
329 _bpm = bpm;
330 _calcPhaseOffset(timeInSeconds);
331 }
332
338
339 void RichterLFO::_calcPhaseOffset(double timeInSeconds) {
340
341 // The phase offset applied by the playhead's start position needs to be calculated only
342 // when playback initially starts, and not for any subsequent buffers until playback stops
343 // and starts again
344 static int seekIndexOffset {0};
346 const double waveLength {1 / _calcFreq(0)};
347 const double waveTimePosition {std::fmod(timeInSeconds, waveLength)};
348
349 seekIndexOffset = static_cast<int>((waveTimePosition / waveLength) * Wavetables::SIZE);
350 _needsSeekOffsetCalc = false;
351 }
352
353 if (_phaseSyncSwitch) {
354 _indexOffset = seekIndexOffset;
355 } else {
356 _indexOffset = 0;
357 }
358 }
359
360 double RichterLFO::_calcFreq(double modAmount) {
361 // Calculate the frequency based on whether tempo sync is active
362 double freq {0};
363
364 if (_tempoSyncSwitch) {
365 freq = (_bpm / 60) * (_tempoDenom / _tempoNumer);
366 } else {
367 freq = _rawFreq + ((Parameters::FREQ.maxValue / 2) * modAmount);
368 }
369
370 freq = Parameters::FREQ.BoundsCheck(freq);
371 _modulatedFreqValue = freq;
372
373 return freq;
374 }
375
376 double RichterLFO::_calcLFOValue(double freq, double phaseModValue) {
377 const double samplesPerTremoloCycle {_sampleRate / freq};
378 const double scale {Wavetables::SIZE / samplesPerTremoloCycle};
379
380 // Calculate the current position within the wave table
382
383 _modulatedPhaseValue = _manualPhase + (phaseModValue * Parameters::PHASE.maxValue);
384
385 const int phaseIndexOffset {
386 static_cast<int>((_modulatedPhaseValue / Parameters::PHASE.maxValue) * Wavetables::SIZE)
387 };
388
389 const int index {static_cast<int>(_wavetablePosition)};
390
391 const double wavetableValue {_waveArrayPointer[(index + _indexOffset + phaseIndexOffset) % Wavetables::SIZE]};
392
393 return _outputMode == Parameters::OUTPUTMODE.BIPOLAR ? wavetableValue : (wavetableValue + 1);
394 }
395
396 double RichterLFO::_getNextOutputImpl(double /*inSample*/) {
397 // Get the mod amount to use, divide by 2 to reduce range to -0.5:0.5
398 const double freqModValue {calcModValue(_freqModulationSources) / 2};
399 const double depthModValue {calcModValue(_depthModulationSources) / 2};
400 const double phaseModValue {calcModValue(_phaseModulationSources) / 2};
401
402 const double lfoValue {_calcLFOValue(_calcFreq(freqModValue), phaseModValue)};
403
404 // Calculate the depth value after modulation
405 const double depth {Parameters::DEPTH.BoundsCheck(
406 _rawDepth + (Parameters::DEPTH.maxValue * depthModValue)
407 )};
408 _modulatedDepthValue = depth;
409
410 if (_bypassSwitch) {
411 // Produce a value in the range -1:1 (or 0:2), invert if needed
412 return (lfoValue * depth) * (_invertSwitch ? -1 : 1);
413 } else {
414 return 0;
415 }
416 }
417}
const double * _waveArrayPointer
Definition RichterLFO.h:145
virtual void _resetImpl() override
Definition RichterLFO.h:333
std::vector< ModulationSourceWrapper< double > > _phaseModulationSources
Definition RichterLFO.h:149
void prepareForNextBuffer(double bpm, double timeInSeconds)
Definition RichterLFO.h:327
RichterLFO(RichterLFO &)=delete
RichterLFO operator=(RichterLFO &other)=delete
virtual ~RichterLFO() override=default
double getModulatedPhaseValue() const
Definition RichterLFO.h:75
bool addDepthModulationSource(std::shared_ptr< ModulationSource > source)
Definition RichterLFO.h:263
bool getTempoSyncSwitch() const
Definition RichterLFO.h:64
void setTempoSyncSwitch(bool val)
Definition RichterLFO.h:82
std::vector< ModulationSourceWrapper< double > > _freqModulationSources
Definition RichterLFO.h:147
void setTempoDenom(int val)
Definition RichterLFO.h:87
bool getPhaseSyncSwitch() const
Definition RichterLFO.h:63
bool setDepthModulationAmount(size_t index, double amount)
Definition RichterLFO.h:286
void setOutputMode(int val)
Definition RichterLFO.h:85
double getModulatedFreqValue() const
Definition RichterLFO.h:71
bool removeDepthModulationSource(std::shared_ptr< ModulationSource > source)
Definition RichterLFO.h:275
void setInvertSwitch(bool val)
Definition RichterLFO.h:83
std::vector< ModulationSourceWrapper< double > > getFreqModulationSources() const
Definition RichterLFO.h:97
void setManualPhase(double val)
Definition RichterLFO.h:90
double _getNextOutputImpl(double inSample) override
Definition RichterLFO.h:396
bool removePhaseModulationSource(std::shared_ptr< ModulationSource > source)
Definition RichterLFO.h:307
double getTempoNumer() const
Definition RichterLFO.h:68
std::vector< ModulationSourceWrapper< double > > _depthModulationSources
Definition RichterLFO.h:148
void setTempoNumer(int val)
Definition RichterLFO.h:86
bool addFreqModulationSource(std::shared_ptr< ModulationSource > source)
Definition RichterLFO.h:231
double getManualPhase() const
Definition RichterLFO.h:74
bool addPhaseModulationSource(std::shared_ptr< ModulationSource > source)
Definition RichterLFO.h:295
double _calcLFOValue(double freq, double phaseModValue)
Definition RichterLFO.h:376
void setSampleRate(double val)
Definition RichterLFO.h:91
std::vector< ModulationSourceWrapper< double > > getPhaseModulationSources() const
Definition RichterLFO.h:107
void _calcPhaseOffset(double timeInSeconds)
Definition RichterLFO.h:339
bool removeFreqModulationSource(std::shared_ptr< ModulationSource > source)
Definition RichterLFO.h:243
bool setFreqModulationAmount(size_t index, double amount)
Definition RichterLFO.h:254
void setPhaseSyncSwitch(bool val)
Definition RichterLFO.h:81
double getTempoDenom() const
Definition RichterLFO.h:69
double getModulatedDepthValue() const
Definition RichterLFO.h:73
std::vector< ModulationSourceWrapper< double > > getDepthModulationSources() const
Definition RichterLFO.h:102
double _calcFreq(double modAmount)
Definition RichterLFO.h:360
bool setPhaseModulationAmount(size_t index, double amount)
Definition RichterLFO.h:318
void setDepth(double val)
Definition RichterLFO.h:89
void setBypassSwitch(bool val)
Definition RichterLFO.h:80
void setFreq(double val)
Definition RichterLFO.h:88
static const Wavetables * getInstance()
const double * getSidechain() const
const double * getSquare() const
const double * getSine() const
const double * getSaw() const
const ParameterDefinition::RangedParameter< double > FREQ(0, 20, 2)
const ParameterDefinition::RangedParameter< int > TEMPODENOM(1, 32, 1)
const OutputModeParameter OUTPUTMODE
const ParameterDefinition::RangedParameter< double > DEPTH(0, 1, 0.5)
const ParameterDefinition::RangedParameter< double > PHASE(0, 360, 0)
const ParameterDefinition::RangedParameter< int > TEMPONUMER(1, 32, 1)
SampleType calcModValue(const std::vector< ModulationSourceWrapper< SampleType > > &sources)