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:
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