#include "HetrickCV.hpp" namespace rack_plugin_HetrickCV { #ifdef USE_VST2 #define plugin "HetrickCV" #endif // USE_VST2 struct LogicCombine : Module { enum ParamIds { NUM_PARAMS }; enum InputIds { IN1_INPUT, IN2_INPUT, IN3_INPUT, IN4_INPUT, IN5_INPUT, IN6_INPUT, IN7_INPUT, IN8_INPUT, NUM_INPUTS }; enum OutputIds { OR_OUTPUT, NOR_OUTPUT, TRIG_OUTPUT, NUM_OUTPUTS }; enum LightIds { OR_LIGHT, NOR_LIGHT, TRIG_LIGHT, NUM_LIGHTS }; bool ins[NUM_INPUTS] = {}; bool trigs[NUM_INPUTS] = {}; float outs[3] = {}; float trigLight; SchmittTrigger inTrigs[NUM_INPUTS]; bool orState = false; bool trigState = false; const float lightLambda = 0.075; TriggerGenerator trigger; LogicCombine() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { } void step() override; // For more advanced Module features, read Rack's engine.hpp header file // - toJson, fromJson: serialization of internal data // - onSampleRateChange: event triggered by a change of sample rate // - reset, randomize: implements special behavior when user clicks these from the context menu }; void LogicCombine::step() { orState = false; trigState = false; for(int i = 0; i < NUM_INPUTS; i++) { ins[i] = (inputs[IN1_INPUT + i].value >= 1.0f); trigs[i] = inTrigs[i].process(inputs[IN1_INPUT + i].value); orState = orState || ins[i]; trigState = trigState || trigs[i]; } outs[0] = orState ? 5.0f : 0.0f; outs[1] = 5.0f - outs[0]; if(trigState) { trigger.trigger(); lights[TRIG_LIGHT].value = 5.0f; } outs[2] = trigger.process() ? 5.0f : 0.0f; if (lights[TRIG_LIGHT].value > 0.01) lights[TRIG_LIGHT].value -= lights[TRIG_LIGHT].value / lightLambda * engineGetSampleTime(); outputs[OR_OUTPUT].value = outs[0]; outputs[NOR_OUTPUT].value = outs[1]; outputs[TRIG_OUTPUT].value = outs[2]; lights[OR_LIGHT].setBrightness(outs[0]); lights[NOR_LIGHT].setBrightness(outs[1]); lights[TRIG_LIGHT].setBrightnessSmooth(outs[2]); } struct LogicCombineWidget : ModuleWidget { LogicCombineWidget(LogicCombine *module); }; LogicCombineWidget::LogicCombineWidget(LogicCombine *module) : ModuleWidget(module) { box.size = Vec(8 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT); { auto *panel = new SVGPanel(); panel->box.size = box.size; panel->setBackground(SVG::load(assetPlugin(plugin, "res/LogicCombiner.svg"))); addChild(panel); } 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))); //////PARAMS////// //////INPUTS////// const int inSpacing = 40; const int outPos = 67; const int lightPos = outPos + 29; for(int i = 0; i < LogicCombine::NUM_INPUTS; i++) { addInput(Port::create(Vec(10, 50 + (i*inSpacing)), Port::INPUT, module, LogicCombine::IN1_INPUT + i)); } //////OUTPUTS////// addOutput(Port::create(Vec(outPos, 150), Port::OUTPUT, module, LogicCombine::OR_OUTPUT)); addOutput(Port::create(Vec(outPos, 195), Port::OUTPUT, module, LogicCombine::NOR_OUTPUT)); addOutput(Port::create(Vec(outPos, 240), Port::OUTPUT, module, LogicCombine::TRIG_OUTPUT)); //////BLINKENLIGHTS////// addChild(ModuleLightWidget::create>(Vec(lightPos, 158), module, LogicCombine::OR_LIGHT)); addChild(ModuleLightWidget::create>(Vec(lightPos, 203), module, LogicCombine::NOR_LIGHT)); addChild(ModuleLightWidget::create>(Vec(lightPos, 248), module, LogicCombine::TRIG_LIGHT)); } } // namespace rack_plugin_HetrickCV using namespace rack_plugin_HetrickCV; RACK_PLUGIN_MODEL_INIT(HetrickCV, LogicCombine) { Model *modelLogicCombine = Model::create("HetrickCV", "Logic Combine", "OR Logic (Gate Combiner)", LOGIC_TAG); return modelLogicCombine; }