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.

123 lines
3.7KB

  1. #include "plugin.hpp"
  2. #include "Common.hpp"
  3. using simd::float_4;
  4. struct SlewLimiter : Module {
  5. enum ParamIds {
  6. SHAPE_PARAM,
  7. RISE_PARAM,
  8. FALL_PARAM,
  9. NUM_PARAMS
  10. };
  11. enum InputIds {
  12. RISE_INPUT,
  13. FALL_INPUT,
  14. IN_INPUT,
  15. NUM_INPUTS
  16. };
  17. enum OutputIds {
  18. OUT_OUTPUT,
  19. NUM_OUTPUTS
  20. };
  21. float_4 out[4];
  22. SlewLimiter() {
  23. config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS);
  24. configParam(SHAPE_PARAM, 0.0, 1.0, 0.0, "Shape");
  25. configParam(RISE_PARAM, 0.0, 1.0, 0.0, "Rise time");
  26. configParam(FALL_PARAM, 0.0, 1.0, 0.0, "Fall time");
  27. memset(out, 0, sizeof(out));
  28. }
  29. void process(const ProcessArgs& args) override {
  30. float_4 in[4] = {0.f};
  31. float_4 riseCV[4] = {0.f};
  32. float_4 fallCV[4] = {0.f};
  33. // this is the number of active polyphony engines, defined by the input
  34. int numPolyphonyEngines = inputs[IN_INPUT].getChannels();
  35. // minimum and std::maximum slopes in volts per second
  36. const float slewMin = 0.1;
  37. const float slewMax = 10000.f;
  38. // Amount of extra slew per voltage difference
  39. const float shapeScale = 1 / 10.f;
  40. const float_4 shape = float_4(params[SHAPE_PARAM].getValue());
  41. const float_4 param_rise = float_4(params[RISE_PARAM].getValue() * 10.f);
  42. const float_4 param_fall = float_4(params[FALL_PARAM].getValue() * 10.f);
  43. outputs[OUT_OUTPUT].setChannels(numPolyphonyEngines);
  44. for (int c = 0; c < numPolyphonyEngines; c += 4) {
  45. in[c / 4] = inputs[IN_INPUT].getVoltageSimd<float_4>(c);
  46. if (inputs[RISE_INPUT].isConnected()) {
  47. if (inputs[RISE_INPUT].getChannels() == 1) {
  48. riseCV[c / 4] = float_4(inputs[RISE_INPUT].getVoltage());
  49. }
  50. else {
  51. riseCV[c / 4] = inputs[RISE_INPUT].getVoltageSimd<float_4>(c);
  52. }
  53. }
  54. if (inputs[FALL_INPUT].isConnected()) {
  55. if (inputs[FALL_INPUT].getChannels() == 1) {
  56. fallCV[c / 4] = float_4(inputs[FALL_INPUT].getVoltage());
  57. }
  58. else {
  59. fallCV[c / 4] = inputs[FALL_INPUT].getVoltageSimd<float_4>(c);
  60. }
  61. }
  62. riseCV[c / 4] += param_rise;
  63. fallCV[c / 4] += param_fall;
  64. float_4 delta = in[c / 4] - out[c / 4];
  65. float_4 delta_gt_0 = delta > float_4::zero();
  66. float_4 delta_lt_0 = delta < float_4::zero();
  67. float_4 rateCV;
  68. rateCV = ifelse(delta_gt_0, riseCV[c / 4], float_4::zero());
  69. rateCV = ifelse(delta_lt_0, fallCV[c / 4], rateCV) * 0.1f;
  70. float_4 pm_one = simd::sgn(delta);
  71. float_4 slew = slewMax * simd::pow(float_4(slewMin / slewMax), rateCV);
  72. out[c / 4] += slew * simd::crossfade(pm_one, shapeScale * delta, shape) * args.sampleTime;
  73. out[c / 4] = ifelse(delta_gt_0 & (out[c / 4] > in[c / 4]), in[c / 4], out[c / 4]);
  74. out[c / 4] = ifelse(delta_lt_0 & (out[c / 4] < in[c / 4]), in[c / 4], out[c / 4]);
  75. out[c / 4].store(outputs[OUT_OUTPUT].getVoltages(c));
  76. }
  77. }
  78. };
  79. struct SlewLimiterWidget : ModuleWidget {
  80. SlewLimiterWidget(SlewLimiter* module) {
  81. setModule(module);
  82. setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/SlewLimiter.svg")));
  83. addChild(createWidget<Knurlie>(Vec(15, 0)));
  84. addChild(createWidget<Knurlie>(Vec(15, 365)));
  85. addParam(createParam<Davies1900hWhiteKnob>(Vec(27, 39), module, ::SlewLimiter::SHAPE_PARAM));
  86. addParam(createParam<BefacoSlidePot>(Vec(15, 102), module, ::SlewLimiter::RISE_PARAM));
  87. addParam(createParam<BefacoSlidePot>(Vec(60, 102), module, ::SlewLimiter::FALL_PARAM));
  88. addInput(createInput<BefacoInputPort>(Vec(10, 273), module, ::SlewLimiter::RISE_INPUT));
  89. addInput(createInput<BefacoInputPort>(Vec(55, 273), module, ::SlewLimiter::FALL_INPUT));
  90. addInput(createInput<BefacoInputPort>(Vec(10, 323), module, ::SlewLimiter::IN_INPUT));
  91. addOutput(createOutput<BefacoOutputPort>(Vec(55, 323), module, ::SlewLimiter::OUT_OUTPUT));
  92. }
  93. };
  94. Model* modelSlewLimiter = createModel<::SlewLimiter, SlewLimiterWidget>("SlewLimiter");