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.

210 lines
7.4KB

  1. #include "plugin.hpp"
  2. struct Gates : Module {
  3. enum ParamId {
  4. LENGTH_PARAM,
  5. RESET_PARAM,
  6. PARAMS_LEN
  7. };
  8. enum InputId {
  9. LENGTH_INPUT,
  10. IN_INPUT,
  11. RESET_INPUT,
  12. INPUTS_LEN
  13. };
  14. enum OutputId {
  15. RISE_OUTPUT,
  16. FALL_OUTPUT,
  17. FLIP_OUTPUT,
  18. FLOP_OUTPUT,
  19. GATE_OUTPUT,
  20. END_OUTPUT,
  21. OUTPUTS_LEN
  22. };
  23. enum LightId {
  24. RESET_LIGHT,
  25. ENUMS(RISE_LIGHT, 2),
  26. ENUMS(FALL_LIGHT, 2),
  27. ENUMS(FLIP_LIGHT, 2),
  28. ENUMS(FLOP_LIGHT, 2),
  29. ENUMS(GATE_LIGHT, 2),
  30. ENUMS(END_LIGHT, 2),
  31. LIGHTS_LEN
  32. };
  33. dsp::BooleanTrigger resetParamTrigger;
  34. bool state[16] = {};
  35. dsp::SchmittTrigger resetTrigger[16];
  36. dsp::PulseGenerator risePulse[16];
  37. dsp::PulseGenerator fallPulse[16];
  38. dsp::PulseGenerator eogPulse[16];
  39. bool flop[16] = {};
  40. float gateTime[16] = {};
  41. dsp::ClockDivider lightDivider;
  42. Gates() {
  43. config(PARAMS_LEN, INPUTS_LEN, OUTPUTS_LEN, LIGHTS_LEN);
  44. configParam(LENGTH_PARAM, std::log2(1e-3f), std::log2(10.f), std::log2(0.1f), "Gate length", " ms", 2, 1000);
  45. configButton(RESET_PARAM, "Reset flip/flop");
  46. configInput(LENGTH_INPUT, "Gate length");
  47. configInput(IN_INPUT, "Gate");
  48. configInput(RESET_INPUT, "Reset flip/flop");
  49. configOutput(RISE_OUTPUT, "Rising edge trigger");
  50. configOutput(FALL_OUTPUT, "Falling edge trigger");
  51. configOutput(FLIP_OUTPUT, "Flip");
  52. configOutput(FLOP_OUTPUT, "Flop");
  53. configOutput(GATE_OUTPUT, "Gate");
  54. configOutput(END_OUTPUT, "End of gate");
  55. lightDivider.setDivision(32);
  56. for (int c = 0; c < 16; c++) {
  57. gateTime[c] = INFINITY;
  58. }
  59. }
  60. void process(const ProcessArgs& args) override {
  61. int channels = std::max(1, inputs[IN_INPUT].getChannels());
  62. bool anyRise = false;
  63. bool anyFall = false;
  64. bool anyFlip = false;
  65. bool anyFlop = false;
  66. bool anyGate = false;
  67. bool anyEnd = false;
  68. // Reset
  69. bool resetButton = false;
  70. if (resetParamTrigger.process(params[RESET_PARAM].getValue() > 0.f)) {
  71. resetButton = true;
  72. }
  73. // Process channels
  74. for (int c = 0; c < channels; c++) {
  75. float in = inputs[IN_INPUT].getVoltage(c);
  76. if (state[c]) {
  77. // HIGH to LOW
  78. if (in <= 0.1f) {
  79. state[c] = false;
  80. fallPulse[c].trigger(1e-3f);
  81. }
  82. }
  83. else {
  84. // LOW to HIGH
  85. if (in >= 2.f) {
  86. state[c] = true;
  87. risePulse[c].trigger(1e-3f);
  88. // Flip flop
  89. flop[c] ^= true;
  90. // Gate
  91. gateTime[c] = 0.f;
  92. }
  93. }
  94. // Reset
  95. bool reset = resetButton;
  96. if (resetTrigger[c].process(inputs[RESET_INPUT].getVoltage(c), 0.1f, 2.f)) {
  97. reset = true;
  98. }
  99. if (reset) {
  100. flop[c] = false;
  101. }
  102. // Gate
  103. float gatePitch = params[LENGTH_PARAM].getValue() + inputs[LENGTH_INPUT].getPolyVoltage(c);
  104. float gateLength = dsp::approxExp2_taylor5(gatePitch + 30.f) / 1073741824;
  105. if (std::isfinite(gateTime[c])) {
  106. gateTime[c] += args.sampleTime;
  107. if (reset || gateTime[c] >= gateLength) {
  108. gateTime[c] = INFINITY;
  109. eogPulse[c].trigger(1e-3f);
  110. }
  111. }
  112. // Outputs
  113. bool rise = risePulse[c].process(args.sampleTime);
  114. outputs[RISE_OUTPUT].setVoltage(rise ? 10.f : 0.f, c);
  115. anyRise = anyRise || rise;
  116. bool fall = fallPulse[c].process(args.sampleTime);
  117. outputs[FALL_OUTPUT].setVoltage(fall ? 10.f : 0.f, c);
  118. anyFall = anyFall || fall;
  119. outputs[FLIP_OUTPUT].setVoltage(!flop[c] ? 10.f : 0.f, c);
  120. anyFlip = anyFlip || !flop[c];
  121. outputs[FLOP_OUTPUT].setVoltage(flop[c] ? 10.f : 0.f, c);
  122. anyFlop = anyFlop || flop[c];
  123. bool gate = std::isfinite(gateTime[c]);
  124. outputs[GATE_OUTPUT].setVoltage(gate ? 10.f : 0.f, c);
  125. anyGate = anyGate || gate;
  126. bool end = eogPulse[c].process(args.sampleTime);
  127. outputs[END_OUTPUT].setVoltage(end ? 10.f : 0.f, c);
  128. anyEnd = anyEnd || end;
  129. }
  130. outputs[RISE_OUTPUT].setChannels(channels);
  131. outputs[FALL_OUTPUT].setChannels(channels);
  132. outputs[FLIP_OUTPUT].setChannels(channels);
  133. outputs[FLOP_OUTPUT].setChannels(channels);
  134. outputs[GATE_OUTPUT].setChannels(channels);
  135. outputs[END_OUTPUT].setChannels(channels);
  136. if (lightDivider.process()) {
  137. float lightTime = args.sampleTime * lightDivider.getDivision();
  138. lights[RESET_LIGHT].setBrightness(params[RESET_PARAM].getValue() > 0.f);
  139. lights[RISE_LIGHT + 0].setBrightnessSmooth(anyRise && channels <= 1, lightTime);
  140. lights[RISE_LIGHT + 1].setBrightnessSmooth(anyRise && channels > 1, lightTime);
  141. lights[FALL_LIGHT + 0].setBrightnessSmooth(anyFall && channels <= 1, lightTime);
  142. lights[FALL_LIGHT + 1].setBrightnessSmooth(anyFall && channels > 1, lightTime);
  143. lights[FLIP_LIGHT + 0].setBrightnessSmooth(anyFlip && channels <= 1, lightTime);
  144. lights[FLIP_LIGHT + 1].setBrightnessSmooth(anyFlip && channels > 1, lightTime);
  145. lights[FLOP_LIGHT + 0].setBrightnessSmooth(anyFlop && channels <= 1, lightTime);
  146. lights[FLOP_LIGHT + 1].setBrightnessSmooth(anyFlop && channels > 1, lightTime);
  147. lights[GATE_LIGHT + 0].setBrightnessSmooth(anyGate && channels <= 1, lightTime);
  148. lights[GATE_LIGHT + 1].setBrightnessSmooth(anyGate && channels > 1, lightTime);
  149. lights[END_LIGHT + 0].setBrightnessSmooth(anyEnd && channels <= 1, lightTime);
  150. lights[END_LIGHT + 1].setBrightnessSmooth(anyEnd && channels > 1, lightTime);
  151. }
  152. }
  153. };
  154. struct GatesWidget : ModuleWidget {
  155. GatesWidget(Gates* module) {
  156. setModule(module);
  157. setPanel(createPanel(asset::plugin(pluginInstance, "res/Gates.svg")));
  158. addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, 0)));
  159. addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0)));
  160. addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  161. addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  162. addParam(createParamCentered<RoundLargeBlackKnob>(mm2px(Vec(12.646, 26.755)), module, Gates::LENGTH_PARAM));
  163. addParam(createLightParamCentered<VCVLightBezel<>>(mm2px(Vec(18.146, 52.31)), module, Gates::RESET_PARAM, Gates::RESET_LIGHT));
  164. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(7.299, 52.31)), module, Gates::LENGTH_INPUT));
  165. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(7.297, 67.53)), module, Gates::IN_INPUT));
  166. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(18.132, 67.53)), module, Gates::RESET_INPUT));
  167. addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(7.297, 82.732)), module, Gates::RISE_OUTPUT));
  168. addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(18.134, 82.732)), module, Gates::FALL_OUTPUT));
  169. addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(7.297, 97.958)), module, Gates::FLIP_OUTPUT));
  170. addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(18.134, 97.958)), module, Gates::FLOP_OUTPUT));
  171. addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(7.297, 113.115)), module, Gates::GATE_OUTPUT));
  172. addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(18.134, 113.115)), module, Gates::END_OUTPUT));
  173. addChild(createLightCentered<TinyLight<YellowBlueLight<>>>(mm2px(Vec(11.027, 79.007)), module, Gates::RISE_LIGHT));
  174. addChild(createLightCentered<TinyLight<YellowBlueLight<>>>(mm2px(Vec(21.864, 79.007)), module, Gates::FALL_LIGHT));
  175. addChild(createLightCentered<TinyLight<YellowBlueLight<>>>(mm2px(Vec(11.027, 94.233)), module, Gates::FLIP_LIGHT));
  176. addChild(createLightCentered<TinyLight<YellowBlueLight<>>>(mm2px(Vec(21.864, 94.233)), module, Gates::FLOP_LIGHT));
  177. addChild(createLightCentered<TinyLight<YellowBlueLight<>>>(mm2px(Vec(11.027, 109.393)), module, Gates::GATE_LIGHT));
  178. addChild(createLightCentered<TinyLight<YellowBlueLight<>>>(mm2px(Vec(21.864, 109.393)), module, Gates::END_LIGHT));
  179. }
  180. };
  181. Model* modelGates = createModel<Gates, GatesWidget>("Gates");