You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

246 lines
7.0KB

  1. ///////////////////////////////////////////////////
  2. //
  3. //
  4. // Gate maker, make gates by clock - VCV Module
  5. //
  6. // Strum 2017
  7. //
  8. ///////////////////////////////////////////////////
  9. #include "mental.hpp"
  10. #include "dsp/digital.hpp"
  11. #include <sstream>
  12. #include <iomanip>
  13. namespace rack_plugin_mental {
  14. struct MentalGateMaker : Module {
  15. enum ParamIds {
  16. RST_BUTTON,
  17. TRIG_BUTTON,
  18. CYCLE_BUTTON,
  19. COUNT_NUM_PARAM,
  20. DELAY_PARAM,
  21. TAIL_PARAM,
  22. NUM_PARAMS
  23. };
  24. enum InputIds {
  25. CLK_IN,
  26. RESET_IN,
  27. TRIGGER_IN,
  28. CYCLE_IN,
  29. COUNT_CV,
  30. DELAY_CV,
  31. TAIL_CV,
  32. NUM_INPUTS
  33. };
  34. enum OutputIds {
  35. OUTPUT,
  36. FINISH_OUT,
  37. TRIG_OUT,
  38. NUM_OUTPUTS
  39. };
  40. enum LightIds {
  41. CYCLE_BUTTON_LED,
  42. NUM_LIGHTS
  43. };
  44. SchmittTrigger clock_trigger;
  45. SchmittTrigger reset_trigger;
  46. SchmittTrigger cycle__button_trigger;
  47. SchmittTrigger trigger_trigger;
  48. int count_limit = 0;
  49. int count_on = 0;
  50. int count_disp = 0;
  51. int count = 0;
  52. int delay = 0;
  53. int tail = 0;
  54. bool cycle = true;
  55. bool cycle_button_state = true;
  56. bool triggered = false;
  57. bool mode = false;
  58. MentalGateMaker();
  59. void step() override;
  60. };
  61. MentalGateMaker::MentalGateMaker()
  62. {
  63. params.resize(NUM_PARAMS);
  64. inputs.resize(NUM_INPUTS);
  65. outputs.resize(NUM_OUTPUTS);
  66. lights.resize(NUM_LIGHTS);
  67. }
  68. void MentalGateMaker::step()
  69. {
  70. if (cycle__button_trigger.process(params[CYCLE_BUTTON].value))
  71. {
  72. cycle_button_state = !cycle_button_state;
  73. count = 0;
  74. outputs[OUTPUT].value = 0;
  75. outputs[FINISH_OUT].value = 0.0;
  76. }
  77. if (inputs[CYCLE_IN].value || cycle_button_state)
  78. {
  79. cycle = true;
  80. lights[CYCLE_BUTTON_LED].value = 1.0;
  81. } else
  82. {
  83. cycle = false;
  84. lights[CYCLE_BUTTON_LED].value = 0.0;
  85. }
  86. delay = round(params[DELAY_PARAM].value);
  87. count_on = round(params[COUNT_NUM_PARAM].value);
  88. count_disp = count_on + 1;
  89. tail = round(params[TAIL_PARAM].value);
  90. count_limit = count_on + delay + tail;
  91. bool reset = false;
  92. if (trigger_trigger.process(params[TRIG_BUTTON].value) || (trigger_trigger.process(inputs[TRIGGER_IN].value)))
  93. {
  94. reset = true;
  95. triggered = true;
  96. count = 0;
  97. outputs[OUTPUT].value = 0;
  98. outputs[FINISH_OUT].value = 0.0;
  99. }
  100. if (reset_trigger.process(params[RST_BUTTON].value) || (reset_trigger.process(inputs[RESET_IN].value)))
  101. {
  102. reset = true;
  103. count = 0;
  104. outputs[OUTPUT].value = 0;
  105. outputs[FINISH_OUT].value = 0.0;
  106. }
  107. if (reset == false && (cycle || triggered))
  108. {
  109. if (clock_trigger.process(inputs[CLK_IN].value) && count <= count_limit)
  110. count++;
  111. }
  112. if (count >= delay && count <= (count_on + delay)) outputs[OUTPUT].value = 10.0;
  113. else outputs[OUTPUT].value = 0.0;
  114. if (count > count_limit)
  115. {
  116. count = 0;
  117. if (triggered) outputs[OUTPUT].value = 0;
  118. triggered = false;
  119. outputs[FINISH_OUT].value = 10.0;
  120. }
  121. }
  122. ////////////////////////////////////
  123. struct NumberDisplayWidget : TransparentWidget {
  124. int *value;
  125. std::shared_ptr<Font> font;
  126. NumberDisplayWidget() {
  127. font = Font::load(assetPlugin(plugin, "res/Segment7Standard.ttf"));
  128. };
  129. void draw(NVGcontext *vg) override
  130. {
  131. // Background
  132. NVGcolor backgroundColor = nvgRGB(0x00, 0x00, 0x00);
  133. NVGcolor StrokeColor = nvgRGB(0x00, 0x47, 0x7e);
  134. nvgBeginPath(vg);
  135. nvgRoundedRect(vg, -1.0, -1.0, box.size.x+2, box.size.y+2, 4.0);
  136. nvgFillColor(vg, StrokeColor);
  137. nvgFill(vg);
  138. nvgBeginPath(vg);
  139. nvgRoundedRect(vg, 0.0, 0.0, box.size.x, box.size.y, 4.0);
  140. nvgFillColor(vg, backgroundColor);
  141. nvgFill(vg);
  142. // text
  143. nvgFontSize(vg, 18);
  144. nvgFontFaceId(vg, font->handle);
  145. nvgTextLetterSpacing(vg, 2.5);
  146. std::stringstream to_display;
  147. to_display << std::setw(3) << *value;
  148. Vec textPos = Vec(6.0f, 17.0f);
  149. NVGcolor textColor = nvgRGB(0x00, 0x47, 0x7e);
  150. nvgFillColor(vg, textColor);
  151. nvgText(vg, textPos.x, textPos.y, to_display.str().c_str(), NULL);
  152. }
  153. };
  154. //////////////////////////////////
  155. struct MentalGateMakerWidget : ModuleWidget {
  156. MentalGateMakerWidget(MentalGateMaker *module);
  157. };
  158. MentalGateMakerWidget::MentalGateMakerWidget(MentalGateMaker *module) : ModuleWidget(module)
  159. {
  160. setPanel(SVG::load(assetPlugin(plugin, "res/MentalGateMaker.svg")));
  161. addParam(ParamWidget::create<MedKnob>(Vec(2, 20), module, MentalGateMaker::COUNT_NUM_PARAM, 0.0, 32.0, 0.0));
  162. addInput(Port::create<CVInPort>(Vec(33, 20), Port::INPUT, module, MentalGateMaker::COUNT_CV));
  163. NumberDisplayWidget *count_display = new NumberDisplayWidget();
  164. count_display->box.pos = Vec(63,20);
  165. count_display->box.size = Vec(50, 20);
  166. count_display->value = &module->count_disp;
  167. addChild(count_display);
  168. addParam(ParamWidget::create<MedKnob>(Vec(2, 50), module, MentalGateMaker::DELAY_PARAM, 0.0, 32.0, 0.0));
  169. addInput(Port::create<CVInPort>(Vec(33, 50), Port::INPUT, module, MentalGateMaker::DELAY_CV));
  170. NumberDisplayWidget *delay_display = new NumberDisplayWidget();
  171. delay_display->box.pos = Vec(63,50);
  172. delay_display->box.size = Vec(50, 20);
  173. delay_display->value = &module->delay;
  174. addChild(delay_display);
  175. addParam(ParamWidget::create<MedKnob>(Vec(2, 80), module, MentalGateMaker::TAIL_PARAM, 0.0, 32.0, 0.0));
  176. addInput(Port::create<CVInPort>(Vec(33, 80), Port::INPUT, module, MentalGateMaker::TAIL_CV));
  177. NumberDisplayWidget *tail_display = new NumberDisplayWidget();
  178. tail_display->box.pos = Vec(63,80);
  179. tail_display->box.size = Vec(50, 20);
  180. tail_display->value = &module->tail;
  181. addChild(tail_display);
  182. int offset = 30;
  183. addInput(Port::create<GateInPort>(Vec(3, 80 + offset), Port::INPUT, module, MentalGateMaker::CLK_IN));
  184. addInput(Port::create<GateInPort>(Vec(3, 110 + offset), Port::INPUT, module, MentalGateMaker::RESET_IN));
  185. addParam(ParamWidget::create<LEDButton>(Vec(35, 110 + offset), module, MentalGateMaker::RST_BUTTON, 0.0, 1.0, 0.0));
  186. addInput(Port::create<GateInPort>(Vec(3, 140 + offset), Port::INPUT, module, MentalGateMaker::TRIGGER_IN));
  187. addParam(ParamWidget::create<LEDButton>(Vec(35, 140 + offset), module, MentalGateMaker::TRIG_BUTTON, 0.0, 1.0, 0.0));
  188. addParam(ParamWidget::create<LEDButton>(Vec(35, 170 + offset), module, MentalGateMaker::CYCLE_BUTTON, 0.0, 1.0, 0.0));
  189. addChild(ModuleLightWidget::create<MedLight<BlueLED>>(Vec(35+5, 170 + offset + 5), module, MentalGateMaker::CYCLE_BUTTON_LED));
  190. addInput(Port::create<GateInPort>(Vec(3, 170 + offset), Port::INPUT, module, MentalGateMaker::CYCLE_IN));
  191. addOutput(Port::create<GateOutPort>(Vec(93, 110), Port::OUTPUT, module, MentalGateMaker::OUTPUT));
  192. addOutput(Port::create<GateOutPort>(Vec(93, 140), Port::OUTPUT, module, MentalGateMaker::TRIG_OUT));
  193. addOutput(Port::create<GateOutPort>(Vec(93, 170), Port::OUTPUT, module, MentalGateMaker::FINISH_OUT));
  194. }
  195. } // namespace rack_plugin_mental
  196. using namespace rack_plugin_mental;
  197. RACK_PLUGIN_MODEL_INIT(mental, MentalGateMaker) {
  198. Model *modelMentalGateMaker = Model::create<MentalGateMaker, MentalGateMakerWidget>("mental", "MentalGateMaker", "Gate Maker", UTILITY_TAG);
  199. return modelMentalGateMaker;
  200. }