/////////////////////////////////////////////////// // // // Knobs - VCV Module outputs 3 constants of different types and ranges // // Strum 2017 // /////////////////////////////////////////////////// #include "mental.hpp" #include "dsp/digital.hpp" #include #include namespace rack_plugin_mental { struct MentalKnobs : Module { enum ParamIds { STEP_SWITCH, BI_SWITCH = STEP_SWITCH + 3, STEPSIZE_SWITCH = BI_SWITCH + 3, KNOB_PARAM = STEPSIZE_SWITCH + 3, SCALE_PARAM = KNOB_PARAM + 3, NUM_PARAMS = SCALE_PARAM + 3 }; enum InputIds { NUM_INPUTS }; enum OutputIds { OUTPUT, NUM_OUTPUTS = OUTPUT + 3 }; enum LightIds { BUTTON_LEDS, NUM_LIGHTS = BUTTON_LEDS + 9 }; float knob_value[3] = {0.0,0.0,0.0}; float scale_value[3] = {0.0,0.0,0.0}; float output_value[3] = {0.0,0.0,0.0}; int display_value[3] = {0,0,0}; SchmittTrigger step_switch_trigger[3],bi_switch_trigger[3],stepsize_switch_trigger[3]; bool switch_states[3][3] = {{0,0,0}, {0,0,0}, {0,0,0}}; int octaves[3] = {0,0,0}; int semitones[3] = {0,0,0}; MentalKnobs() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {} void step() override; json_t *toJson() override { json_t *rootJ = json_object(); // button states json_t *switch_statesJ = json_array(); for (int i = 0; i < 3; i++) { for (int j = 0 ; j < 3 ; j++) { json_t *switch_stateJ = json_integer((int) switch_states[i][j]); json_array_append_new(switch_statesJ, switch_stateJ); } } json_object_set_new(rootJ, "switches", switch_statesJ); return rootJ; } void fromJson(json_t *rootJ) override { // button states json_t *switch_statesJ = json_object_get(rootJ, "switches"); if (switch_statesJ) { for (int i = 0; i < 3 ; i++) { for (int j = 0 ; j < 3 ; j++) { json_t *switch_stateJ = json_array_get(switch_statesJ, i * 3 + j); if (switch_stateJ) switch_states[i][j] = !!json_integer_value(switch_stateJ); } } } } }; void MentalKnobs::step() { for ( int i = 0 ; i < 3 ; i++) { // button triggers if (step_switch_trigger[i].process(params[STEP_SWITCH + i].value)) { switch_states[0][i] = !switch_states[0][i]; } lights[BUTTON_LEDS + i].value = switch_states[0][i] ? 1.0 : 0.0; if (stepsize_switch_trigger[i].process(params[STEPSIZE_SWITCH + i].value)) { switch_states[1][i] = !switch_states[1][i]; } lights[BUTTON_LEDS + 6 + i].value = switch_states[1][i] ? 1.0 : 0.0; if (bi_switch_trigger[i].process(params[BI_SWITCH + i].value)) { switch_states[2][i] = !switch_states[2][i]; } lights[BUTTON_LEDS + 3 + i].value = switch_states[2][i] ? 1.0 : 0.0; knob_value[i] = params[KNOB_PARAM + i].value; scale_value[i] = params[SCALE_PARAM + i].value; if (!switch_states[2][i]) // bi switch { knob_value[i] = std::abs(knob_value[i]); } output_value[i] = knob_value[i] * scale_value[i]; if (switch_states[0][i]) // step switch { if (switch_states[1][i]) // stepsize switch - quantise to semitones { octaves[i] = std::round(output_value[i]); semitones[i] = std::round((output_value[i] - octaves[i])*12); if (semitones[i] < 0) { semitones[i] +=12; octaves[i] -= 1; } output_value[i] = octaves[i] + semitones[i]/12.0; } else output_value[i] = std::round(output_value[i]); } display_value[i] = std::round(output_value[i]); outputs[OUTPUT + i].value = output_value[i]; } } //////////////////////////////////// struct NumberDisplayWidget4 : TransparentWidget { int *value; std::shared_ptr font; NumberDisplayWidget4() { 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 MentalKnobsWidget : ModuleWidget { MentalKnobsWidget(MentalKnobs *module); }; MentalKnobsWidget::MentalKnobsWidget(MentalKnobs *module) : ModuleWidget(module) { setPanel(SVG::load(assetPlugin(plugin, "res/MentalKnobs.svg"))); int group_offset = 120; for (int i = 0 ; i < 3 ; i++) { addParam(ParamWidget::create(Vec(2, 20+group_offset*i), module, MentalKnobs::KNOB_PARAM + i, -1.0, 1.0, 0.0)); addParam(ParamWidget::create(Vec(32, 20+group_offset*i), module, MentalKnobs::SCALE_PARAM + i,0.0, 10.0, 1.0)); addParam(ParamWidget::create(Vec(5, 50+group_offset*i), module, MentalKnobs::STEP_SWITCH + i, 0.0, 1.0, 0.0)); addChild(ModuleLightWidget::create>(Vec(10, 55+group_offset*i), module, MentalKnobs::BUTTON_LEDS + i )); addParam(ParamWidget::create(Vec(5, 75+group_offset*i), module, MentalKnobs::BI_SWITCH + i, 0.0, 1.0, 0.0)); addChild(ModuleLightWidget::create>(Vec(10, 80+group_offset*i), module, MentalKnobs::BUTTON_LEDS + 3 + i)); addParam(ParamWidget::create(Vec(35, 50+group_offset*i), module, MentalKnobs::STEPSIZE_SWITCH + i, 0.0, 1.0, 0.0)); addChild(ModuleLightWidget::create>(Vec(40, 55+group_offset*i), module, MentalKnobs::BUTTON_LEDS + 6 + i)); addOutput(Port::create(Vec(33, 75+group_offset*i), Port::OUTPUT, module, MentalKnobs::OUTPUT + i)); } NumberDisplayWidget4 *display = new NumberDisplayWidget4(); display->box.pos = Vec(5,105); display->box.size = Vec(50, 20); display->value = &module->display_value[0]; addChild(display); NumberDisplayWidget4 *display2 = new NumberDisplayWidget4(); display2->box.pos = Vec(5,105+group_offset); display2->box.size = Vec(50, 20); display2->value = &module->display_value[1]; addChild(display2); NumberDisplayWidget4 *display3 = new NumberDisplayWidget4(); display3->box.pos = Vec(5,105+group_offset * 2); display3->box.size = Vec(50, 20); display3->value = &module->display_value[2]; addChild(display3); } } // namespace rack_plugin_mental using namespace rack_plugin_mental; RACK_PLUGIN_MODEL_INIT(mental, MentalKnobs) { Model *modelMentalKnobs = Model::create("mental", "MentalKnobs", "Knobs", CONTROLLER_TAG, UTILITY_TAG); return modelMentalKnobs; }