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.

158 lines
4.9KB

  1. #include "Gratrix.hpp"
  2. namespace rack_plugin_Gratrix {
  3. //============================================================================================================
  4. struct VCA : MicroModule {
  5. enum ParamIds {
  6. LEVEL_PARAM,
  7. MIX_1_PARAM,
  8. MIX_2_PARAM,
  9. NUM_PARAMS
  10. };
  11. enum InputIds {
  12. EXP_INPUT, // N+1
  13. LIN_INPUT, // N+1
  14. IN_INPUT, // N+1
  15. NUM_INPUTS,
  16. OFF_INPUTS = EXP_INPUT
  17. };
  18. enum OutputIds {
  19. MIX_1_OUTPUT, // 1
  20. MIX_2_OUTPUT, // 1
  21. OUT_OUTPUT, // N
  22. NUM_OUTPUTS,
  23. OFF_OUTPUTS = OUT_OUTPUT
  24. };
  25. VCA() : MicroModule(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) {}
  26. void step();
  27. };
  28. //============================================================================================================
  29. void VCA::step() {
  30. float v = inputs[IN_INPUT].value * params[LEVEL_PARAM].value;
  31. if (inputs[LIN_INPUT].active)
  32. v *= clamp(inputs[LIN_INPUT].value / 10.0f, 0.0f, 1.0f);
  33. const float expBase = 50.0f;
  34. if (inputs[EXP_INPUT].active)
  35. v *= rescale(powf(expBase, clamp(inputs[EXP_INPUT].value / 10.0f, 0.0f, 1.0f)), 1.0f, expBase, 0.0f, 1.0f);
  36. outputs[OUT_OUTPUT].value = v;
  37. }
  38. //============================================================================================================
  39. struct VCABank : Module
  40. {
  41. std::array<VCA, GTX__N> inst;
  42. VCABank()
  43. :
  44. Module(VCA::NUM_PARAMS,
  45. (GTX__N+1) * (VCA::NUM_INPUTS - VCA::OFF_INPUTS ) + VCA::OFF_INPUTS,
  46. (GTX__N ) * (VCA::NUM_OUTPUTS - VCA::OFF_OUTPUTS) + VCA::OFF_OUTPUTS)
  47. {}
  48. static constexpr std::size_t imap(std::size_t port, std::size_t bank)
  49. {
  50. return port + bank * VCA::NUM_INPUTS;
  51. }
  52. static constexpr std::size_t omap(std::size_t port, std::size_t bank)
  53. {
  54. return (port < VCA::OFF_OUTPUTS) ? port : port + bank * (VCA::NUM_OUTPUTS - VCA::OFF_OUTPUTS);
  55. }
  56. void step() override
  57. {
  58. for (std::size_t i=0; i<GTX__N; ++i)
  59. {
  60. for (std::size_t p=0; p<VCA::NUM_PARAMS; ++p) inst[i].params[p] = params[p];
  61. for (std::size_t p=0; p<VCA::NUM_INPUTS; ++p) inst[i].inputs[p] = inputs[imap(p, i)].active ? inputs[imap(p, i)] : inputs[imap(p, GTX__N)];
  62. for (std::size_t p=0; p<VCA::NUM_OUTPUTS; ++p) inst[i].outputs[p] = outputs[omap(p, i)];
  63. inst[i].step();
  64. for (std::size_t p=0; p<VCA::NUM_OUTPUTS; ++p) outputs[omap(p, i)].value = inst[i].outputs[p].value;
  65. }
  66. float mix = 0.0f;
  67. for (std::size_t i=0; i<GTX__N; ++i)
  68. {
  69. mix += inst[i].outputs[VCA::OUT_OUTPUT].value;
  70. }
  71. outputs[VCA::MIX_1_OUTPUT].value = mix * params[VCA::MIX_1_PARAM].value;
  72. outputs[VCA::MIX_2_OUTPUT].value = mix * params[VCA::MIX_2_PARAM].value;
  73. }
  74. };
  75. //============================================================================================================
  76. //! \brief The widget.
  77. struct GtxWidget_VCA : ModuleWidget
  78. {
  79. GtxWidget_VCA(VCABank *module) : ModuleWidget(module)
  80. {
  81. GTX__WIDGET();
  82. box.size = Vec(12*15, 380);
  83. #if GTX__SAVE_SVG
  84. {
  85. PanelGen pg(assetPlugin(plugin, "build/res/VCA-F1.svg"), box.size, "VCA-F1");
  86. pg.nob_big(0, 0, "LEVEL");
  87. pg.nob_med(1, -0.28, "MIX OUT 1");
  88. pg.nob_med(1, +0.28, "MIX OUT 2");
  89. pg.bus_in (0, 1, "EXP"); pg.bus_in (1, 1, "LIN");
  90. pg.bus_in (0, 2, "IN"); pg.bus_out(1, 2, "OUT");
  91. }
  92. #endif
  93. setPanel(SVG::load(assetPlugin(plugin, "res/VCA-F1.svg")));
  94. addChild(Widget::create<ScrewSilver>(Vec(15, 0)));
  95. addChild(Widget::create<ScrewSilver>(Vec(box.size.x-30, 0)));
  96. addChild(Widget::create<ScrewSilver>(Vec(15, 365)));
  97. addChild(Widget::create<ScrewSilver>(Vec(box.size.x-30, 365)));
  98. addParam(createParamGTX<KnobFreeHug>(Vec(fx(0), fy(0)), module, VCA::LEVEL_PARAM, 0.0f, 1.0f, 0.5f));
  99. addParam(createParamGTX<KnobFreeMed>(Vec(fx(1-0.18), fy(-0.28)), module, VCA::MIX_1_PARAM, 0.0f, 1.0f, 0.5f));
  100. addParam(createParamGTX<KnobFreeMed>(Vec(fx(1-0.18), fy(+0.28)), module, VCA::MIX_2_PARAM, 0.0f, 1.0f, 0.5f));
  101. addOutput(createOutputGTX<PortOutMed>(Vec(fx(1+0.28), fy(-0.28)), module, VCA::MIX_1_OUTPUT));
  102. addOutput(createOutputGTX<PortOutMed>(Vec(fx(1+0.28), fy(+0.28)), module, VCA::MIX_2_OUTPUT));
  103. for (std::size_t i=0; i<GTX__N; ++i)
  104. {
  105. addInput(createInputGTX<PortInMed>(Vec(px(1, i), py(1, i)), module, VCABank::imap(VCA::LIN_INPUT, i)));
  106. addInput(createInputGTX<PortInMed>(Vec(px(0, i), py(1, i)), module, VCABank::imap(VCA::EXP_INPUT, i)));
  107. addInput(createInputGTX<PortInMed>(Vec(px(0, i), py(2, i)), module, VCABank::imap(VCA::IN_INPUT, i)));
  108. addOutput(createOutputGTX<PortOutMed>(Vec(px(1, i), py(2, i)), module, VCABank::omap(VCA::OUT_OUTPUT, i)));
  109. }
  110. addInput(createInputGTX<PortInMed>(Vec(gx(1), gy(1)), module, VCABank::imap(VCA::LIN_INPUT, GTX__N)));
  111. addInput(createInputGTX<PortInMed>(Vec(gx(0), gy(1)), module, VCABank::imap(VCA::EXP_INPUT, GTX__N)));
  112. addInput(createInputGTX<PortInMed>(Vec(gx(0), gy(2)), module, VCABank::imap(VCA::IN_INPUT, GTX__N)));
  113. }
  114. };
  115. } // namespace rack_plugin_Gratrix
  116. using namespace rack_plugin_Gratrix;
  117. RACK_PLUGIN_MODEL_INIT(Gratrix, VCA_F1) {
  118. Model *model = Model::create<VCABank, GtxWidget_VCA>("Gratrix", "VCA-F1", "VCA-F1", AMPLIFIER_TAG);
  119. return model;
  120. }