/* --no-title-yet-- (SlimSeq) 16 step seq (based on m.lueders' sequential switch) TODO: -if-bool cleanup -save modestates and resetpos -adjustable step count -playmodes: pendulum/ping-pong, one-shot -output slew (portamento) -useful unclocked/held operation -(maybe) momentary control inputs (instead of flips) / optional -(maybe) unipolar/bipolar options -(maybe) gates *///////////////////////////////////////////////////////////////////////////// #include "pvc.hpp" #include "dsp/digital.hpp" // SchmittTrigger PulseGenerator #include "dsp/filter.hpp" // SlewLimiter namespace rack_plugin_PvC { #define STEPCOUNT 16 struct SlimSeq : Module { enum ParamIds { STEP1_KNOB, SCL_KNOB = STEP1_KNOB + STEPCOUNT, STEP1_SEL, CLOCK_UI = STEP1_SEL + STEPCOUNT, REVERSE_UI, RNDMODE_UI, HOLD_UI, RESET_UI, OFF_KNOB, NUM_PARAMS }; enum InputIds { CLOCK_IN, REVERSE_IN, RNDMODE_IN, HOLD_IN, RESET_IN, STEP1_IN, NUM_INPUTS = STEP1_IN + STEPCOUNT }; enum OutputIds { OUT, NUM_OUTPUTS }; enum LightIds { REVERSE_LIGHT, RNDMODE_LIGHT, FORWARD_LIGHT, STEP1_LIGHT, OUT_POS_LED = STEP1_LIGHT + STEPCOUNT, OUT_NEG_LED, NUM_LIGHTS }; SlimSeq() : Module( NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS ) { reset(); }; void step() override; int currentPos = 0; int counterPos = 0; int resetPos = 0; bool isRunning = false; bool isHold = false; bool isRandom = false; bool isReverse = false; bool isHopper = false; float stepInput = 0.0f; SchmittTrigger clockTrigger, reverseTrigger, randomTrigger, holdTrigger, resetTrigger; SchmittTrigger posButtons[STEPCOUNT]; void reset() override { currentPos = 0; counterPos = 0; resetPos = 0; isRunning = false; isHold = false; isRandom = false; isReverse = false; isHopper = false; stepInput = 0.0f; for(int i=0; i (STEPCOUNT-1) ) counterPos -= STEPCOUNT; // loop the current while ( currentPos < 0 ) currentPos += STEPCOUNT; while ( currentPos > (STEPCOUNT-1) ) currentPos -= STEPCOUNT; // calc out outputs[OUT].value = clamp(stepInput * params[SCL_KNOB].value + params[OFF_KNOB].value, -10.0f, 10.0f); // lights // direction lights[REVERSE_LIGHT].value = isHold ? 1.0f : isRandom&&isHopper ? 0.0f : isRandom&&!isHopper ? 1.0f : isReverse ? 1.0f : 0.0f; lights[RNDMODE_LIGHT].value = isHold ? 1.0f : isRandom&&isHopper ? 1.0f : isRandom&&!isHopper ? 0.0f : 0.0f; lights[FORWARD_LIGHT].value = isHold ? 1.0f : isRandom&&isHopper ? 0.0f : isRandom&&!isHopper ? 1.0f : isReverse ? 0.0f : 1.0f; // steplights for(int i=0; i 0) ? outputs[OUT].value*0.1f : 0.0f; }; struct StepButton : SVGSwitch, MomentarySwitch { StepButton() { addFrame(SVG::load(assetPlugin(plugin, "res/components/empty.svg"))); box.size = Vec(73,30); } }; // struct ControlButton : StepButton { // ControlButton() { // box.size = Vec(73,30); // } // }; struct SlimSeqWidget : ModuleWidget { SlimSeqWidget(SlimSeq *module); }; SlimSeqWidget::SlimSeqWidget(SlimSeq *module) : ModuleWidget(module) { setPanel(SVG::load(assetPlugin(plugin, "res/panels/SlimSeq.svg"))); // screws addChild(Widget::create(Vec(15, 0))); addChild(Widget::create(Vec(box.size.x-30, 0))); addChild(Widget::create(Vec(15, 365))); addChild(Widget::create(Vec(box.size.x-30, 365))); // control inputs addInput(Port::create(Vec(4,22), Port::INPUT, module,SlimSeq::CLOCK_IN)); //addParam(ParamWidget::create(Vec(48,70),module,SlimSeq::CLOCK_UI , 0, 1, 0)); addInput(Port::create(Vec(34,22), Port::INPUT, module,SlimSeq::REVERSE_IN)); // addParam(ParamWidget::create(Vec(48,270),module,SlimSeq::REVERSE_UI , 0, 1, 0)); addInput(Port::create(Vec(64,22), Port::INPUT, module,SlimSeq::HOLD_IN)); // addParam(ParamWidget::create(Vec(48,270),module,SlimSeq::HOLD_UI , 0, 1, 0)); addInput(Port::create(Vec(94,22), Port::INPUT, module,SlimSeq::RNDMODE_IN)); // addParam(ParamWidget::create(Vec(48,270),module,SlimSeq::RNDMODE_UI , 0, 1, 0)); addInput(Port::create(Vec(124,22), Port::INPUT, module,SlimSeq::RESET_IN)); // addParam(ParamWidget::create(Vec(48,270),module,SlimSeq::RESET_UI , 0, 1, 0)); // direction lights addChild(ModuleLightWidget::create>(Vec(67,62),module,SlimSeq::REVERSE_LIGHT)); addChild(ModuleLightWidget::create>(Vec(73,62),module,SlimSeq::RNDMODE_LIGHT)); addChild(ModuleLightWidget::create>(Vec(79,62),module,SlimSeq::FORWARD_LIGHT)); // steps for (int i = 0; i < 8; i++) { int top = 31; // left 16-9 addParam(ParamWidget::create(Vec(1,69 + top * i),module,SlimSeq::STEP1_SEL + STEPCOUNT-1 - i , 0, 1, 0)); addParam(ParamWidget::create(Vec(16,73 + top * i),module,SlimSeq::STEP1_KNOB + STEPCOUNT-1 - i , -1.0f, 1.0f, 0.0f)); addInput(Port::create(Vec(40,73 + top * i), Port::INPUT, module,SlimSeq::STEP1_IN + + STEPCOUNT-1 - i)); addChild(ModuleLightWidget::create>(Vec(65,82 + top * i),module,SlimSeq::STEP1_LIGHT + STEPCOUNT-1 - i)); // right 1-8 addParam(ParamWidget::create(Vec(76,69 + top * i),module,SlimSeq::STEP1_SEL + i , 0, 1, 0)); addChild(ModuleLightWidget::create>(Vec(81,82 + top * i),module,SlimSeq::STEP1_LIGHT + i)); addInput(Port::create(Vec(88,73 + top * i), Port::INPUT, module,SlimSeq::STEP1_IN + i)); addParam(ParamWidget::create(Vec(112,73 + top * i),module,SlimSeq::STEP1_KNOB + i, -1.0f, 1.0f, 0.0f)); } // main out addParam(ParamWidget::create(Vec(36,323),module,SlimSeq::SCL_KNOB, -1.0f, 1.0f, 1.0f)); addChild(ModuleLightWidget::create>(Vec(73,330),module,SlimSeq::OUT_POS_LED)); addOutput(Port::create(Vec(64,336), Port::OUTPUT, module,SlimSeq::OUT)); addParam(ParamWidget::create(Vec(92,323),module,SlimSeq::OFF_KNOB, -5.0f, 5.0f, 0.0f)); } } // namespace rack_plugin_PvC using namespace rack_plugin_PvC; RACK_PLUGIN_MODEL_INIT(PvC, SlimSeq) { Model *modelSlimSeq = Model::create( "PvC", "SlimSeq", "SlimSeq", SEQUENCER_TAG, SWITCH_TAG); return modelSlimSeq; }