diff --git a/Makefile b/Makefile index 9a5e9ff..0aa4dcd 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ SLUG = Fundamental -VERSION = 0.5.0 +VERSION = 0.5.1 SOURCES = $(wildcard src/*.cpp) diff --git a/res/SequentialSwitch1.svg b/res/SequentialSwitch1.svg new file mode 100644 index 0000000..1df9f53 --- /dev/null +++ b/res/SequentialSwitch1.svg @@ -0,0 +1,484 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/SequentialSwitch2.svg b/res/SequentialSwitch2.svg new file mode 100644 index 0000000..30b87ed --- /dev/null +++ b/res/SequentialSwitch2.svg @@ -0,0 +1,490 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Fundamental.cpp b/src/Fundamental.cpp index 7bba3b7..303abbf 100644 --- a/src/Fundamental.cpp +++ b/src/Fundamental.cpp @@ -25,4 +25,6 @@ void init(rack::Plugin *p) { p->addModel(createModel("Fundamental", "Mutes", "Mutes", SWITCH_TAG)); p->addModel(createModel("Fundamental", "Scope", "Scope", VISUAL_TAG)); p->addModel(createModel("Fundamental", "SEQ3", "SEQ-3", SEQUENCER_TAG)); + p->addModel(createModel("Fundamental", "SequentialSwitch1", "Sequential Switch 1", UTILITY_TAG)); + p->addModel(createModel("Fundamental", "SequentialSwitch2", "Sequential Switch 2", UTILITY_TAG)); } diff --git a/src/Fundamental.hpp b/src/Fundamental.hpp index 4f85f83..014ad74 100644 --- a/src/Fundamental.hpp +++ b/src/Fundamental.hpp @@ -67,3 +67,11 @@ struct SEQ3Widget : ModuleWidget { SEQ3Widget(); Menu *createContextMenu() override; }; + +struct SequentialSwitch1Widget : ModuleWidget { + SequentialSwitch1Widget(); +}; + +struct SequentialSwitch2Widget : ModuleWidget { + SequentialSwitch2Widget(); +}; diff --git a/src/SequentialSwitch.cpp b/src/SequentialSwitch.cpp new file mode 100644 index 0000000..ee337d0 --- /dev/null +++ b/src/SequentialSwitch.cpp @@ -0,0 +1,131 @@ +#include "Fundamental.hpp" +#include "dsp/digital.hpp" +#include "dsp/filter.hpp" + + +template +struct SequentialSwitch : Module { + enum ParamIds { + CHANNELS_PARAM, + NUM_PARAMS + }; + enum InputIds { + CLOCK_INPUT, + RESET_INPUT, + ENUMS(IN_INPUT, TYPE == 1 ? 1 : 4), + NUM_INPUTS + }; + enum OutputIds { + ENUMS(OUT_OUTPUT, TYPE == 1 ? 4 : 1), + NUM_OUTPUTS + }; + enum LightIds { + ENUMS(CHANNEL_LIGHT, 4), + NUM_LIGHTS + }; + + SchmittTrigger clockTrigger; + SchmittTrigger resetTrigger; + int channel = 0; + SlewLimiter channelFilter[4]; + + SequentialSwitch() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { + clockTrigger.setThresholds(0.0, 2.0); + resetTrigger.setThresholds(0.0, 2.0); + for (int i = 0; i < 4; i++) { + channelFilter[i].rise = 0.01; + channelFilter[i].fall = 0.01; + } + } + + void step() override { + // Determine current channel + if (clockTrigger.process(inputs[CLOCK_INPUT].value)) { + channel++; + } + if (resetTrigger.process(inputs[RESET_INPUT].value)) { + channel = 0; + } + int channels = 4 - (int) params[CHANNELS_PARAM].value; + channel %= channels; + + // Filter channels + for (int i = 0; i < 4; i++) { + channelFilter[i].process(channel == i ? 1.0 : 0.0); + } + + // Set outputs + if (TYPE == 1) { + float out = inputs[IN_INPUT + 0].value; + for (int i = 0; i < 4; i++) { + outputs[OUT_OUTPUT + i].value = channelFilter[i].out * out; + } + } + else { + float out = 0.0; + for (int i = 0; i < 4; i++) { + out += channelFilter[i].out * inputs[IN_INPUT + i].value; + } + outputs[OUT_OUTPUT + 0].value = out; + } + + // Set lights + for (int i = 0; i < 4; i++) { + lights[CHANNEL_LIGHT + i].setBrightness(channelFilter[i].out); + } + } +}; + + +SequentialSwitch1Widget::SequentialSwitch1Widget() { + typedef SequentialSwitch<1> TSequentialSwitch; + TSequentialSwitch *module = new TSequentialSwitch(); + setModule(module); + setPanel(SVG::load(assetPlugin(plugin, "res/SequentialSwitch1.svg"))); + + addChild(createScrew(Vec(RACK_GRID_WIDTH, 0))); + addChild(createScrew(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); + + addParam(createParam(mm2px(Vec(5.24619, 46.9153)), module, TSequentialSwitch::CHANNELS_PARAM, 0.0, 2.0, 0.0)); + + addInput(createInput(mm2px(Vec(3.51398, 17.694)), module, TSequentialSwitch::CLOCK_INPUT)); + addInput(createInput(mm2px(Vec(3.51398, 32.1896)), module, TSequentialSwitch::RESET_INPUT)); + addInput(createInput(mm2px(Vec(3.51536, 62.8096)), module, TSequentialSwitch::IN_INPUT + 0)); + + addOutput(createOutput(mm2px(Vec(3.51536, 77.8095)), module, TSequentialSwitch::OUT_OUTPUT + 0)); + addOutput(createOutput(mm2px(Vec(3.51398, 87.8113)), module, TSequentialSwitch::OUT_OUTPUT + 1)); + addOutput(createOutput(mm2px(Vec(3.51398, 97.809)), module, TSequentialSwitch::OUT_OUTPUT + 2)); + addOutput(createOutput(mm2px(Vec(3.51398, 107.809)), module, TSequentialSwitch::OUT_OUTPUT + 3)); + + addChild(createLight>(mm2px(Vec(10.8203, 77.7158)), module, TSequentialSwitch::CHANNEL_LIGHT + 0)); + addChild(createLight>(mm2px(Vec(10.8203, 87.7163)), module, TSequentialSwitch::CHANNEL_LIGHT + 1)); + addChild(createLight>(mm2px(Vec(10.8203, 97.7167)), module, TSequentialSwitch::CHANNEL_LIGHT + 2)); + addChild(createLight>(mm2px(Vec(10.8203, 107.716)), module, TSequentialSwitch::CHANNEL_LIGHT + 3)); +} + + +SequentialSwitch2Widget::SequentialSwitch2Widget() { + typedef SequentialSwitch<2> TSequentialSwitch; + TSequentialSwitch *module = new TSequentialSwitch(); + setModule(module); + setPanel(SVG::load(assetPlugin(plugin, "res/SequentialSwitch2.svg"))); + + addChild(createScrew(Vec(RACK_GRID_WIDTH, 0))); + addChild(createScrew(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); + + addParam(createParam(mm2px(Vec(5.24619, 46.9153)), module, TSequentialSwitch::CHANNELS_PARAM, 0.0, 2.0, 0.0)); + + addInput(createInput(mm2px(Vec(3.51398, 17.694)), module, TSequentialSwitch::CLOCK_INPUT)); + addInput(createInput(mm2px(Vec(3.51398, 32.191)), module, TSequentialSwitch::RESET_INPUT)); + addInput(createInput(mm2px(Vec(3.51398, 62.811)), module, TSequentialSwitch::IN_INPUT + 0)); + addInput(createInput(mm2px(Vec(3.51398, 72.8114)), module, TSequentialSwitch::IN_INPUT + 1)); + addInput(createInput(mm2px(Vec(3.51398, 82.8091)), module, TSequentialSwitch::IN_INPUT + 2)); + addInput(createInput(mm2px(Vec(3.51398, 92.8109)), module, TSequentialSwitch::IN_INPUT + 3)); + + addOutput(createOutput(mm2px(Vec(3.51398, 107.622)), module, TSequentialSwitch::OUT_OUTPUT + 0)); + + addChild(createLight>(mm2px(Vec(10.7321, 62.6277)), module, TSequentialSwitch::CHANNEL_LIGHT + 0)); + addChild(createLight>(mm2px(Vec(10.7321, 72.6281)), module, TSequentialSwitch::CHANNEL_LIGHT + 1)); + addChild(createLight>(mm2px(Vec(10.7321, 82.6285)), module, TSequentialSwitch::CHANNEL_LIGHT + 2)); + addChild(createLight>(mm2px(Vec(10.7321, 92.6276)), module, TSequentialSwitch::CHANNEL_LIGHT + 3)); +}