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.

168 lines
5.0KB

  1. #include "plugin.hpp"
  2. struct Branches : Module {
  3. enum ParamIds {
  4. THRESHOLD1_PARAM,
  5. THRESHOLD2_PARAM,
  6. MODE1_PARAM,
  7. MODE2_PARAM,
  8. NUM_PARAMS
  9. };
  10. enum InputIds {
  11. IN1_INPUT,
  12. IN2_INPUT,
  13. P1_INPUT,
  14. P2_INPUT,
  15. NUM_INPUTS
  16. };
  17. enum OutputIds {
  18. OUT1A_OUTPUT,
  19. OUT2A_OUTPUT,
  20. OUT1B_OUTPUT,
  21. OUT2B_OUTPUT,
  22. NUM_OUTPUTS
  23. };
  24. enum LightIds {
  25. MODE1_LIGHT,
  26. MODE2_LIGHT,
  27. STATE1_POS_LIGHT, STATE1_NEG_LIGHT,
  28. STATE2_POS_LIGHT, STATE2_NEG_LIGHT,
  29. NUM_LIGHTS
  30. };
  31. dsp::SchmittTrigger gateTriggers[2];
  32. dsp::SchmittTrigger modeTriggers[2];
  33. bool modes[2] = {};
  34. bool outcomes[2] = {};
  35. Branches() {
  36. config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
  37. configParam(THRESHOLD1_PARAM, 0.0, 1.0, 0.5, "Probability 1");
  38. configParam(MODE1_PARAM, 0.0, 1.0, 0.0, "Mode 1");
  39. configParam(THRESHOLD2_PARAM, 0.0, 1.0, 0.5, "Probability 2");
  40. configParam(MODE2_PARAM, 0.0, 1.0, 0.0, "Mode 2");
  41. }
  42. json_t *dataToJson() override {
  43. json_t *rootJ = json_object();
  44. json_t *modesJ = json_array();
  45. for (int i = 0; i < 2; i++) {
  46. json_array_insert_new(modesJ, i, json_boolean(modes[i]));
  47. }
  48. json_object_set_new(rootJ, "modes", modesJ);
  49. return rootJ;
  50. }
  51. void dataFromJson(json_t *rootJ) override {
  52. json_t *modesJ = json_object_get(rootJ, "modes");
  53. if (modesJ) {
  54. for (int i = 0; i < 2; i++) {
  55. json_t *modeJ = json_array_get(modesJ, i);
  56. if (modeJ)
  57. modes[i] = json_boolean_value(modeJ);
  58. }
  59. }
  60. }
  61. void process(const ProcessArgs &args) override {
  62. float gate = 0.0;
  63. for (int i = 0; i < 2; i++) {
  64. // mode button
  65. if (modeTriggers[i].process(params[MODE1_PARAM + i].getValue()))
  66. modes[i] = !modes[i];
  67. if (inputs[IN1_INPUT + i].isConnected())
  68. gate = inputs[IN1_INPUT + i].getVoltage();
  69. if (gateTriggers[i].process(gate)) {
  70. // trigger
  71. float r = random::uniform();
  72. float threshold = clamp(params[THRESHOLD1_PARAM + i].getValue() + inputs[P1_INPUT + i].getVoltage() / 10.f, 0.f, 1.f);
  73. bool toss = (r < threshold);
  74. if (!modes[i]) {
  75. // direct modes
  76. outcomes[i] = toss;
  77. }
  78. else {
  79. // toggle modes
  80. outcomes[i] = (outcomes[i] != toss);
  81. }
  82. if (!outcomes[i])
  83. lights[STATE1_POS_LIGHT + 2*i].value = 1.0;
  84. else
  85. lights[STATE1_NEG_LIGHT + 2*i].value = 1.0;
  86. }
  87. lights[STATE1_POS_LIGHT + 2*i].value *= 1.0 - args.sampleTime * 15.0;
  88. lights[STATE1_NEG_LIGHT + 2*i].value *= 1.0 - args.sampleTime * 15.0;
  89. lights[MODE1_LIGHT + i].value = modes[i] ? 1.0 : 0.0;
  90. outputs[OUT1A_OUTPUT + i].setVoltage(outcomes[i] ? 0.0 : gate);
  91. outputs[OUT1B_OUTPUT + i].setVoltage(outcomes[i] ? gate : 0.0);
  92. }
  93. }
  94. void onReset() override {
  95. for (int i = 0; i < 2; i++) {
  96. modes[i] = false;
  97. outcomes[i] = false;
  98. }
  99. }
  100. };
  101. struct BranchesWidget : ModuleWidget {
  102. BranchesWidget(Branches *module) {
  103. setModule(module);
  104. setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/Branches.svg")));
  105. addChild(createWidget<ScrewSilver>(Vec(15, 0)));
  106. addChild(createWidget<ScrewSilver>(Vec(15, 365)));
  107. addParam(createParam<Rogan1PSRed>(Vec(24, 64), module, Branches::THRESHOLD1_PARAM));
  108. addParam(createParam<TL1105>(Vec(69, 58), module, Branches::MODE1_PARAM));
  109. addInput(createInput<PJ301MPort>(Vec(9, 122), module, Branches::IN1_INPUT));
  110. addInput(createInput<PJ301MPort>(Vec(55, 122), module, Branches::P1_INPUT));
  111. addOutput(createOutput<PJ301MPort>(Vec(9, 160), module, Branches::OUT1A_OUTPUT));
  112. addOutput(createOutput<PJ301MPort>(Vec(55, 160), module, Branches::OUT1B_OUTPUT));
  113. addParam(createParam<Rogan1PSGreen>(Vec(24, 220), module, Branches::THRESHOLD2_PARAM));
  114. addParam(createParam<TL1105>(Vec(69, 214), module, Branches::MODE2_PARAM));
  115. addInput(createInput<PJ301MPort>(Vec(9, 278), module, Branches::IN2_INPUT));
  116. addInput(createInput<PJ301MPort>(Vec(55, 278), module, Branches::P2_INPUT));
  117. addOutput(createOutput<PJ301MPort>(Vec(9, 316), module, Branches::OUT2A_OUTPUT));
  118. addOutput(createOutput<PJ301MPort>(Vec(55, 316), module, Branches::OUT2B_OUTPUT));
  119. addChild(createLight<SmallLight<GreenRedLight>>(Vec(40, 169), module, Branches::STATE1_POS_LIGHT));
  120. addChild(createLight<SmallLight<GreenRedLight>>(Vec(40, 325), module, Branches::STATE2_POS_LIGHT));
  121. }
  122. void appendContextMenu(Menu *menu) override {
  123. Branches *branches = dynamic_cast<Branches*>(module);
  124. assert(branches);
  125. struct BranchesModeItem : MenuItem {
  126. Branches *branches;
  127. int channel;
  128. void onAction(const event::Action &e) override {
  129. branches->modes[channel] ^= 1;
  130. }
  131. void step() override {
  132. rightText = branches->modes[channel] ? "Toggle" : "Latch";
  133. MenuItem::step();
  134. }
  135. };
  136. menu->addChild(construct<MenuLabel>());
  137. menu->addChild(construct<MenuLabel>(&MenuLabel::text, "Channels"));
  138. menu->addChild(construct<BranchesModeItem>(&MenuItem::text, "Channel 1 modes", &BranchesModeItem::branches, branches, &BranchesModeItem::channel, 0));
  139. menu->addChild(construct<BranchesModeItem>(&MenuItem::text, "Channel 2 modes", &BranchesModeItem::branches, branches, &BranchesModeItem::channel, 1));
  140. }
  141. };
  142. Model *modelBranches = createModel<Branches, BranchesWidget>("Branches");