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.

204 lines
7.8KB

  1. #include "plugin.hpp"
  2. // Only valid for <1, 4> and <4, 1>
  3. template <int INPUTS, int OUTPUTS>
  4. struct SequentialSwitch : Module {
  5. enum ParamIds {
  6. STEPS_PARAM,
  7. NUM_PARAMS
  8. };
  9. enum InputIds {
  10. CLOCK_INPUT,
  11. RESET_INPUT,
  12. ENUMS(IN_INPUTS, INPUTS),
  13. NUM_INPUTS
  14. };
  15. enum OutputIds {
  16. ENUMS(OUT_OUTPUTS, OUTPUTS),
  17. NUM_OUTPUTS
  18. };
  19. enum LightIds {
  20. ENUMS(CHANNEL_LIGHTS, 4 * 2),
  21. NUM_LIGHTS
  22. };
  23. dsp::SchmittTrigger clockTrigger;
  24. dsp::SchmittTrigger resetTrigger;
  25. int index = 0;
  26. dsp::ClockDivider lightDivider;
  27. dsp::SlewLimiter clickFilters[4];
  28. SequentialSwitch() {
  29. config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
  30. configSwitch(STEPS_PARAM, 0.0, 2.0, 2.0, "Steps", {"2", "3", "4"});
  31. configInput(CLOCK_INPUT, "Clock");
  32. configInput(RESET_INPUT, "Reset");
  33. if (INPUTS == 1) {
  34. configInput(IN_INPUTS + 0, "Main");
  35. }
  36. else {
  37. for (int i = 0; i < INPUTS; i++)
  38. configInput(IN_INPUTS + i, string::f("Channel %d", i + 1));
  39. }
  40. if (OUTPUTS == 1) {
  41. configOutput(OUT_OUTPUTS + 0, "Main");
  42. }
  43. else {
  44. for (int i = 0; i < OUTPUTS; i++)
  45. configOutput(OUT_OUTPUTS + i, string::f("Channel %d", i + 1));
  46. }
  47. for (int i = 0; i < 4; i++) {
  48. clickFilters[i].rise = 400.f; // Hz
  49. clickFilters[i].fall = 400.f; // Hz
  50. }
  51. lightDivider.setDivision(512);
  52. }
  53. void process(const ProcessArgs& args) override {
  54. // Determine current index
  55. if (clockTrigger.process(rescale(inputs[CLOCK_INPUT].getVoltage(), 0.1f, 2.f, 0.f, 1.f))) {
  56. index++;
  57. }
  58. if (resetTrigger.process(rescale(inputs[RESET_INPUT].getVoltage(), 0.1f, 2.f, 0.f, 1.f))) {
  59. index = 0;
  60. }
  61. int length = 2 + (int) std::round(params[STEPS_PARAM].getValue());
  62. if (index >= length)
  63. index = 0;
  64. // Use first input to get number of channels
  65. int channels = std::max(inputs[IN_INPUTS + 0].getChannels(), 1);
  66. if (INPUTS == 1) {
  67. // <1, 4>
  68. // Get input
  69. float* in = inputs[IN_INPUTS + 0].getVoltages();
  70. // Set output
  71. for (int i = 0; i < OUTPUTS; i++) {
  72. float gain = clickFilters[i].process(args.sampleTime, index == i);
  73. outputs[OUT_OUTPUTS + i].setChannels(channels);
  74. if (gain != 0.f) {
  75. for (int c = 0; c < channels; c++) {
  76. float out = in[c] * gain;
  77. outputs[OUT_OUTPUTS + i].setVoltage(out, c);
  78. }
  79. }
  80. else {
  81. outputs[OUT_OUTPUTS + i].clearVoltages();
  82. }
  83. }
  84. }
  85. else {
  86. // <4, 1>
  87. // Get input
  88. float out[16] = {};
  89. for (int i = 0; i < INPUTS; i++) {
  90. float gain = clickFilters[i].process(args.sampleTime, index == i);
  91. if (gain != 0.f) {
  92. for (int c = 0; c < channels; c++) {
  93. float in = inputs[IN_INPUTS + i].getVoltage(c);
  94. out[c] += in * gain;
  95. }
  96. }
  97. }
  98. // Set output
  99. outputs[OUT_OUTPUTS + 0].setChannels(channels);
  100. outputs[OUT_OUTPUTS + 0].writeVoltages(out);
  101. }
  102. // Set lights
  103. if (lightDivider.process()) {
  104. for (int i = 0; i < 4; i++) {
  105. lights[CHANNEL_LIGHTS + 2 * i + 0].setBrightness(index == i);
  106. lights[CHANNEL_LIGHTS + 2 * i + 1].setBrightness(i >= length);
  107. }
  108. }
  109. }
  110. void fromJson(json_t* rootJ) override {
  111. Module::fromJson(rootJ);
  112. // If version <2.0 we should transform STEPS_PARAM
  113. json_t* versionJ = json_object_get(rootJ, "version");
  114. if (versionJ) {
  115. std::string version = json_string_value(versionJ);
  116. if (string::startsWith(version, "0.") || string::startsWith(version, "1.")) {
  117. DEBUG("steps %f", params[STEPS_PARAM].getValue());
  118. params[STEPS_PARAM].setValue(2 - params[STEPS_PARAM].getValue());
  119. }
  120. }
  121. }
  122. };
  123. struct SequentialSwitch1Widget : ModuleWidget {
  124. typedef SequentialSwitch<1, 4> TSequentialSwitch;
  125. SequentialSwitch1Widget(TSequentialSwitch* module) {
  126. setModule(module);
  127. setPanel(createPanel(asset::plugin(pluginInstance, "res/SequentialSwitch1.svg")));
  128. addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, 0)));
  129. addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0)));
  130. addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  131. addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  132. addParam(createParamCentered<CKSSThreeHorizontal>(mm2px(Vec(7.555, 20.942)), module, TSequentialSwitch::STEPS_PARAM));
  133. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(7.555, 33.831)), module, TSequentialSwitch::CLOCK_INPUT));
  134. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(7.555, 50.126)), module, TSequentialSwitch::RESET_INPUT));
  135. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(7.555, 66.379)), module, TSequentialSwitch::IN_INPUTS + 0));
  136. addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(7.555, 82.607)), module, TSequentialSwitch::OUT_OUTPUTS + 0));
  137. addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(7.555, 92.767)), module, TSequentialSwitch::OUT_OUTPUTS + 1));
  138. addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(7.555, 102.927)), module, TSequentialSwitch::OUT_OUTPUTS + 2));
  139. addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(7.555, 113.087)), module, TSequentialSwitch::OUT_OUTPUTS + 3));
  140. addChild(createLightCentered<TinyLight<YellowRedLight<>>>(mm2px(Vec(11.28, 78.863)), module, TSequentialSwitch::CHANNEL_LIGHTS + 2 * 0));
  141. addChild(createLightCentered<TinyLight<YellowRedLight<>>>(mm2px(Vec(11.28, 89.023)), module, TSequentialSwitch::CHANNEL_LIGHTS + 2 * 1));
  142. addChild(createLightCentered<TinyLight<YellowRedLight<>>>(mm2px(Vec(11.28, 99.183)), module, TSequentialSwitch::CHANNEL_LIGHTS + 2 * 2));
  143. addChild(createLightCentered<TinyLight<YellowRedLight<>>>(mm2px(Vec(11.28, 109.343)), module, TSequentialSwitch::CHANNEL_LIGHTS + 2 * 3));
  144. }
  145. };
  146. Model* modelSequentialSwitch1 = createModel<SequentialSwitch<1, 4>, SequentialSwitch1Widget>("SequentialSwitch1");
  147. struct SequentialSwitch2Widget : ModuleWidget {
  148. typedef SequentialSwitch<4, 1> TSequentialSwitch;
  149. SequentialSwitch2Widget(TSequentialSwitch* module) {
  150. setModule(module);
  151. setPanel(createPanel(asset::plugin(pluginInstance, "res/SequentialSwitch2.svg")));
  152. addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, 0)));
  153. addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0)));
  154. addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  155. addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  156. addParam(createParamCentered<CKSSThreeHorizontal>(mm2px(Vec(7.8, 20.942)), module, TSequentialSwitch::STEPS_PARAM));
  157. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(7.8, 33.831)), module, TSequentialSwitch::CLOCK_INPUT));
  158. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(7.8, 50.126)), module, TSequentialSwitch::RESET_INPUT));
  159. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(7.8, 66.379)), module, TSequentialSwitch::IN_INPUTS + 0));
  160. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(7.8, 76.539)), module, TSequentialSwitch::IN_INPUTS + 1));
  161. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(7.8, 86.699)), module, TSequentialSwitch::IN_INPUTS + 2));
  162. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(7.8, 96.859)), module, TSequentialSwitch::IN_INPUTS + 3));
  163. addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(7.8, 113.115)), module, TSequentialSwitch::OUT_OUTPUTS + 0));
  164. addChild(createLightCentered<TinyLight<YellowRedLight<>>>(mm2px(Vec(11.526, 63.259)), module, TSequentialSwitch::CHANNEL_LIGHTS + 2 * 0));
  165. addChild(createLightCentered<TinyLight<YellowRedLight<>>>(mm2px(Vec(11.526, 72.795)), module, TSequentialSwitch::CHANNEL_LIGHTS + 2 * 1));
  166. addChild(createLightCentered<TinyLight<YellowRedLight<>>>(mm2px(Vec(11.526, 82.955)), module, TSequentialSwitch::CHANNEL_LIGHTS + 2 * 2));
  167. addChild(createLightCentered<TinyLight<YellowRedLight<>>>(mm2px(Vec(11.526, 93.115)), module, TSequentialSwitch::CHANNEL_LIGHTS + 2 * 3));
  168. }
  169. };
  170. Model* modelSequentialSwitch2 = createModel<SequentialSwitch<4, 1>, SequentialSwitch2Widget>("SequentialSwitch2");