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.

132 lines
3.9KB

  1. #include "plugin.hpp"
  2. using simd::float_4;
  3. struct Fade : Module {
  4. enum ParamId {
  5. CROSSFADE_PARAM,
  6. CROSSFADE_CV_PARAM,
  7. PARAMS_LEN
  8. };
  9. enum InputId {
  10. CROSSFADE_INPUT,
  11. IN1_INPUT,
  12. IN2_INPUT,
  13. INPUTS_LEN
  14. };
  15. enum OutputId {
  16. OUT1_OUTPUT,
  17. OUT2_OUTPUT,
  18. OUTPUTS_LEN
  19. };
  20. enum LightId {
  21. LIGHTS_LEN
  22. };
  23. /**
  24. 0 linear
  25. 1 -3dB
  26. */
  27. int panLaw = 0;
  28. Fade() {
  29. config(PARAMS_LEN, INPUTS_LEN, OUTPUTS_LEN, LIGHTS_LEN);
  30. configParam(CROSSFADE_PARAM, 0.f, 1.f, 0.5f, "Crossfade", "%", 0, 100);
  31. configParam(CROSSFADE_CV_PARAM, -1.f, 1.f, 0.f, "Crossfade CV", "%", 0, 100);
  32. configInput(CROSSFADE_INPUT, "Crossfade");
  33. configInput(IN1_INPUT, "Ch 1");
  34. configInput(IN2_INPUT, "Ch 2");
  35. configOutput(OUT1_OUTPUT, "Ch 1");
  36. configOutput(OUT2_OUTPUT, "Ch 2");
  37. configBypass(IN1_INPUT, OUT1_OUTPUT);
  38. configBypass(IN2_INPUT, OUT2_OUTPUT);
  39. }
  40. void onReset(const ResetEvent& e) override {
  41. Module::onReset(e);
  42. panLaw = 0;
  43. }
  44. void process(const ProcessArgs& args) override {
  45. if (!outputs[OUT1_OUTPUT].isConnected() && !outputs[OUT2_OUTPUT].isConnected())
  46. return;
  47. int channels = std::max({1, inputs[IN1_INPUT].getChannels(), inputs[IN2_INPUT].getChannels()});
  48. for (int c = 0; c < channels; c += 4) {
  49. // Get crossfade amount
  50. float_4 crossfade = params[CROSSFADE_PARAM].getValue();
  51. crossfade += inputs[CROSSFADE_INPUT].getPolyVoltageSimd<float_4>(c) / 10.f * params[CROSSFADE_CV_PARAM].getValue();
  52. crossfade = clamp(crossfade, 0.f, 1.f);
  53. float_4 crossfade1 = 1.f - crossfade;
  54. // Apply sqrt pan law
  55. if (panLaw == 1) {
  56. crossfade = (simd::sqrt(crossfade));
  57. crossfade1 = simd::sqrt(crossfade1);
  58. }
  59. // Get inputs
  60. float_4 in1 = inputs[IN1_INPUT].getPolyVoltageSimd<float_4>(c);
  61. float_4 in2 = inputs[IN2_INPUT].getPolyVoltageSimd<float_4>(c);
  62. // Calculate outputs
  63. float_4 out1 = crossfade1 * in1 + crossfade * in2;
  64. float_4 out2 = crossfade * in1 + crossfade1 * in2;
  65. outputs[OUT1_OUTPUT].setVoltageSimd(out1, c);
  66. outputs[OUT2_OUTPUT].setVoltageSimd(out2, c);
  67. }
  68. outputs[OUT1_OUTPUT].setChannels(channels);
  69. outputs[OUT2_OUTPUT].setChannels(channels);
  70. }
  71. json_t* dataToJson() override {
  72. json_t* rootJ = json_object();
  73. json_object_set_new(rootJ, "panLaw", json_integer(panLaw));
  74. return rootJ;
  75. }
  76. void dataFromJson(json_t* rootJ) override {
  77. json_t* panLawJ = json_object_get(rootJ, "panLaw");
  78. if (panLawJ)
  79. panLaw = json_integer_value(panLawJ);
  80. }
  81. };
  82. struct FadeWidget : ModuleWidget {
  83. FadeWidget(Fade* module) {
  84. setModule(module);
  85. setPanel(createPanel(asset::plugin(pluginInstance, "res/Fade.svg"), asset::plugin(pluginInstance, "res/Fade-dark.svg")));
  86. addChild(createWidget<ThemedScrew>(Vec(RACK_GRID_WIDTH, 0)));
  87. addChild(createWidget<ThemedScrew>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0)));
  88. addChild(createWidget<ThemedScrew>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  89. addChild(createWidget<ThemedScrew>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  90. addParam(createParamCentered<RoundBlackKnob>(mm2px(Vec(7.62, 24.723)), module, Fade::CROSSFADE_PARAM));
  91. addParam(createParamCentered<Trimpot>(mm2px(Vec(7.62, 37.064)), module, Fade::CROSSFADE_CV_PARAM));
  92. addInput(createInputCentered<ThemedPJ301MPort>(mm2px(Vec(7.62, 52.987)), module, Fade::CROSSFADE_INPUT));
  93. addInput(createInputCentered<ThemedPJ301MPort>(mm2px(Vec(7.62, 67.53)), module, Fade::IN1_INPUT));
  94. addInput(createInputCentered<ThemedPJ301MPort>(mm2px(Vec(7.62, 82.732)), module, Fade::IN2_INPUT));
  95. addOutput(createOutputCentered<ThemedPJ301MPort>(mm2px(Vec(7.62, 97.923)), module, Fade::OUT1_OUTPUT));
  96. addOutput(createOutputCentered<ThemedPJ301MPort>(mm2px(Vec(7.62, 113.115)), module, Fade::OUT2_OUTPUT));
  97. }
  98. void appendContextMenu(Menu* menu) override {
  99. Fade* module = getModule<Fade>();
  100. menu->addChild(new MenuSeparator);
  101. menu->addChild(createIndexPtrSubmenuItem("Pan law", {"-6 dB (linear)", "-3 dB"}, &module->panLaw));
  102. }
  103. };
  104. Model* modelFade = createModel<Fade, FadeWidget>("Fade");