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.

149 lines
4.6KB

  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 gateTrigger[2];
  33. SchmittTrigger modeTrigger[2];
  34. bool mode[2] = {};
  35. bool outcome[2] = {};
  36. Branches() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {}
  37. void step() override;
  38. void onReset() override {
  39. for (int i = 0; i < 2; i++) {
  40. mode[i] = false;
  41. outcome[i] = false;
  42. }
  43. }
  44. };
  45. void Branches::step() {
  46. float gate = 0.0;
  47. for (int i = 0; i < 2; i++) {
  48. // mode button
  49. if (modeTrigger[i].process(params[MODE1_PARAM + i].value))
  50. mode[i] = !mode[i];
  51. if (inputs[IN1_INPUT + i].active)
  52. gate = inputs[IN1_INPUT + i].value;
  53. if (gateTrigger[i].process(gate)) {
  54. // trigger
  55. float r = randomUniform();
  56. float threshold = clamp(params[THRESHOLD1_PARAM + i].value + inputs[P1_INPUT + i].value / 10.f, 0.f, 1.f);
  57. bool toss = (r < threshold);
  58. if (!mode[i]) {
  59. // direct mode
  60. outcome[i] = toss;
  61. }
  62. else {
  63. // toggle mode
  64. outcome[i] = (outcome[i] != toss);
  65. }
  66. if (!outcome[i])
  67. lights[STATE1_POS_LIGHT + 2*i].value = 1.0;
  68. else
  69. lights[STATE1_NEG_LIGHT + 2*i].value = 1.0;
  70. }
  71. lights[STATE1_POS_LIGHT + 2*i].value *= 1.0 - engineGetSampleTime() * 15.0;
  72. lights[STATE1_NEG_LIGHT + 2*i].value *= 1.0 - engineGetSampleTime() * 15.0;
  73. lights[MODE1_LIGHT + i].value = mode[i] ? 1.0 : 0.0;
  74. outputs[OUT1A_OUTPUT + i].value = outcome[i] ? 0.0 : gate;
  75. outputs[OUT1B_OUTPUT + i].value = outcome[i] ? gate : 0.0;
  76. }
  77. }
  78. struct BranchesWidget : ModuleWidget {
  79. BranchesWidget(Branches *module) : ModuleWidget(module) {
  80. box.size = Vec(15*6, 380);
  81. {
  82. Panel *panel = new LightPanel();
  83. panel->backgroundImage = Image::load(assetPlugin(plugin, "res/Branches.png"));
  84. panel->box.size = box.size;
  85. addChild(panel);
  86. }
  87. addChild(Widget::create<ScrewSilver>(Vec(15, 0)));
  88. addChild(Widget::create<ScrewSilver>(Vec(15, 365)));
  89. addParam(ParamWidget::create<Rogan1PSRed>(Vec(24, 64), module, Branches::THRESHOLD1_PARAM, 0.0, 1.0, 0.5));
  90. addParam(ParamWidget::create<TL1105>(Vec(69, 58), module, Branches::MODE1_PARAM, 0.0, 1.0, 0.0));
  91. addInput(Port::create<PJ301MPort>(Vec(9, 122), Port::INPUT, module, Branches::IN1_INPUT));
  92. addInput(Port::create<PJ301MPort>(Vec(55, 122), Port::INPUT, module, Branches::P1_INPUT));
  93. addOutput(Port::create<PJ301MPort>(Vec(9, 160), Port::OUTPUT, module, Branches::OUT1A_OUTPUT));
  94. addOutput(Port::create<PJ301MPort>(Vec(55, 160), Port::OUTPUT, module, Branches::OUT1B_OUTPUT));
  95. addParam(ParamWidget::create<Rogan1PSGreen>(Vec(24, 220), module, Branches::THRESHOLD2_PARAM, 0.0, 1.0, 0.5));
  96. addParam(ParamWidget::create<TL1105>(Vec(69, 214), module, Branches::MODE2_PARAM, 0.0, 1.0, 0.0));
  97. addInput(Port::create<PJ301MPort>(Vec(9, 278), Port::INPUT, module, Branches::IN2_INPUT));
  98. addInput(Port::create<PJ301MPort>(Vec(55, 278), Port::INPUT, module, Branches::P2_INPUT));
  99. addOutput(Port::create<PJ301MPort>(Vec(9, 316), Port::OUTPUT, module, Branches::OUT2A_OUTPUT));
  100. addOutput(Port::create<PJ301MPort>(Vec(55, 316), Port::OUTPUT, module, Branches::OUT2B_OUTPUT));
  101. addChild(ModuleLightWidget::create<SmallLight<GreenRedLight>>(Vec(40, 169), module, Branches::STATE1_POS_LIGHT));
  102. addChild(ModuleLightWidget::create<SmallLight<GreenRedLight>>(Vec(40, 325), module, Branches::STATE2_POS_LIGHT));
  103. }
  104. void appendContextMenu(Menu *menu) override {
  105. Branches *branches = dynamic_cast<Branches*>(module);
  106. assert(branches);
  107. struct BranchesModeItem : MenuItem {
  108. Branches *branches;
  109. int channel;
  110. void onAction(EventAction &e) override {
  111. branches->mode[channel] ^= 1;
  112. }
  113. void step() override {
  114. rightText = branches->mode[channel] ? "Toggle" : "Latch";
  115. MenuItem::step();
  116. }
  117. };
  118. menu->addChild(construct<MenuLabel>());
  119. menu->addChild(construct<MenuLabel>(&MenuLabel::text, "Channels"));
  120. menu->addChild(construct<BranchesModeItem>(&MenuItem::text, "Channel 1 mode", &BranchesModeItem::branches, branches, &BranchesModeItem::channel, 0));
  121. menu->addChild(construct<BranchesModeItem>(&MenuItem::text, "Channel 2 mode", &BranchesModeItem::branches, branches, &BranchesModeItem::channel, 1));
  122. }
  123. };
  124. Model *modelBranches = Model::create<Branches, BranchesWidget>("Audible Instruments", "Branches", "Bernoulli Gate", RANDOM_TAG, DUAL_TAG);