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.

241 lines
8.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. DELAY_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(DELAY_LIGHT, 2),
  31. LIGHTS_LEN
  32. };
  33. double time = 0.0;
  34. dsp::BooleanTrigger resetParamTrigger;
  35. dsp::ClockDivider lightDivider;
  36. struct Engine {
  37. bool state = false;
  38. dsp::SchmittTrigger resetTrigger;
  39. dsp::PulseGenerator risePulse;
  40. dsp::PulseGenerator fallPulse;
  41. bool flop = false;
  42. float gateTime = INFINITY;
  43. // TODO Change this to a circular buffer with binary search, to avoid allocations when events are pushed.
  44. std::map<double, bool> stateEvents;
  45. };
  46. Engine engines[16];
  47. Gates() {
  48. config(PARAMS_LEN, INPUTS_LEN, OUTPUTS_LEN, LIGHTS_LEN);
  49. configParam(LENGTH_PARAM, std::log2(1e-3f), std::log2(10.f), std::log2(0.1f), "Gate length", " ms", 2, 1000);
  50. configButton(RESET_PARAM, "Reset flip/flop");
  51. configInput(LENGTH_INPUT, "Gate length");
  52. configInput(IN_INPUT, "Gate");
  53. configInput(RESET_INPUT, "Reset flip/flop");
  54. configOutput(RISE_OUTPUT, "Rising edge trigger");
  55. configOutput(FALL_OUTPUT, "Falling edge trigger");
  56. configOutput(FLIP_OUTPUT, "Flip");
  57. configOutput(FLOP_OUTPUT, "Flop");
  58. configOutput(GATE_OUTPUT, "Gate");
  59. configOutput(DELAY_OUTPUT, "Gate delay");
  60. lightDivider.setDivision(32);
  61. }
  62. void process(const ProcessArgs& args) override {
  63. int channels = std::max(1, inputs[IN_INPUT].getChannels());
  64. bool anyRise = false;
  65. bool anyFall = false;
  66. bool anyFlip = false;
  67. bool anyFlop = false;
  68. bool anyGate = false;
  69. bool anyDelay = false;
  70. // Reset
  71. bool resetButton = false;
  72. if (resetParamTrigger.process(params[RESET_PARAM].getValue() > 0.f)) {
  73. resetButton = true;
  74. }
  75. // Process channels
  76. for (int c = 0; c < channels; c++) {
  77. Engine& e = engines[c];
  78. float in = inputs[IN_INPUT].getVoltage(c);
  79. bool newState = false;
  80. if (e.state) {
  81. // HIGH to LOW
  82. if (in <= 0.1f) {
  83. e.state = false;
  84. e.fallPulse.trigger(1e-3f);
  85. newState = true;
  86. }
  87. }
  88. else {
  89. // LOW to HIGH
  90. if (in >= 2.f) {
  91. e.state = true;
  92. e.risePulse.trigger(1e-3f);
  93. // Flip flop
  94. e.flop ^= true;
  95. // Gate
  96. e.gateTime = 0.f;
  97. newState = true;
  98. }
  99. }
  100. // Reset
  101. bool reset = resetButton;
  102. if (e.resetTrigger.process(inputs[RESET_INPUT].getVoltage(c), 0.1f, 2.f)) {
  103. reset = true;
  104. }
  105. if (reset) {
  106. e.flop = false;
  107. e.stateEvents.clear();
  108. }
  109. // Outputs
  110. bool rise = e.risePulse.process(args.sampleTime);
  111. outputs[RISE_OUTPUT].setVoltage(rise ? 10.f : 0.f, c);
  112. anyRise = anyRise || rise;
  113. bool fall = e.fallPulse.process(args.sampleTime);
  114. outputs[FALL_OUTPUT].setVoltage(fall ? 10.f : 0.f, c);
  115. anyFall = anyFall || fall;
  116. outputs[FLIP_OUTPUT].setVoltage(!e.flop ? 10.f : 0.f, c);
  117. anyFlip = anyFlip || !e.flop;
  118. outputs[FLOP_OUTPUT].setVoltage(e.flop ? 10.f : 0.f, c);
  119. anyFlop = anyFlop || e.flop;
  120. // Gate output
  121. float gatePitch = params[LENGTH_PARAM].getValue() + inputs[LENGTH_INPUT].getPolyVoltage(c);
  122. float gateLength = dsp::exp2_taylor5(gatePitch + 30.f) / 1073741824;
  123. if (std::isfinite(e.gateTime)) {
  124. e.gateTime += args.sampleTime;
  125. if (reset || e.gateTime >= gateLength) {
  126. e.gateTime = INFINITY;
  127. }
  128. }
  129. bool gate = std::isfinite(e.gateTime);
  130. outputs[GATE_OUTPUT].setVoltage(gate ? 10.f : 0.f, c);
  131. anyGate = anyGate || gate;
  132. // Gate delay output
  133. if (outputs[DELAY_OUTPUT].isConnected()) {
  134. bool delayGate = false;
  135. // Timestamp of past gate
  136. double delayTime = time - gateLength;
  137. // Find event less than or equal to delayTime.
  138. // If not found, gate will be off.
  139. auto eventIt = e.stateEvents.upper_bound(delayTime);
  140. if (eventIt != e.stateEvents.begin()) {
  141. eventIt--;
  142. delayGate = eventIt->second;
  143. }
  144. if (newState) {
  145. // Keep buffer a reasonable size
  146. if (e.stateEvents.size() >= (1 << 10) - 1) {
  147. e.stateEvents.erase(e.stateEvents.begin());
  148. }
  149. // Insert current state at current time
  150. e.stateEvents[time] = e.state;
  151. }
  152. outputs[DELAY_OUTPUT].setVoltage(delayGate ? 10.f : 0.f, c);
  153. anyDelay = anyDelay || delayGate;
  154. }
  155. }
  156. time += args.sampleTime;
  157. outputs[RISE_OUTPUT].setChannels(channels);
  158. outputs[FALL_OUTPUT].setChannels(channels);
  159. outputs[FLIP_OUTPUT].setChannels(channels);
  160. outputs[FLOP_OUTPUT].setChannels(channels);
  161. outputs[GATE_OUTPUT].setChannels(channels);
  162. outputs[DELAY_OUTPUT].setChannels(channels);
  163. if (lightDivider.process()) {
  164. float lightTime = args.sampleTime * lightDivider.getDivision();
  165. lights[RESET_LIGHT].setBrightness(params[RESET_PARAM].getValue() > 0.f);
  166. lights[RISE_LIGHT + 0].setBrightnessSmooth(anyRise && channels <= 1, lightTime);
  167. lights[RISE_LIGHT + 1].setBrightnessSmooth(anyRise && channels > 1, lightTime);
  168. lights[FALL_LIGHT + 0].setBrightnessSmooth(anyFall && channels <= 1, lightTime);
  169. lights[FALL_LIGHT + 1].setBrightnessSmooth(anyFall && channels > 1, lightTime);
  170. lights[FLIP_LIGHT + 0].setBrightnessSmooth(anyFlip && channels <= 1, lightTime);
  171. lights[FLIP_LIGHT + 1].setBrightnessSmooth(anyFlip && channels > 1, lightTime);
  172. lights[FLOP_LIGHT + 0].setBrightnessSmooth(anyFlop && channels <= 1, lightTime);
  173. lights[FLOP_LIGHT + 1].setBrightnessSmooth(anyFlop && channels > 1, lightTime);
  174. lights[GATE_LIGHT + 0].setBrightnessSmooth(anyGate && channels <= 1, lightTime);
  175. lights[GATE_LIGHT + 1].setBrightnessSmooth(anyGate && channels > 1, lightTime);
  176. lights[DELAY_LIGHT + 0].setBrightnessSmooth(anyDelay && channels <= 1, lightTime);
  177. lights[DELAY_LIGHT + 1].setBrightnessSmooth(anyDelay && channels > 1, lightTime);
  178. }
  179. }
  180. };
  181. struct GatesWidget : ModuleWidget {
  182. GatesWidget(Gates* module) {
  183. setModule(module);
  184. setPanel(createPanel(asset::plugin(pluginInstance, "res/Gates.svg"), asset::plugin(pluginInstance, "res/Gates-dark.svg")));
  185. addChild(createWidget<ThemedScrew>(Vec(RACK_GRID_WIDTH, 0)));
  186. addChild(createWidget<ThemedScrew>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0)));
  187. addChild(createWidget<ThemedScrew>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  188. addChild(createWidget<ThemedScrew>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  189. addParam(createParamCentered<RoundLargeBlackKnob>(mm2px(Vec(12.646, 26.755)), module, Gates::LENGTH_PARAM));
  190. addParam(createLightParamCentered<VCVLightBezel<>>(mm2px(Vec(18.146, 52.31)), module, Gates::RESET_PARAM, Gates::RESET_LIGHT));
  191. addInput(createInputCentered<ThemedPJ301MPort>(mm2px(Vec(7.299, 52.31)), module, Gates::LENGTH_INPUT));
  192. addInput(createInputCentered<ThemedPJ301MPort>(mm2px(Vec(7.297, 67.53)), module, Gates::IN_INPUT));
  193. addInput(createInputCentered<ThemedPJ301MPort>(mm2px(Vec(18.132, 67.53)), module, Gates::RESET_INPUT));
  194. addOutput(createOutputCentered<ThemedPJ301MPort>(mm2px(Vec(7.297, 82.732)), module, Gates::RISE_OUTPUT));
  195. addOutput(createOutputCentered<ThemedPJ301MPort>(mm2px(Vec(18.134, 82.732)), module, Gates::FALL_OUTPUT));
  196. addOutput(createOutputCentered<ThemedPJ301MPort>(mm2px(Vec(7.297, 97.958)), module, Gates::FLIP_OUTPUT));
  197. addOutput(createOutputCentered<ThemedPJ301MPort>(mm2px(Vec(18.134, 97.958)), module, Gates::FLOP_OUTPUT));
  198. addOutput(createOutputCentered<ThemedPJ301MPort>(mm2px(Vec(7.297, 113.115)), module, Gates::GATE_OUTPUT));
  199. addOutput(createOutputCentered<ThemedPJ301MPort>(mm2px(Vec(18.134, 113.115)), module, Gates::DELAY_OUTPUT));
  200. addChild(createLightCentered<TinyLight<YellowBlueLight<>>>(mm2px(Vec(11.027, 79.007)), module, Gates::RISE_LIGHT));
  201. addChild(createLightCentered<TinyLight<YellowBlueLight<>>>(mm2px(Vec(21.864, 79.007)), module, Gates::FALL_LIGHT));
  202. addChild(createLightCentered<TinyLight<YellowBlueLight<>>>(mm2px(Vec(11.027, 94.233)), module, Gates::FLIP_LIGHT));
  203. addChild(createLightCentered<TinyLight<YellowBlueLight<>>>(mm2px(Vec(21.864, 94.233)), module, Gates::FLOP_LIGHT));
  204. addChild(createLightCentered<TinyLight<YellowBlueLight<>>>(mm2px(Vec(11.027, 109.393)), module, Gates::GATE_LIGHT));
  205. addChild(createLightCentered<TinyLight<YellowBlueLight<>>>(mm2px(Vec(21.864, 109.393)), module, Gates::DELAY_LIGHT));
  206. }
  207. };
  208. Model* modelGates = createModel<Gates, GatesWidget>("Gates");