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.

Branches.cpp 5.9KB

5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  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. ENUMS(STATE_LIGHTS, 2 * 2),
  26. NUM_LIGHTS
  27. };
  28. dsp::BooleanTrigger gateTriggers[2][16];
  29. dsp::BooleanTrigger modeTriggers[2];
  30. bool modes[2] = {};
  31. bool outcomes[2][16] = {};
  32. Branches() {
  33. config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
  34. configParam(THRESHOLD1_PARAM, 0.0, 1.0, 0.5, "Channel 1 probability", "%", 0, 100);
  35. configParam(MODE1_PARAM, 0.0, 1.0, 0.0, "Channel 1 mode");
  36. configParam(THRESHOLD2_PARAM, 0.0, 1.0, 0.5, "Channel 2 probability", "%", 0, 100);
  37. configParam(MODE2_PARAM, 0.0, 1.0, 0.0, "Channel 2 mode");
  38. }
  39. void process(const ProcessArgs& args) override {
  40. for (int i = 0; i < 2; i++) {
  41. // Get input
  42. Input* input = &inputs[IN1_INPUT + i];
  43. // 2nd input is normalized to 1st.
  44. if (i == 1 && !input->isConnected())
  45. input = &inputs[IN1_INPUT + 0];
  46. int channels = std::max(input->getChannels(), 1);
  47. // mode button
  48. if (modeTriggers[i].process(params[MODE1_PARAM + i].getValue() > 0.f))
  49. modes[i] ^= true;
  50. bool lightA = false;
  51. bool lightB = false;
  52. // Process triggers
  53. for (int c = 0; c < channels; c++) {
  54. bool gate = input->getVoltage(c) >= 2.f;
  55. if (gateTriggers[i][c].process(gate)) {
  56. // trigger
  57. // We don't have to clamp here because the threshold comparison works without it.
  58. float threshold = params[THRESHOLD1_PARAM + i].getValue() + inputs[P1_INPUT + i].getPolyVoltage(c) / 10.f;
  59. bool toss = (random::uniform() < threshold);
  60. if (!modes[i]) {
  61. // direct modes
  62. outcomes[i][c] = toss;
  63. }
  64. else {
  65. // toggle modes
  66. if (toss)
  67. outcomes[i][c] ^= true;
  68. }
  69. }
  70. // Output gate logic
  71. bool gateA = !outcomes[i][c] && (modes[i] ? true : gate);
  72. bool gateB = outcomes[i][c] && (modes[i] ? true : gate);
  73. if (gateA)
  74. lightA = true;
  75. if (gateB)
  76. lightB = true;
  77. // Set output gates
  78. outputs[OUT1A_OUTPUT + i].setVoltage(gateA ? 10.f : 0.f, c);
  79. outputs[OUT1B_OUTPUT + i].setVoltage(gateB ? 10.f : 0.f, c);
  80. }
  81. outputs[OUT1A_OUTPUT + i].setChannels(channels);
  82. outputs[OUT1B_OUTPUT + i].setChannels(channels);
  83. lights[STATE_LIGHTS + i * 2 + 1].setSmoothBrightness(lightA, args.sampleTime);
  84. lights[STATE_LIGHTS + i * 2 + 0].setSmoothBrightness(lightB, args.sampleTime);
  85. }
  86. }
  87. void onReset() override {
  88. for (int i = 0; i < 2; i++) {
  89. modes[i] = false;
  90. for (int c = 0; c < 16; c++) {
  91. outcomes[i][c] = false;
  92. }
  93. }
  94. }
  95. json_t* dataToJson() override {
  96. json_t* rootJ = json_object();
  97. json_t* modesJ = json_array();
  98. for (int i = 0; i < 2; i++) {
  99. json_array_insert_new(modesJ, i, json_boolean(modes[i]));
  100. }
  101. json_object_set_new(rootJ, "modes", modesJ);
  102. return rootJ;
  103. }
  104. void dataFromJson(json_t* rootJ) override {
  105. json_t* modesJ = json_object_get(rootJ, "modes");
  106. if (modesJ) {
  107. for (int i = 0; i < 2; i++) {
  108. json_t* modeJ = json_array_get(modesJ, i);
  109. if (modeJ)
  110. modes[i] = json_boolean_value(modeJ);
  111. }
  112. }
  113. }
  114. };
  115. struct BranchesWidget : ModuleWidget {
  116. BranchesWidget(Branches* module) {
  117. setModule(module);
  118. setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/Branches.svg")));
  119. addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, 0)));
  120. addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  121. addParam(createParamCentered<TL1105>(mm2px(Vec(25.852, 22.24)), module, Branches::MODE1_PARAM));
  122. addParam(createParamCentered<Rogan1PSRed>(mm2px(Vec(15.057, 28.595)), module, Branches::THRESHOLD1_PARAM));
  123. addParam(createParamCentered<TL1105>(mm2px(Vec(25.852, 74.95)), module, Branches::MODE2_PARAM));
  124. addParam(createParamCentered<Rogan1PSGreen>(mm2px(Vec(15.057, 81.296)), module, Branches::THRESHOLD2_PARAM));
  125. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(7.112, 45.74)), module, Branches::IN1_INPUT));
  126. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(22.991, 45.74)), module, Branches::P1_INPUT));
  127. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(7.112, 98.44)), module, Branches::IN2_INPUT));
  128. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(22.991, 98.44)), module, Branches::P2_INPUT));
  129. addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(7.112, 58.44)), module, Branches::OUT1A_OUTPUT));
  130. addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(22.991, 58.44)), module, Branches::OUT1B_OUTPUT));
  131. addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(7.112, 111.14)), module, Branches::OUT2A_OUTPUT));
  132. addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(22.991, 111.14)), module, Branches::OUT2B_OUTPUT));
  133. addChild(createLightCentered<MediumLight<GreenRedLight>>(mm2px(Vec(15.052, 58.45)), module, Branches::STATE_LIGHTS + 0 * 2));
  134. addChild(createLightCentered<MediumLight<GreenRedLight>>(mm2px(Vec(15.052, 111.151)), module, Branches::STATE_LIGHTS + 1 * 2));
  135. }
  136. void appendContextMenu(Menu* menu) override {
  137. Branches* branches = dynamic_cast<Branches*>(module);
  138. assert(branches);
  139. struct BranchesModeItem : MenuItem {
  140. Branches* branches;
  141. int i;
  142. void onAction(const event::Action& e) override {
  143. branches->modes[i] ^= 1;
  144. }
  145. void step() override {
  146. rightText = branches->modes[i] ? "Latch" : "Toggle";
  147. MenuItem::step();
  148. }
  149. };
  150. menu->addChild(new MenuSeparator);
  151. menu->addChild(construct<MenuLabel>(&MenuLabel::text, "Channels"));
  152. menu->addChild(construct<BranchesModeItem>(&MenuItem::text, "Channel 1 mode", &BranchesModeItem::branches, branches, &BranchesModeItem::i, 0));
  153. menu->addChild(construct<BranchesModeItem>(&MenuItem::text, "Channel 2 mode", &BranchesModeItem::branches, branches, &BranchesModeItem::i, 1));
  154. }
  155. };
  156. Model* modelBranches = createModel<Branches, BranchesWidget>("Branches");