BogaudioModules

BogaudioModules for VCV Rack
Log | Files | Refs | README | LICENSE

commit 18f1ab9da5fa91c182b319dc9ef5d25f185fc55c
parent b68a62b1aff07f0df9fb8afb5d63925c715b79f4
Author: Matt Demanett <matt@demanett.net>
Date:   Mon,  8 Jan 2018 22:41:25 -0500

Resume loop on load feature for each envelope.

Diffstat:
Msrc/BogaudioModules.hpp | 6++++++
Msrc/DADSRH.cpp | 22+++++++++++++++++++---
Msrc/DADSRHCore.cpp | 7++++++-
Msrc/DADSRHCore.hpp | 11++++++++++-
Msrc/DADSRHPlus.cpp | 22+++++++++++++++++++---
Msrc/DGate.cpp | 48+++++++-----------------------------------------
Msrc/Shaper.cpp | 23++++++++++++++++++++---
Msrc/ShaperCore.cpp | 7++++++-
Msrc/ShaperCore.hpp | 11++++++++++-
Msrc/ShaperPlus.cpp | 24+++++++++++++++++++++---
Asrc/trigger_on_load.cpp | 25+++++++++++++++++++++++++
Asrc/trigger_on_load.hpp | 43+++++++++++++++++++++++++++++++++++++++++++
12 files changed, 192 insertions(+), 57 deletions(-)

