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.

186 lines
5.3KB

  1. /*
  2. Heads
  3. */////////////////////////////////////////////////////////////////////////////
  4. #include "pvc.hpp"
  5. #include "dsp/digital.hpp"
  6. namespace rack_plugin_PvC {
  7. struct Heads : Module {
  8. enum ParamIds {
  9. PROB_UI,
  10. TOSS_MODE,
  11. TOSS_UI,
  12. FLIP_UI,
  13. SET_A_UI,
  14. SET_B_UI,
  15. NUM_PARAMS
  16. };
  17. enum InputIds {
  18. SIG_A_IN,
  19. SIG_B_IN,
  20. PROB_CV,
  21. TOSS_IN,
  22. FLIP_IN,
  23. SET_A_IN,
  24. SET_B_IN,
  25. NUM_INPUTS
  26. };
  27. enum OutputIds {
  28. SIG_OUT,
  29. GATE_A_OUT,
  30. GATE_B_OUT,
  31. TRIG_A_OUT,
  32. TRIG_B_OUT,
  33. NUM_OUTPUTS
  34. };
  35. enum LightIds {
  36. A_LED,
  37. B_LED,
  38. DIR_LED,
  39. FLP_LED,
  40. NUM_LIGHTS
  41. };
  42. bool gate = false;
  43. bool flipMode = false;
  44. SchmittTrigger tossTrigger;
  45. SchmittTrigger flipTrigger;
  46. SchmittTrigger resetTrigger;
  47. PulseGenerator gatePulse;
  48. Heads() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {}
  49. void step() override;
  50. void reset() override {
  51. gate = false;
  52. flipMode = false;
  53. }
  54. json_t *toJson() override {
  55. json_t *rootJ = json_object();
  56. json_t *gateStateJ = json_boolean(gate);
  57. json_object_set_new(rootJ, "gateState", gateStateJ);
  58. return rootJ;
  59. }
  60. void fromJson(json_t *rootJ) override {
  61. json_t *gateStateJ = json_object_get(rootJ, "gateState");
  62. if (gateStateJ)
  63. gate = json_boolean_value(gateStateJ);
  64. }
  65. };
  66. void Heads::step() {
  67. flipMode = params[TOSS_MODE].value;
  68. if (tossTrigger.process(inputs[TOSS_IN].value + params[TOSS_UI].value)) {
  69. gatePulse.trigger(0.01f);
  70. if (flipMode)
  71. gate = (randomUniform() < params[PROB_UI].value + inputs[PROB_CV].value) ? !gate : gate;
  72. else
  73. gate = (randomUniform() < (params[PROB_UI].value + inputs[PROB_CV].value*0.1f));
  74. }
  75. if (flipTrigger.process(inputs[FLIP_IN].value + params[FLIP_UI].value)) {
  76. gatePulse.trigger(0.01f);
  77. gate = !gate;
  78. }
  79. if (resetTrigger.process(inputs[SET_A_IN].value + params[SET_A_UI].value)) {
  80. gatePulse.trigger(0.01f);
  81. gate = false;
  82. }
  83. if (resetTrigger.process(inputs[SET_B_IN].value + params[SET_B_UI].value)) {
  84. gatePulse.trigger(0.01f);
  85. gate = true;
  86. }
  87. outputs[SIG_OUT].value = !gate ? inputs[SIG_A_IN].value : inputs[SIG_B_IN].value;
  88. outputs[GATE_A_OUT].value = !gate * 10.0f;
  89. outputs[TRIG_A_OUT].value = !gate * gatePulse.process(1.0/engineGetSampleRate()) * 10.0f;
  90. outputs[GATE_B_OUT].value = gate * 10.0f;
  91. outputs[TRIG_B_OUT].value = gate * gatePulse.process(1.0/engineGetSampleRate()) * 10.0f;
  92. lights[A_LED].value = !gate;
  93. lights[B_LED].value = gate;
  94. lights[DIR_LED].value = !flipMode;
  95. lights[FLP_LED].value = flipMode;
  96. }
  97. struct ModeToggle : SVGSwitch, ToggleSwitch {
  98. ModeToggle() {
  99. addFrame(SVG::load(assetPlugin(plugin, "res/components/empty.svg")));
  100. box.size = Vec(12,6);
  101. }
  102. };
  103. struct HeadsWidget : ModuleWidget {
  104. HeadsWidget(Heads *module);
  105. };
  106. HeadsWidget::HeadsWidget(Heads *module) : ModuleWidget(module) {
  107. setPanel(SVG::load(assetPlugin(plugin, "res/panels/Heads.svg")));
  108. // screws
  109. addChild(Widget::create<ScrewHead1>(Vec(15, 0)));
  110. addChild(Widget::create<ScrewHead2>(Vec(box.size.x - 15, 0)));
  111. addChild(Widget::create<ScrewHead3>(Vec(30, 365)));
  112. // addChild(Widget::create<ScrewHead4>(Vec(box.size.x - 15, 365)));
  113. addInput(Port::create<InPortAud>(Vec(4,22), Port::INPUT, module, Heads::SIG_A_IN));
  114. addInput(Port::create<InPortAud>(Vec(34,22), Port::INPUT, module, Heads::SIG_B_IN));
  115. addParam(ParamWidget::create<PvCKnob>(Vec(19,64),module, Heads::PROB_UI, 0.0f, 1.0f, 0.5f));
  116. addInput(Port::create<InPortCtrl>(Vec(19,88), Port::INPUT, module, Heads::PROB_CV));
  117. addInput(Port::create<InPortBin>(Vec(19,124), Port::INPUT, module, Heads::TOSS_IN));
  118. addParam(ParamWidget::create<LabelButtonL>(Vec(12,149), module, Heads::TOSS_UI, 0, 1, 0));
  119. addChild(ModuleLightWidget::create<FourPixLight<OrangeLED>>(Vec(25,165),module, Heads::DIR_LED));
  120. addChild(ModuleLightWidget::create<FourPixLight<BlueLED>>(Vec(31,165),module, Heads::FLP_LED));
  121. addParam(ParamWidget::create<ModeToggle>(Vec(24,164), module, Heads::TOSS_MODE, 0, 1, 0));
  122. addInput(Port::create<InPortBin>(Vec(19,180), Port::INPUT, module, Heads::FLIP_IN));
  123. addParam(ParamWidget::create<LabelButtonL>(Vec(12,205), module, Heads::FLIP_UI, 0, 1, 0));
  124. addInput(Port::create<InPortBin>(Vec(4,222), Port::INPUT, module, Heads::SET_A_IN));
  125. addParam(ParamWidget::create<LabelButtonS>(Vec(3,247), module, Heads::SET_A_UI, 0, 1, 0));
  126. addInput(Port::create<InPortBin>(Vec(34,222), Port::INPUT, module, Heads::SET_B_IN));
  127. addParam(ParamWidget::create<LabelButtonS>(Vec(33,247), module, Heads::SET_B_UI, 0, 1, 0));
  128. addOutput(Port::create<OutPortVal>(Vec(19,276), Port::OUTPUT, module, Heads::SIG_OUT));
  129. addChild(ModuleLightWidget::create<FourPixLight<CyanLED>>(Vec(13,267),module, Heads::A_LED));
  130. addOutput(Port::create<OutPortBin>(Vec(4,312), Port::OUTPUT, module, Heads::GATE_A_OUT));
  131. addOutput(Port::create<OutPortBin>(Vec(4,336), Port::OUTPUT, module, Heads::TRIG_A_OUT));
  132. addChild(ModuleLightWidget::create<FourPixLight<PurpleLED>>(Vec(43,267),module, Heads::B_LED));
  133. addOutput(Port::create<OutPortBin>(Vec(34,312), Port::OUTPUT, module, Heads::GATE_B_OUT));
  134. addOutput(Port::create<OutPortBin>(Vec(34,336), Port::OUTPUT, module, Heads::TRIG_B_OUT));
  135. }
  136. } // namespace rack_plugin_PvC
  137. using namespace rack_plugin_PvC;
  138. RACK_PLUGIN_MODEL_INIT(PvC, Heads) {
  139. Model *modelHeads = Model::create<Heads, HeadsWidget>(
  140. "PvC", "Heads", "Heads", LOGIC_TAG, SWITCH_TAG, RANDOM_TAG);
  141. return modelHeads;
  142. }