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.

151 lines
5.0KB

  1. #include "plugin.hpp"
  2. using simd::float_4;
  3. struct ABC : Module {
  4. enum ParamIds {
  5. B1_LEVEL_PARAM,
  6. C1_LEVEL_PARAM,
  7. B2_LEVEL_PARAM,
  8. C2_LEVEL_PARAM,
  9. NUM_PARAMS
  10. };
  11. enum InputIds {
  12. A1_INPUT,
  13. B1_INPUT,
  14. C1_INPUT,
  15. A2_INPUT,
  16. B2_INPUT,
  17. C2_INPUT,
  18. NUM_INPUTS
  19. };
  20. enum OutputIds {
  21. OUT1_OUTPUT,
  22. OUT2_OUTPUT,
  23. NUM_OUTPUTS
  24. };
  25. enum LightIds {
  26. ENUMS(OUT1_LIGHT, 3),
  27. ENUMS(OUT2_LIGHT, 3),
  28. NUM_LIGHTS
  29. };
  30. ABC() {
  31. config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
  32. configParam(B1_LEVEL_PARAM, -1.0, 1.0, 0.0, "B1 Level");
  33. configParam(C1_LEVEL_PARAM, -1.0, 1.0, 0.0, "C1 Level");
  34. configParam(B2_LEVEL_PARAM, -1.0, 1.0, 0.0, "B2 Level");
  35. configParam(C2_LEVEL_PARAM, -1.0, 1.0, 0.0, "C2 Level");
  36. configInput(A1_INPUT, "A1");
  37. configInput(B1_INPUT, "B1");
  38. configInput(C1_INPUT, "C1");
  39. configInput(A2_INPUT, "A2");
  40. configInput(B2_INPUT, "B2");
  41. configInput(C2_INPUT, "C2");
  42. getInputInfo(B1_INPUT)->description = "Normalled to 5V";
  43. getInputInfo(C1_INPUT)->description = "Normalled to 10V";
  44. getInputInfo(B2_INPUT)->description = "Normalled to 5V";
  45. getInputInfo(C2_INPUT)->description = "Normalled to 10V";
  46. configOutput(OUT1_OUTPUT, "Out 1");
  47. configOutput(OUT2_OUTPUT, "Out 2");
  48. getOutputInfo(OUT1_OUTPUT)->description = "Normalled to Out 2";
  49. }
  50. void processSection(const ProcessArgs& args, int& lastChannels, float_4* lastOut, ParamIds levelB, ParamIds levelC, InputIds inputA, InputIds inputB, InputIds inputC, OutputIds output, LightIds outLight) {
  51. // Compute polyphony channels
  52. int channels = std::max(lastChannels, inputs[inputA].getChannels());
  53. channels = std::max(channels, inputs[inputB].getChannels());
  54. channels = std::max(channels, inputs[inputC].getChannels());
  55. lastChannels = channels;
  56. // Get param levels
  57. float gainB = 2.f * exponentialBipolar80Pade_5_4(params[levelB].getValue());
  58. float gainC = exponentialBipolar80Pade_5_4(params[levelC].getValue());
  59. for (int c = 0; c < channels; c += 4) {
  60. // Get inputs
  61. float_4 inA = inputs[inputA].getPolyVoltageSimd<float_4>(c);
  62. float_4 inB = inputs[inputB].getNormalPolyVoltageSimd<float_4>(5.f, c) * gainB;
  63. float_4 inC = inputs[inputC].getNormalPolyVoltageSimd<float_4>(10.f, c) * gainC;
  64. // Compute and set output
  65. float_4 out = inA * inB / 5.f + inC;
  66. lastOut[c / 4] += out;
  67. if (outputs[output].isConnected()) {
  68. outputs[output].setChannels(channels);
  69. outputs[output].setVoltageSimd(clip(lastOut[c / 4]), c);
  70. }
  71. }
  72. // Set lights
  73. if (channels == 1) {
  74. float b = lastOut[0][0];
  75. lights[outLight + 0].setSmoothBrightness(b / 5.f, args.sampleTime);
  76. lights[outLight + 1].setSmoothBrightness(-b / 5.f, args.sampleTime);
  77. lights[outLight + 2].setBrightness(0.f);
  78. }
  79. else {
  80. // RMS of output
  81. float b = 0.f;
  82. for (int c = 0; c < channels; c++)
  83. b += std::pow(lastOut[c / 4][c % 4], 2);
  84. b = std::sqrt(b / channels);
  85. lights[outLight + 0].setBrightness(0.0f);
  86. lights[outLight + 1].setBrightness(0.0f);
  87. lights[outLight + 2].setBrightness(b / 5.f);
  88. }
  89. }
  90. void process(const ProcessArgs& args) override {
  91. int channels = 1;
  92. float_4 out[4] = {};
  93. // Section A
  94. processSection(args, channels, out, B1_LEVEL_PARAM, C1_LEVEL_PARAM, A1_INPUT, B1_INPUT, C1_INPUT, OUT1_OUTPUT, OUT1_LIGHT);
  95. // Break summing if output A is patched
  96. if (outputs[OUT1_OUTPUT].isConnected()) {
  97. channels = 1;
  98. std::memset(out, 0, sizeof(out));
  99. }
  100. // Section B
  101. processSection(args, channels, out, B2_LEVEL_PARAM, C2_LEVEL_PARAM, A2_INPUT, B2_INPUT, C2_INPUT, OUT2_OUTPUT, OUT2_LIGHT);
  102. }
  103. };
  104. struct ABCWidget : ModuleWidget {
  105. ABCWidget(ABC* module) {
  106. setModule(module);
  107. setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/panels/ABC.svg")));
  108. addChild(createWidget<Knurlie>(Vec(15, 0)));
  109. addChild(createWidget<Knurlie>(Vec(15, 365)));
  110. addParam(createParam<Davies1900hRedKnob>(Vec(45, 37), module, ABC::B1_LEVEL_PARAM));
  111. addParam(createParam<Davies1900hWhiteKnob>(Vec(45, 107), module, ABC::C1_LEVEL_PARAM));
  112. addParam(createParam<Davies1900hRedKnob>(Vec(45, 204), module, ABC::B2_LEVEL_PARAM));
  113. addParam(createParam<Davies1900hWhiteKnob>(Vec(45, 274), module, ABC::C2_LEVEL_PARAM));
  114. addInput(createInput<BefacoInputPort>(Vec(7, 28), module, ABC::A1_INPUT));
  115. addInput(createInput<BefacoInputPort>(Vec(7, 70), module, ABC::B1_INPUT));
  116. addInput(createInput<BefacoInputPort>(Vec(7, 112), module, ABC::C1_INPUT));
  117. addOutput(createOutput<BefacoOutputPort>(Vec(7, 154), module, ABC::OUT1_OUTPUT));
  118. addInput(createInput<BefacoInputPort>(Vec(7, 195), module, ABC::A2_INPUT));
  119. addInput(createInput<BefacoInputPort>(Vec(7, 237), module, ABC::B2_INPUT));
  120. addInput(createInput<BefacoInputPort>(Vec(7, 279), module, ABC::C2_INPUT));
  121. addOutput(createOutput<BefacoOutputPort>(Vec(7, 321), module, ABC::OUT2_OUTPUT));
  122. addChild(createLight<MediumLight<RedGreenBlueLight>>(Vec(37, 162), module, ABC::OUT1_LIGHT));
  123. addChild(createLight<MediumLight<RedGreenBlueLight>>(Vec(37, 329), module, ABC::OUT2_LIGHT));
  124. }
  125. };
  126. Model* modelABC = createModel<ABC, ABCWidget>("ABC");