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.

165 lines
5.0KB

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