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.

110 lines
3.3KB

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