BogaudioModules

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

commit 62a0883bd4946d4056e15eadb8892f996ddd4024
parent 538817a5f18b4ff81257da2b7c891372245f4548
Author: Matt Demanett <matt@demanett.net>
Date:   Sun,  5 May 2019 00:39:05 -0400

8:1, 1:8, ADDR-SEQ: add "Select on clock" option: the effective select value only changes when a clock is received. #46

Diffstat:
MREADME.md | 2++
Msrc/AddrSeq.cpp | 50+++++++++++++++++++++++++++++++++++++++++++++++---
Msrc/AddrSeq.hpp | 4++++
Msrc/EightOne.cpp | 50+++++++++++++++++++++++++++++++++++++++++++++++---
Msrc/EightOne.hpp | 4++++
Msrc/OneEight.cpp | 50+++++++++++++++++++++++++++++++++++++++++++++++---
Msrc/OneEight.hpp | 4++++
7 files changed, 155 insertions(+), 9 deletions(-)

diff --git a/README.md b/README.md @@ -333,6 +333,8 @@ As a multiplexer, it routes an input to the output under control of the SELECT k Both functions may be used simultaneously: the SELECT+CV value is added to the sequential/clocked value, wrapping around. Note that the STEPS value only affects the sequential value; for example, using a clock input and setting STEPS to 2 will yield an alternation between two adjacent inputs, but this pair can be selected with the SELECT knob or CV. +On the context (right-click) menu, if option "Select on clock" is selected, then the select value (knob and CV) is checked and used to modify the active step only when a clock is received, rather than continuously. + #### 1:8 1:8 is the opposite of 8:1 -- it routes a single input to 1 of 8 outputs. The control circuit behavior (CLOCK, SELECT, etc) is the same. diff --git a/src/AddrSeq.cpp b/src/AddrSeq.cpp @@ -1,6 +1,8 @@ #include "AddrSeq.hpp" +#define SELECT_ON_CLOCK "select_on_clock" + void AddrSeq::onReset() { _step = 0; _clock.reset(); @@ -11,6 +13,19 @@ void AddrSeq::onSampleRateChange() { _timer.setParams(engineGetSampleRate(), 0.001f); } +json_t* AddrSeq::toJson() { + json_t* root = json_object(); + json_object_set_new(root, SELECT_ON_CLOCK, json_boolean(_selectOnClock)); + return root; +} + +void AddrSeq::fromJson(json_t* root) { + json_t* s = json_object_get(root, SELECT_ON_CLOCK); + if (s) { + _selectOnClock = json_is_true(s); + } +} + void AddrSeq::step() { bool reset = _reset.process(inputs[RESET_INPUT].value); if (reset) { @@ -19,13 +34,17 @@ void AddrSeq::step() { bool timer = _timer.next(); bool clock = _clock.process(inputs[CLOCK_INPUT].value) && !timer; - int steps = clamp(params[STEPS_PARAM].value, 1.0f, 8.0f); + int steps = params[STEPS_PARAM].value; int reverse = 1 - 2 * (params[DIRECTION_PARAM].value == 0.0f); _step = (_step + reverse * clock) % steps; _step += (_step < 0) * steps; _step -= _step * reset; - int step = _step + (int)params[SELECT_PARAM].value; - step += (int)(clamp(inputs[SELECT_INPUT].value, 0.0f, 10.0f) * 0.1f * 8.0f); + int select = params[SELECT_PARAM].value; + select += clamp(inputs[SELECT_INPUT].value, 0.0f, 10.0f) * 0.1f * 8.0f; + if (!_selectOnClock || clock) { + _select = select; + } + int step = _step + _select; step = step % 8; float out = 0.0f; @@ -36,6 +55,24 @@ void AddrSeq::step() { outputs[OUT_OUTPUT].value = out * 10.0f; } +struct SelectOnClockMenuItem : MenuItem { + AddrSeq* _module; + + SelectOnClockMenuItem(AddrSeq* module, const char* label) + : _module(module) + { + this->text = label; + } + + void onAction(EventAction &e) override { + _module->_selectOnClock = !_module->_selectOnClock; + } + + void step() override { + rightText = _module->_selectOnClock ? "✔" : ""; + } +}; + struct AddrSeqWidget : ModuleWidget { static constexpr int hp = 6; @@ -116,6 +153,13 @@ struct AddrSeqWidget : ModuleWidget { addChild(ModuleLightWidget::create<SmallLight<GreenLight>>(out7LightPosition, module, AddrSeq::OUT7_LIGHT)); addChild(ModuleLightWidget::create<SmallLight<GreenLight>>(out8LightPosition, module, AddrSeq::OUT8_LIGHT)); } + + void appendContextMenu(Menu* menu) override { + AddrSeq* m = dynamic_cast<AddrSeq*>(module); + assert(m); + menu->addChild(new MenuLabel()); + menu->addChild(new SelectOnClockMenuItem(m, "Select on clock")); + } }; Model* modelAddrSeq = createModel<AddrSeq, AddrSeqWidget>("Bogaudio-AddrSeq", "ADDR-SEQ", "voltage-addressable sequencer", SEQUENCER_TAG); diff --git a/src/AddrSeq.hpp b/src/AddrSeq.hpp @@ -53,6 +53,8 @@ struct AddrSeq : Module { Trigger _reset; Timer _timer; int _step; + bool _selectOnClock = false; + int _select = 0; AddrSeq() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { onReset(); @@ -61,6 +63,8 @@ struct AddrSeq : Module { void onReset() override; void onSampleRateChange() override; + json_t* toJson() override; + void fromJson(json_t* root) override; void step() override; }; diff --git a/src/EightOne.cpp b/src/EightOne.cpp @@ -1,6 +1,8 @@ #include "EightOne.hpp" +#define SELECT_ON_CLOCK "select_on_clock" + void EightOne::onReset() { _step = 0; _clock.reset(); @@ -11,6 +13,19 @@ void EightOne::onSampleRateChange() { _timer.setParams(engineGetSampleRate(), 0.001f); } +json_t* EightOne::toJson() { + json_t* root = json_object(); + json_object_set_new(root, SELECT_ON_CLOCK, json_boolean(_selectOnClock)); + return root; +} + +void EightOne::fromJson(json_t* root) { + json_t* s = json_object_get(root, SELECT_ON_CLOCK); + if (s) { + _selectOnClock = json_is_true(s); + } +} + void EightOne::step() { bool reset = _reset.process(inputs[RESET_INPUT].value); if (reset) { @@ -19,13 +34,17 @@ void EightOne::step() { bool timer = _timer.next(); bool clock = _clock.process(inputs[CLOCK_INPUT].value) && !timer; - int steps = clamp(params[STEPS_PARAM].value, 1.0f, 8.0f); + int steps = params[STEPS_PARAM].value; int reverse = 1 - 2 * (params[DIRECTION_PARAM].value == 0.0f); _step = (_step + reverse * clock) % steps; _step += (_step < 0) * steps; _step -= _step * reset; - int step = _step + (int)params[SELECT_PARAM].value; - step += (int)(clamp(inputs[SELECT_INPUT].value, 0.0f, 10.0f) * 0.1f * 8.0f); + int select = params[SELECT_PARAM].value; + select += clamp(inputs[SELECT_INPUT].value, 0.0f, 10.0f) * 0.1f * 8.0f; + if (!_selectOnClock || clock) { + _select = select; + } + int step = _step + _select; step = step % 8; float out = 0.0f; @@ -36,6 +55,24 @@ void EightOne::step() { outputs[OUT_OUTPUT].value = out; } +struct SelectOnClockMenuItem : MenuItem { + EightOne* _module; + + SelectOnClockMenuItem(EightOne* module, const char* label) + : _module(module) + { + this->text = label; + } + + void onAction(EventAction &e) override { + _module->_selectOnClock = !_module->_selectOnClock; + } + + void step() override { + rightText = _module->_selectOnClock ? "✔" : ""; + } +}; + struct EightOneWidget : ModuleWidget { static constexpr int hp = 6; @@ -116,6 +153,13 @@ struct EightOneWidget : ModuleWidget { addChild(ModuleLightWidget::create<SmallLight<GreenLight>>(in7LightPosition, module, EightOne::IN7_LIGHT)); addChild(ModuleLightWidget::create<SmallLight<GreenLight>>(in8LightPosition, module, EightOne::IN8_LIGHT)); } + + void appendContextMenu(Menu* menu) override { + EightOne* m = dynamic_cast<EightOne*>(module); + assert(m); + menu->addChild(new MenuLabel()); + menu->addChild(new SelectOnClockMenuItem(m, "Select on clock")); + } }; Model* modelEightOne = createModel<EightOne, EightOneWidget>("Bogaudio-EightOne", "8:1", "demux & sequential switch", SWITCH_TAG); diff --git a/src/EightOne.hpp b/src/EightOne.hpp @@ -53,6 +53,8 @@ struct EightOne : Module { Trigger _reset; Timer _timer; int _step; + bool _selectOnClock = false; + int _select = 0; EightOne() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { onReset(); @@ -61,6 +63,8 @@ struct EightOne : Module { void onReset() override; void onSampleRateChange() override; + json_t* toJson() override; + void fromJson(json_t* root) override; void step() override; }; diff --git a/src/OneEight.cpp b/src/OneEight.cpp @@ -1,6 +1,8 @@ #include "OneEight.hpp" +#define SELECT_ON_CLOCK "select_on_clock" + void OneEight::onReset() { _step = 0; _clock.reset(); @@ -11,6 +13,19 @@ void OneEight::onSampleRateChange() { _timer.setParams(engineGetSampleRate(), 0.001f); } +json_t* OneEight::toJson() { + json_t* root = json_object(); + json_object_set_new(root, SELECT_ON_CLOCK, json_boolean(_selectOnClock)); + return root; +} + +void OneEight::fromJson(json_t* root) { + json_t* s = json_object_get(root, SELECT_ON_CLOCK); + if (s) { + _selectOnClock = json_is_true(s); + } +} + void OneEight::step() { bool reset = _reset.process(inputs[RESET_INPUT].value); if (reset) { @@ -19,13 +34,17 @@ void OneEight::step() { bool timer = _timer.next(); bool clock = _clock.process(inputs[CLOCK_INPUT].value) && !timer; - int steps = clamp(params[STEPS_PARAM].value, 1.0f, 8.0f); + int steps = params[STEPS_PARAM].value; int reverse = 1 - 2 * (params[DIRECTION_PARAM].value == 0.0f); _step = (_step + reverse * clock) % steps; _step += (_step < 0) * steps; _step -= _step * reset; - int step = _step + (int)params[SELECT_PARAM].value; - step += (int)(clamp(inputs[SELECT_INPUT].value, 0.0f, 10.0f) * 0.1f * 8.0f); + int select = params[SELECT_PARAM].value; + select += clamp(inputs[SELECT_INPUT].value, 0.0f, 10.0f) * 0.1f * 8.0f; + if (!_selectOnClock || clock) { + _select = select; + } + int step = _step + _select; step = step % 8; float in = inputs[IN_INPUT].value + !inputs[IN_INPUT].active * 10.0f; @@ -35,6 +54,24 @@ void OneEight::step() { } } +struct SelectOnClockMenuItem : MenuItem { + OneEight* _module; + + SelectOnClockMenuItem(OneEight* module, const char* label) + : _module(module) + { + this->text = label; + } + + void onAction(EventAction &e) override { + _module->_selectOnClock = !_module->_selectOnClock; + } + + void step() override { + rightText = _module->_selectOnClock ? "✔" : ""; + } +}; + struct OneEightWidget : ModuleWidget { static constexpr int hp = 6; @@ -115,6 +152,13 @@ struct OneEightWidget : ModuleWidget { addChild(ModuleLightWidget::create<SmallLight<GreenLight>>(out7LightPosition, module, OneEight::OUT7_LIGHT)); addChild(ModuleLightWidget::create<SmallLight<GreenLight>>(out8LightPosition, module, OneEight::OUT8_LIGHT)); } + + void appendContextMenu(Menu* menu) override { + OneEight* m = dynamic_cast<OneEight*>(module); + assert(m); + menu->addChild(new MenuLabel()); + menu->addChild(new SelectOnClockMenuItem(m, "Select on clock")); + } }; Model* modelOneEight = createModel<OneEight, OneEightWidget>("Bogaudio-OneEight", "1:8", "mux & sequential switch", SWITCH_TAG); diff --git a/src/OneEight.hpp b/src/OneEight.hpp @@ -53,6 +53,8 @@ struct OneEight : Module { Trigger _reset; Timer _timer; int _step; + bool _selectOnClock = false; + int _select = 0; OneEight() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { onReset(); @@ -61,6 +63,8 @@ struct OneEight : Module { void onReset() override; void onSampleRateChange() override; + json_t* toJson() override; + void fromJson(json_t* root) override; void step() override; };