diff --git a/src/BogaudioModules.hpp b/src/BogaudioModules.hpp @@ -6,7 +6,9 @@ #include <algorithm> #include "rack.hpp" + #include "dsp/digital.hpp" +#include "trigger_on_load.hpp" #include "widgets.hpp" using namespace rack; @@ -18,18 +20,22 @@ namespace bogaudio { struct ShaperWidget : ModuleWidget { ShaperWidget(); + virtual Menu* createContextMenu() override; }; struct ShaperPlusWidget : ModuleWidget { ShaperPlusWidget(); + virtual Menu* createContextMenu() override; }; struct DADSRHWidget : ModuleWidget { DADSRHWidget(); + virtual Menu* createContextMenu() override; }; struct DADSRHPlusWidget : ModuleWidget { DADSRHPlusWidget(); + virtual Menu* createContextMenu() override; }; struct AnalyzerWidget : ModuleWidget { diff --git a/src/DADSRH.cpp b/src/DADSRH.cpp @@ -1,7 +1,7 @@ #include "DADSRHCore.hpp" -struct DADSRH : Module { +struct DADSRH : TriggerOnLoadModule { enum ParamsIds { DELAY_PARAM, ATTACK_PARAM, @@ -52,7 +52,7 @@ struct DADSRH : Module { DADSRHCore _core; - DADSRH() : Module( + DADSRH() : TriggerOnLoadModule( NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, @@ -104,7 +104,10 @@ struct DADSRH : Module { lights[DECAY_SHAPE3_LIGHT], lights[RELEASE_SHAPE1_LIGHT], lights[RELEASE_SHAPE2_LIGHT], - lights[RELEASE_SHAPE3_LIGHT] + lights[RELEASE_SHAPE3_LIGHT], + + _triggerOnLoad, + _shouldTriggerOnLoad ) { reset(); } @@ -116,6 +119,10 @@ struct DADSRH : Module { virtual void step() override { _core.step(); } + + virtual bool shouldTriggerOnNextLoad() override { + return _core._stage != _core.STOPPED_STAGE; + } }; @@ -210,3 +217,12 @@ DADSRHWidget::DADSRHWidget() { addChild(createLight<TinyLight<GreenLight>>(releaseShape2LightPosition, module, DADSRH::RELEASE_SHAPE2_LIGHT)); addChild(createLight<TinyLight<GreenLight>>(releaseShape3LightPosition, module, DADSRH::RELEASE_SHAPE3_LIGHT)); } + +Menu* DADSRHWidget::createContextMenu() { + DADSRH* dadsrh = dynamic_cast<DADSRH*>(module); + assert(dadsrh); + Menu* menu = ModuleWidget::createContextMenu(); + menu->addChild(new MenuLabel()); + menu->addChild(new TriggerOnLoadMenuItem(dadsrh, "Resume Loop on Load")); + return menu; +} diff --git a/src/DADSRHCore.cpp b/src/DADSRHCore.cpp @@ -16,7 +16,10 @@ void DADSRHCore::step() { const float shapeInverseExponent = 0.5; bool slow = _speedParam.value <= 0.5; - if (_trigger.process(_triggerParam.value + _triggerInput.value)) { + if ( + _trigger.process(_triggerParam.value + _triggerInput.value) || + (_firstStep && _triggerOnLoad && _shouldTriggerOnLoad && _loopParam.value < 0.5 && _modeParam.value < 0.5) + ) { if (_stage == STOPPED_STAGE || _retriggerParam.value <= 0.5) { _stage = DELAY_STAGE; _holdProgress = _stageProgress = _envelope = 0.0; @@ -237,6 +240,8 @@ void DADSRHCore::step() { _releaseShape1Light.value = (int)_releaseShapeParam.value == SHAPE1; _releaseShape2Light.value = (int)_releaseShapeParam.value == SHAPE2; _releaseShape3Light.value = (int)_releaseShapeParam.value == SHAPE3; + + _firstStep = false; } float DADSRHCore::stepAmount(const Param& knob, const Input* cv, bool slow, bool allowZero) { diff --git a/src/DADSRHCore.hpp b/src/DADSRHCore.hpp @@ -60,6 +60,9 @@ struct DADSRHCore { Light& _releaseShape2Light; Light& _releaseShape3Light; + bool _firstStep = true; + bool& _triggerOnLoad; + bool& _shouldTriggerOnLoad; SchmittTrigger _trigger; PulseGenerator _triggerOuptutPulseGen; Stage _stage; @@ -111,7 +114,10 @@ struct DADSRHCore { Light& decayShape3Light, Light& releaseShape1Light, Light& releaseShape2Light, - Light& releaseShape3Light + Light& releaseShape3Light, + + bool& triggerOnLoad, + bool& shouldTriggerOnLoad ) : _delayParam(delayParam) , _attackParam(attackParam) , _decayParam(decayParam) @@ -158,6 +164,9 @@ struct DADSRHCore { , _releaseShape1Light(releaseShape1Light) , _releaseShape2Light(releaseShape2Light) , _releaseShape3Light(releaseShape3Light) + + , _triggerOnLoad(triggerOnLoad) + , _shouldTriggerOnLoad(shouldTriggerOnLoad) { reset(); } diff --git a/src/DADSRHPlus.cpp b/src/DADSRHPlus.cpp @@ -1,7 +1,7 @@ #include "DADSRHCore.hpp" -struct DADSRHPlus : Module { +struct DADSRHPlus : TriggerOnLoadModule { enum ParamsIds { DELAY_PARAM, ATTACK_PARAM, @@ -63,7 +63,7 @@ struct DADSRHPlus : Module { DADSRHCore _core; - DADSRHPlus() : Module( + DADSRHPlus() : TriggerOnLoadModule( NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, @@ -115,7 +115,10 @@ struct DADSRHPlus : Module { lights[DECAY_SHAPE3_LIGHT], lights[RELEASE_SHAPE1_LIGHT], lights[RELEASE_SHAPE2_LIGHT], - lights[RELEASE_SHAPE3_LIGHT] + lights[RELEASE_SHAPE3_LIGHT], + + _triggerOnLoad, + _shouldTriggerOnLoad ) { reset(); } @@ -127,6 +130,10 @@ struct DADSRHPlus : Module { virtual void step() override { _core.step(); } + + virtual bool shouldTriggerOnNextLoad() override { + return _core._stage != _core.STOPPED_STAGE; + } }; DADSRHPlusWidget::DADSRHPlusWidget() { @@ -242,3 +249,12 @@ DADSRHPlusWidget::DADSRHPlusWidget() { addChild(createLight<TinyLight<GreenLight>>(releaseShape2LightPosition, module, DADSRHPlus::RELEASE_SHAPE2_LIGHT)); addChild(createLight<TinyLight<GreenLight>>(releaseShape3LightPosition, module, DADSRHPlus::RELEASE_SHAPE3_LIGHT)); } + +Menu* DADSRHPlusWidget::createContextMenu() { + DADSRHPlus* dadsrhPlus = dynamic_cast<DADSRHPlus*>(module); + assert(dadsrhPlus); + Menu* menu = ModuleWidget::createContextMenu(); + menu->addChild(new MenuLabel()); + menu->addChild(new TriggerOnLoadMenuItem(dadsrhPlus, "Resume Loop on Load")); + return menu; +} diff --git a/src/DGate.cpp b/src/DGate.cpp @@ -1,7 +1,7 @@ #include "BogaudioModules.hpp" -struct DGate : Module { +struct DGate : TriggerOnLoadModule { enum ParamsIds { DELAY_PARAM, GATE_PARAM, @@ -34,42 +34,23 @@ struct DGate : Module { }; bool _firstStep = true; - bool _loopOnLoad = true; - bool _shouldLoopOnLoad = true; SchmittTrigger _trigger; PulseGenerator _triggerOuptutPulseGen; Stage _stage; float _stageProgress; - DGate() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { + DGate() : TriggerOnLoadModule(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { reset(); } - virtual json_t* toJson() override; - virtual void fromJson(json_t* root) override; virtual void reset() override; virtual void step() override; bool stepStage(Param& knob); + virtual bool shouldTriggerOnNextLoad() override { + return _stage != STOPPED_STAGE; + }; }; -json_t* DGate::toJson() { - json_t* root = json_object(); - json_object_set_new(root, "loopOnLoad", json_boolean(_loopOnLoad)); - json_object_set_new(root, "shouldLoopOnLoad", json_boolean(_stage != STOPPED_STAGE)); - return root; -} - -void DGate::fromJson(json_t* root) { - json_t* loopOnLoad = json_object_get(root, "loopOnLoad"); - if (loopOnLoad) { - _loopOnLoad = json_is_true(loopOnLoad); - } - json_t* shouldLoopOnLoad = json_object_get(root, "shouldLoopOnLoad"); - if (shouldLoopOnLoad) { - _shouldLoopOnLoad = json_is_true(shouldLoopOnLoad); - } -} - void DGate::reset() { _trigger.reset(); _triggerOuptutPulseGen.process(10.0); @@ -82,7 +63,7 @@ void DGate::step() { bool complete = false; if ( _trigger.process(params[TRIGGER_PARAM].value + inputs[TRIGGER_INPUT].value) || - (_firstStep && _loopOnLoad && _shouldLoopOnLoad && params[LOOP_PARAM].value <= 0.0) + (_firstStep && _triggerOnLoad && _shouldTriggerOnLoad && params[LOOP_PARAM].value <= 0.0) ) { _stage = DELAY_STAGE; _stageProgress = 0.0; @@ -184,26 +165,11 @@ DGateWidget::DGateWidget() { addChild(createLight<TinyLight<GreenLight>>(gateLightPosition, module, DGate::GATE_LIGHT)); } -struct DGateWidgetAutoloopMenuItem : MenuItem { - DGate* _module; - DGateWidgetAutoloopMenuItem(DGate* module, const char* label) : _module(module) { - this->text = label; - } - - void onAction(EventAction &e) override { - _module->_loopOnLoad = !_module->_loopOnLoad; - } - - void step() override { - rightText = _module->_loopOnLoad ? "✔" : ""; - } -}; - Menu* DGateWidget::createContextMenu() { DGate* dgate = dynamic_cast<DGate*>(module); assert(dgate); Menu* menu = ModuleWidget::createContextMenu(); menu->addChild(new MenuLabel()); - menu->addChild(new DGateWidgetAutoloopMenuItem(dgate, "Loop on Patch Load")); + menu->addChild(new TriggerOnLoadMenuItem(dgate, "Resume Loop on Load")); return menu; } diff --git a/src/Shaper.cpp b/src/Shaper.cpp @@ -1,6 +1,7 @@ + #include "ShaperCore.hpp" -struct Shaper : Module { +struct Shaper : TriggerOnLoadModule { enum ParamIds { ATTACK_PARAM, ON_PARAM, @@ -38,7 +39,7 @@ struct Shaper : Module { ShaperCore _core; - Shaper() : Module( + Shaper() : TriggerOnLoadModule( NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, @@ -76,7 +77,10 @@ struct Shaper : Module { lights[ATTACK_LIGHT], lights[ON_LIGHT], lights[DECAY_LIGHT], - lights[OFF_LIGHT] + lights[OFF_LIGHT], + + _triggerOnLoad, + _shouldTriggerOnLoad ) { reset(); @@ -89,6 +93,10 @@ struct Shaper : Module { virtual void step() override { _core.step(); } + + virtual bool shouldTriggerOnNextLoad() override { + return _core._stage != _core.STOPPED_STAGE; + } }; @@ -159,3 +167,12 @@ ShaperWidget::ShaperWidget() { addChild(createLight<TinyLight<GreenLight>>(decayLightPosition, module, Shaper::DECAY_LIGHT)); addChild(createLight<TinyLight<GreenLight>>(offLightPosition, module, Shaper::OFF_LIGHT)); } + +Menu* ShaperWidget::createContextMenu() { + Shaper* shaper = dynamic_cast<Shaper*>(module); + assert(shaper); + Menu* menu = ModuleWidget::createContextMenu(); + menu->addChild(new MenuLabel()); + menu->addChild(new TriggerOnLoadMenuItem(shaper, "Resume Loop on Load")); + return menu; +} diff --git a/src/ShaperCore.cpp b/src/ShaperCore.cpp @@ -11,7 +11,10 @@ void ShaperCore::reset() { void ShaperCore::step() { bool complete = false; bool slow = _speedParam.value <= 0.0; - if (_trigger.process(_triggerParam.value + _triggerInput.value)) { + if ( + _trigger.process(_triggerParam.value + _triggerInput.value) || + (_firstStep && _triggerOnLoad && _shouldTriggerOnLoad && _loopParam.value <= 0.0) + ) { _stage = ATTACK_STAGE; _stageProgress = 0.0; } @@ -109,6 +112,8 @@ void ShaperCore::step() { _onLight.value = _stage == ON_STAGE; _decayLight.value = _stage == DECAY_STAGE; _offLight.value = _stage == OFF_STAGE; + + _firstStep = false; } bool ShaperCore::stepStage(const Param& knob, const Input* cv, bool slow) { diff --git a/src/ShaperCore.hpp b/src/ShaperCore.hpp @@ -45,6 +45,9 @@ struct ShaperCore { Light& _decayLight; Light& _offLight; + bool _firstStep = true; + bool& _triggerOnLoad; + bool& _shouldTriggerOnLoad; SchmittTrigger _trigger; PulseGenerator _triggerOuptutPulseGen; Stage _stage; @@ -82,7 +85,10 @@ struct ShaperCore { Light& attackLight, Light& onLight, Light& decayLight, - Light& offLight + Light& offLight, + + bool& triggerOnLoad, + bool& shouldTriggerOnLoad ) : _attackParam(attackParam) , _onParam(onParam) , _decayParam(decayParam) @@ -115,6 +121,9 @@ struct ShaperCore { , _onLight(onLight) , _decayLight(decayLight) , _offLight(offLight) + + , _triggerOnLoad(triggerOnLoad) + , _shouldTriggerOnLoad(shouldTriggerOnLoad) { reset(); } diff --git a/src/ShaperPlus.cpp b/src/ShaperPlus.cpp @@ -1,6 +1,7 @@ + #include "ShaperCore.hpp" -struct ShaperPlus : Module { +struct ShaperPlus : TriggerOnLoadModule { enum ParamIds { ATTACK_PARAM, ON_PARAM, @@ -45,7 +46,7 @@ struct ShaperPlus : Module { ShaperCore _core; - ShaperPlus() : Module( + ShaperPlus() : TriggerOnLoadModule( NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, @@ -83,7 +84,10 @@ struct ShaperPlus : Module { lights[ATTACK_LIGHT], lights[ON_LIGHT], lights[DECAY_LIGHT], - lights[OFF_LIGHT] + lights[OFF_LIGHT], + + _triggerOnLoad, + _shouldTriggerOnLoad ) { reset(); @@ -96,8 +100,13 @@ struct ShaperPlus : Module { virtual void step() override { _core.step(); } + + virtual bool shouldTriggerOnNextLoad() override { + return _core._stage != _core.STOPPED_STAGE; + } }; + ShaperPlusWidget::ShaperPlusWidget() { ShaperPlus *module = new ShaperPlus(); setModule(module); @@ -187,3 +196,12 @@ ShaperPlusWidget::ShaperPlusWidget() { addChild(createLight<TinyLight<GreenLight>>(decayLightPosition, module, ShaperPlus::DECAY_LIGHT)); addChild(createLight<TinyLight<GreenLight>>(offLightPosition, module, ShaperPlus::OFF_LIGHT)); } + +Menu* ShaperPlusWidget::createContextMenu() { + ShaperPlus* shaperPlus = dynamic_cast<ShaperPlus*>(module); + assert(shaperPlus); + Menu* menu = ModuleWidget::createContextMenu(); + menu->addChild(new MenuLabel()); + menu->addChild(new TriggerOnLoadMenuItem(shaperPlus, "Resume Loop on Load")); + return menu; +} diff --git a/src/trigger_on_load.cpp b/src/trigger_on_load.cpp @@ -0,0 +1,25 @@ + +#include "trigger_on_load.hpp" + +using namespace bogaudio; + +#define TRIGGER_ON_LOAD "triggerOnLoad" +#define SHOULD_TRIGGER_ON_LOAD "shouldTriggerOnLoad" + +json_t* TriggerOnLoadModule::toJson() { + json_t* root = json_object(); + json_object_set_new(root, TRIGGER_ON_LOAD, json_boolean(_triggerOnLoad)); + json_object_set_new(root, SHOULD_TRIGGER_ON_LOAD, json_boolean(shouldTriggerOnNextLoad())); + return root; +} + +void TriggerOnLoadModule::fromJson(json_t* root) { + json_t* tol = json_object_get(root, TRIGGER_ON_LOAD); + if (tol) { + _triggerOnLoad = json_is_true(tol); + } + json_t* stol = json_object_get(root, SHOULD_TRIGGER_ON_LOAD); + if (stol) { + _shouldTriggerOnLoad = json_is_true(stol); + } +} diff --git a/src/trigger_on_load.hpp b/src/trigger_on_load.hpp @@ -0,0 +1,43 @@ + +#include "rack.hpp" + +using namespace rack; + +extern Plugin *plugin; + +namespace bogaudio { + +struct TriggerOnLoadModule : Module { + bool _triggerOnLoad = true; + bool _shouldTriggerOnLoad = true; + + TriggerOnLoadModule(int numParams, int numInputs, int numOutputs, int numLights) + : Module(numParams, numInputs, numOutputs, numLights) + { + } + + virtual json_t* toJson() override; + virtual void fromJson(json_t* root) override; + + virtual bool shouldTriggerOnNextLoad() = 0; +}; + +struct TriggerOnLoadMenuItem : MenuItem { + TriggerOnLoadModule* _module; + + TriggerOnLoadMenuItem(TriggerOnLoadModule* module, const char* label) + : _module(module) + { + this->text = label; + } + + void onAction(EventAction &e) override { + _module->_triggerOnLoad = !_module->_triggerOnLoad; + } + + void step() override { + rightText = _module->_triggerOnLoad ? "✔" : ""; + } +}; + +} // namespace bogaudio