diff --git a/WECore/RichterLFO/RichterLFO.h b/WECore/RichterLFO/RichterLFO.h index 210875d..bd48550 100644 --- a/WECore/RichterLFO/RichterLFO.h +++ b/WECore/RichterLFO/RichterLFO.h @@ -64,6 +64,7 @@ namespace WECore::Richter { bool getTempoSyncSwitch() const { return _tempoSyncSwitch; } bool getInvertSwitch() const { return _invertSwitch; } int getWave() const { return _wave; } + int getOutputMode() { return _outputMode; } double getTempoNumer() const { return _tempoNumer; } double getTempoDenom() const { return _tempoDenom; } double getFreq() { return _rawFreq; } @@ -81,6 +82,7 @@ namespace WECore::Richter { void setTempoSyncSwitch(bool val) { _tempoSyncSwitch = val; } void setInvertSwitch(bool val) { _invertSwitch = val; } inline void setWave(int val); + void setOutputMode(int val) { _outputMode = Parameters::OUTPUTMODE.BoundsCheck(val); } void setTempoNumer(int val) { _tempoNumer = Parameters::TEMPONUMER.BoundsCheck(val); } void setTempoDenom (int val) { _tempoDenom = Parameters::TEMPODENOM.BoundsCheck(val); } void setFreq(double val) { _rawFreq = Parameters::FREQ.BoundsCheck(val); } @@ -119,7 +121,8 @@ namespace WECore::Richter { protected: int _wave, - _indexOffset; + _indexOffset, + _outputMode; bool _bypassSwitch, _tempoSyncSwitch, @@ -201,6 +204,7 @@ namespace WECore::Richter { RichterLFO::RichterLFO() : _wave(Parameters::WAVE.defaultValue), _indexOffset(0), + _outputMode(Parameters::OUTPUTMODE.defaultValue), _bypassSwitch(Parameters::LFOSWITCH_DEFAULT), _tempoSyncSwitch(Parameters::TEMPOSYNC_DEFAULT), _phaseSyncSwitch(Parameters::PHASESYNC_DEFAULT), @@ -394,7 +398,9 @@ namespace WECore::Richter { const int index {static_cast(_wavetablePosition)}; - return _waveArrayPointer[(index + _indexOffset + phaseIndexOffset) % Wavetables::SIZE]; + const double wavetableValue {_waveArrayPointer[(index + _indexOffset + phaseIndexOffset) % Wavetables::SIZE]}; + + return _outputMode == Parameters::OUTPUTMODE.BIPOLAR ? wavetableValue : (wavetableValue + 1); } double RichterLFO::_getNextOutputImpl(double /*inSample*/) { @@ -412,7 +418,7 @@ namespace WECore::Richter { _modulatedDepthValue = depth; if (_bypassSwitch) { - // Produce a value in the range -1:1, invert if needed + // Produce a value in the range -1:1 (or 0:2), invert if needed return (lfoValue * depth) * (_invertSwitch ? -1 : 1); } else { return 0; diff --git a/WECore/RichterLFO/RichterParameters.h b/WECore/RichterLFO/RichterParameters.h index 0c5495b..1d276ec 100644 --- a/WECore/RichterLFO/RichterParameters.h +++ b/WECore/RichterLFO/RichterParameters.h @@ -38,6 +38,16 @@ namespace WECore::Richter::Parameters { const WaveParameter WAVE; + class OutputModeParameter : public ParameterDefinition::BaseParameter { + public: + OutputModeParameter() : ParameterDefinition::BaseParameter(UNIPOLAR, BIPOLAR, BIPOLAR) {} + + static constexpr int UNIPOLAR {1}, + BIPOLAR {2}; + }; + + const OutputModeParameter OUTPUTMODE; + const ParameterDefinition::RangedParameter TEMPONUMER(1, 32, 1), TEMPODENOM(1, 32, 1); diff --git a/WECore/RichterLFO/Tests/RichterLFOPairTests.cpp b/WECore/RichterLFO/Tests/RichterLFOPairTests.cpp index 2c3872e..e40a7b2 100644 --- a/WECore/RichterLFO/Tests/RichterLFOPairTests.cpp +++ b/WECore/RichterLFO/Tests/RichterLFOPairTests.cpp @@ -33,6 +33,7 @@ SCENARIO("RichterLFOPair: Parameters can be set and retrieved correctly") { CHECK(mLFOPair.LFO.getTempoSyncSwitch() == false); CHECK(mLFOPair.LFO.getInvertSwitch() == false); CHECK(mLFOPair.LFO.getWave() == 1); + CHECK(mLFOPair.LFO.getOutputMode() == 2); CHECK(mLFOPair.LFO.getDepth() == Approx(0.5)); CHECK(mLFOPair.LFO.getFreq() == Approx(2.0)); CHECK(mLFOPair.LFO.getManualPhase() == Approx(0.0)); @@ -44,6 +45,7 @@ SCENARIO("RichterLFOPair: Parameters can be set and retrieved correctly") { CHECK(mLFOPair.MOD->getTempoSyncSwitch() == false); CHECK(mLFOPair.MOD->getInvertSwitch() == false); CHECK(mLFOPair.MOD->getWave() == 1); + CHECK(mLFOPair.MOD->getOutputMode() == 2); CHECK(mLFOPair.MOD->getDepth() == Approx(0.5)); CHECK(mLFOPair.MOD->getFreq() == Approx(2.0)); CHECK(mLFOPair.MOD->getManualPhase() == Approx(0.0)); @@ -58,6 +60,7 @@ SCENARIO("RichterLFOPair: Parameters can be set and retrieved correctly") { mLFOPair.LFO.setTempoSyncSwitch(true); mLFOPair.LFO.setInvertSwitch(true); mLFOPair.LFO.setWave(2); + mLFOPair.LFO.setOutputMode(1); mLFOPair.LFO.setDepth(0.1); mLFOPair.LFO.setFreq(3); mLFOPair.LFO.setManualPhase(0.5); @@ -69,6 +72,7 @@ SCENARIO("RichterLFOPair: Parameters can be set and retrieved correctly") { mLFOPair.MOD->setTempoSyncSwitch(true); mLFOPair.MOD->setInvertSwitch(true); mLFOPair.MOD->setWave(3); + mLFOPair.MOD->setOutputMode(1); mLFOPair.MOD->setDepth(0.5); mLFOPair.MOD->setFreq(6); mLFOPair.MOD->setManualPhase(0.7); @@ -81,6 +85,7 @@ SCENARIO("RichterLFOPair: Parameters can be set and retrieved correctly") { CHECK(mLFOPair.LFO.getTempoSyncSwitch() == true); CHECK(mLFOPair.LFO.getInvertSwitch() == true); CHECK(mLFOPair.LFO.getWave() == 2); + CHECK(mLFOPair.LFO.getOutputMode() == 1); CHECK(mLFOPair.LFO.getDepth() == Approx(0.1)); CHECK(mLFOPair.LFO.getFreq() == Approx(3.0)); CHECK(mLFOPair.LFO.getManualPhase() == Approx(0.5)); @@ -92,6 +97,7 @@ SCENARIO("RichterLFOPair: Parameters can be set and retrieved correctly") { CHECK(mLFOPair.MOD->getTempoSyncSwitch() == true); CHECK(mLFOPair.MOD->getInvertSwitch() == true); CHECK(mLFOPair.MOD->getWave() == 3); + CHECK(mLFOPair.MOD->getOutputMode() == 1); CHECK(mLFOPair.MOD->getDepth() == Approx(0.5)); CHECK(mLFOPair.MOD->getFreq() == Approx(6.0)); CHECK(mLFOPair.MOD->getManualPhase() == Approx(0.7)); @@ -108,6 +114,7 @@ SCENARIO("RichterLFOPair: Parameters enforce their bounds correctly") { WHEN("All parameter values are too low") { mLFOPair.LFO.setWave(-5); + mLFOPair.LFO.setOutputMode(-5); mLFOPair.LFO.setDepth(-5); mLFOPair.LFO.setFreq(-5); mLFOPair.LFO.setManualPhase(-5); @@ -115,6 +122,7 @@ SCENARIO("RichterLFOPair: Parameters enforce their bounds correctly") { mLFOPair.LFO.setTempoDenom(-5); mLFOPair.MOD->setWave(-5); + mLFOPair.MOD->setOutputMode(-5); mLFOPair.MOD->setDepth(-5); mLFOPair.MOD->setFreq(-5); mLFOPair.MOD->setManualPhase(-5); @@ -123,6 +131,7 @@ SCENARIO("RichterLFOPair: Parameters enforce their bounds correctly") { THEN("Parameters enforce their lower bounds") { CHECK(mLFOPair.LFO.getWave() == 1); + CHECK(mLFOPair.LFO.getOutputMode() == 1); CHECK(mLFOPair.LFO.getDepth() == Approx(0.0)); CHECK(mLFOPair.LFO.getFreq() == Approx(0.0)); CHECK(mLFOPair.LFO.getManualPhase() == Approx(0.0)); @@ -130,6 +139,7 @@ SCENARIO("RichterLFOPair: Parameters enforce their bounds correctly") { CHECK(mLFOPair.LFO.getTempoDenom() == Approx(1.0)); CHECK(mLFOPair.MOD->getWave() == 1); + CHECK(mLFOPair.MOD->getOutputMode() == 1); CHECK(mLFOPair.MOD->getDepth() == Approx(0.0)); CHECK(mLFOPair.MOD->getFreq() == Approx(0.0)); CHECK(mLFOPair.MOD->getManualPhase() == Approx(0.0)); @@ -140,6 +150,7 @@ SCENARIO("RichterLFOPair: Parameters enforce their bounds correctly") { WHEN("All parameter values are too high") { mLFOPair.LFO.setWave(100); + mLFOPair.LFO.setOutputMode(100); mLFOPair.LFO.setDepth(100); mLFOPair.LFO.setFreq(100); mLFOPair.LFO.setManualPhase(10000); @@ -147,6 +158,7 @@ SCENARIO("RichterLFOPair: Parameters enforce their bounds correctly") { mLFOPair.LFO.setTempoDenom(100); mLFOPair.MOD->setWave(100); + mLFOPair.MOD->setOutputMode(100); mLFOPair.MOD->setDepth(100); mLFOPair.MOD->setFreq(100); mLFOPair.MOD->setManualPhase(10000); @@ -155,6 +167,7 @@ SCENARIO("RichterLFOPair: Parameters enforce their bounds correctly") { THEN("Parameters enforce their upper bounds") { CHECK(mLFOPair.LFO.getWave() == 4); + CHECK(mLFOPair.LFO.getOutputMode() == 2); CHECK(mLFOPair.LFO.getDepth() == Approx(1.0)); CHECK(mLFOPair.LFO.getFreq() == Approx(20.0)); CHECK(mLFOPair.LFO.getManualPhase() == Approx(360.0)); @@ -162,6 +175,7 @@ SCENARIO("RichterLFOPair: Parameters enforce their bounds correctly") { CHECK(mLFOPair.LFO.getTempoDenom() == Approx(32.0)); CHECK(mLFOPair.MOD->getWave() == 4); + CHECK(mLFOPair.MOD->getOutputMode() == 2); CHECK(mLFOPair.MOD->getDepth() == Approx(1.0)); CHECK(mLFOPair.MOD->getFreq() == Approx(20.0)); CHECK(mLFOPair.MOD->getManualPhase() == Approx(360.0));