/////////////////////////////////////////////////// // // // Gate maker, make gates by clock - VCV Module // // Strum 2017 // /////////////////////////////////////////////////// #include "mental.hpp" #include "dsp/digital.hpp" #include #include namespace rack_plugin_mental { struct MentalGateMaker : Module { enum ParamIds { RST_BUTTON, TRIG_BUTTON, CYCLE_BUTTON, COUNT_NUM_PARAM, DELAY_PARAM, TAIL_PARAM, NUM_PARAMS }; enum InputIds { CLK_IN, RESET_IN, TRIGGER_IN, CYCLE_IN, COUNT_CV, DELAY_CV, TAIL_CV, NUM_INPUTS }; enum OutputIds { OUTPUT, FINISH_OUT, TRIG_OUT, NUM_OUTPUTS }; enum LightIds { CYCLE_BUTTON_LED, NUM_LIGHTS }; SchmittTrigger clock_trigger; SchmittTrigger reset_trigger; SchmittTrigger cycle__button_trigger; SchmittTrigger trigger_trigger; int count_limit = 0; int count_on = 0; int count_disp = 0; int count = 0; int delay = 0; int tail = 0; bool cycle = true; bool cycle_button_state = true; bool triggered = false; bool mode = false; MentalGateMaker(); void step() override; }; MentalGateMaker::MentalGateMaker() { params.resize(NUM_PARAMS); inputs.resize(NUM_INPUTS); outputs.resize(NUM_OUTPUTS); lights.resize(NUM_LIGHTS); } void MentalGateMaker::step() { if (cycle__button_trigger.process(params[CYCLE_BUTTON].value)) { cycle_button_state = !cycle_button_state; count = 0; outputs[OUTPUT].value = 0; outputs[FINISH_OUT].value = 0.0; } if (inputs[CYCLE_IN].value || cycle_button_state) { cycle = true; lights[CYCLE_BUTTON_LED].value = 1.0; } else { cycle = false; lights[CYCLE_BUTTON_LED].value = 0.0; } delay = round(params[DELAY_PARAM].value); count_on = round(params[COUNT_NUM_PARAM].value); count_disp = count_on + 1; tail = round(params[TAIL_PARAM].value); count_limit = count_on + delay + tail; bool reset = false; if (trigger_trigger.process(params[TRIG_BUTTON].value) || (trigger_trigger.process(inputs[TRIGGER_IN].value))) { reset = true; triggered = true; count = 0; outputs[OUTPUT].value = 0; outputs[FINISH_OUT].value = 0.0; } if (reset_trigger.process(params[RST_BUTTON].value) || (reset_trigger.process(inputs[RESET_IN].value))) { reset = true; count = 0; outputs[OUTPUT].value = 0; outputs[FINISH_OUT].value = 0.0; } if (reset == false && (cycle || triggered)) { if (clock_trigger.process(inputs[CLK_IN].value) && count <= count_limit) count++; } if (count >= delay && count <= (count_on + delay)) outputs[OUTPUT].value = 10.0; else outputs[OUTPUT].value = 0.0; if (count > count_limit) { count = 0; if (triggered) outputs[OUTPUT].value = 0; triggered = false; outputs[FINISH_OUT].value = 10.0; } } //////////////////////////////////// struct NumberDisplayWidget : TransparentWidget { int *value; std::shared_ptr font; NumberDisplayWidget() { font = Font::load(assetPlugin(plugin, "res/Segment7Standard.ttf")); }; void draw(NVGcontext *vg) override { // Background NVGcolor backgroundColor = nvgRGB(0x00, 0x00, 0x00); NVGcolor StrokeColor = nvgRGB(0x00, 0x47, 0x7e); nvgBeginPath(vg); nvgRoundedRect(vg, -1.0, -1.0, box.size.x+2, box.size.y+2, 4.0); nvgFillColor(vg, StrokeColor); nvgFill(vg); nvgBeginPath(vg); nvgRoundedRect(vg, 0.0, 0.0, box.size.x, box.size.y, 4.0); nvgFillColor(vg, backgroundColor); nvgFill(vg); // text nvgFontSize(vg, 18); nvgFontFaceId(vg, font->handle); nvgTextLetterSpacing(vg, 2.5); std::stringstream to_display; to_display << std::setw(3) << *value; Vec textPos = Vec(6.0f, 17.0f); NVGcolor textColor = nvgRGB(0x00, 0x47, 0x7e); nvgFillColor(vg, textColor); nvgText(vg, textPos.x, textPos.y, to_display.str().c_str(), NULL); } }; ////////////////////////////////// struct MentalGateMakerWidget : ModuleWidget { MentalGateMakerWidget(MentalGateMaker *module); }; MentalGateMakerWidget::MentalGateMakerWidget(MentalGateMaker *module) : ModuleWidget(module) { setPanel(SVG::load(assetPlugin(plugin, "res/MentalGateMaker.svg"))); addParam(ParamWidget::create(Vec(2, 20), module, MentalGateMaker::COUNT_NUM_PARAM, 0.0, 32.0, 0.0)); addInput(Port::create(Vec(33, 20), Port::INPUT, module, MentalGateMaker::COUNT_CV)); NumberDisplayWidget *count_display = new NumberDisplayWidget(); count_display->box.pos = Vec(63,20); count_display->box.size = Vec(50, 20); count_display->value = &module->count_disp; addChild(count_display); addParam(ParamWidget::create(Vec(2, 50), module, MentalGateMaker::DELAY_PARAM, 0.0, 32.0, 0.0)); addInput(Port::create(Vec(33, 50), Port::INPUT, module, MentalGateMaker::DELAY_CV)); NumberDisplayWidget *delay_display = new NumberDisplayWidget(); delay_display->box.pos = Vec(63,50); delay_display->box.size = Vec(50, 20); delay_display->value = &module->delay; addChild(delay_display); addParam(ParamWidget::create(Vec(2, 80), module, MentalGateMaker::TAIL_PARAM, 0.0, 32.0, 0.0)); addInput(Port::create(Vec(33, 80), Port::INPUT, module, MentalGateMaker::TAIL_CV)); NumberDisplayWidget *tail_display = new NumberDisplayWidget(); tail_display->box.pos = Vec(63,80); tail_display->box.size = Vec(50, 20); tail_display->value = &module->tail; addChild(tail_display); int offset = 30; addInput(Port::create(Vec(3, 80 + offset), Port::INPUT, module, MentalGateMaker::CLK_IN)); addInput(Port::create(Vec(3, 110 + offset), Port::INPUT, module, MentalGateMaker::RESET_IN)); addParam(ParamWidget::create(Vec(35, 110 + offset), module, MentalGateMaker::RST_BUTTON, 0.0, 1.0, 0.0)); addInput(Port::create(Vec(3, 140 + offset), Port::INPUT, module, MentalGateMaker::TRIGGER_IN)); addParam(ParamWidget::create(Vec(35, 140 + offset), module, MentalGateMaker::TRIG_BUTTON, 0.0, 1.0, 0.0)); addParam(ParamWidget::create(Vec(35, 170 + offset), module, MentalGateMaker::CYCLE_BUTTON, 0.0, 1.0, 0.0)); addChild(ModuleLightWidget::create>(Vec(35+5, 170 + offset + 5), module, MentalGateMaker::CYCLE_BUTTON_LED)); addInput(Port::create(Vec(3, 170 + offset), Port::INPUT, module, MentalGateMaker::CYCLE_IN)); addOutput(Port::create(Vec(93, 110), Port::OUTPUT, module, MentalGateMaker::OUTPUT)); addOutput(Port::create(Vec(93, 140), Port::OUTPUT, module, MentalGateMaker::TRIG_OUT)); addOutput(Port::create(Vec(93, 170), Port::OUTPUT, module, MentalGateMaker::FINISH_OUT)); } } // namespace rack_plugin_mental using namespace rack_plugin_mental; RACK_PLUGIN_MODEL_INIT(mental, MentalGateMaker) { Model *modelMentalGateMaker = Model::create("mental", "MentalGateMaker", "Gate Maker", UTILITY_TAG); return modelMentalGateMaker; }