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.

139 lines
4.3KB

  1. #include "plugin.hpp"
  2. // Deprecated. Use VCA-1 instead.
  3. struct VCA : Module {
  4. enum ParamIds {
  5. LEVEL1_PARAM,
  6. LEVEL2_PARAM,
  7. NUM_PARAMS
  8. };
  9. enum InputIds {
  10. EXP1_INPUT,
  11. LIN1_INPUT,
  12. IN1_INPUT,
  13. EXP2_INPUT,
  14. LIN2_INPUT,
  15. IN2_INPUT,
  16. NUM_INPUTS
  17. };
  18. enum OutputIds {
  19. OUT1_OUTPUT,
  20. OUT2_OUTPUT,
  21. NUM_OUTPUTS
  22. };
  23. VCA() {
  24. config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS);
  25. configParam(LEVEL1_PARAM, 0.0, 1.0, 1.0, "Channel 1 level", "%", 0, 100);
  26. configParam(LEVEL2_PARAM, 0.0, 1.0, 1.0, "Channel 2 level", "%", 0, 100);
  27. configInput(EXP1_INPUT, "Channel 1 exponential CV");
  28. configInput(EXP2_INPUT, "Channel 2 exponential CV");
  29. configInput(LIN1_INPUT, "Channel 1 linear CV");
  30. configInput(LIN2_INPUT, "Channel 2 linear CV");
  31. configInput(IN1_INPUT, "Channel 1");
  32. configInput(IN2_INPUT, "Channel 2");
  33. configOutput(OUT1_OUTPUT, "Channel 1");
  34. configOutput(OUT2_OUTPUT, "Channel 2");
  35. configBypass(IN1_INPUT, OUT1_OUTPUT);
  36. configBypass(IN2_INPUT, OUT2_OUTPUT);
  37. }
  38. void processChannel(Input& in, Param& level, Input& lin, Input& exp, Output& out) {
  39. // Get input
  40. int channels = std::max(in.getChannels(), 1);
  41. simd::float_4 v[4];
  42. for (int c = 0; c < channels; c += 4) {
  43. v[c / 4] = simd::float_4::load(in.getVoltages(c));
  44. }
  45. // Apply knob gain
  46. float gain = level.getValue();
  47. for (int c = 0; c < channels; c += 4) {
  48. v[c / 4] *= gain;
  49. }
  50. // Apply linear CV gain
  51. if (lin.isConnected()) {
  52. if (lin.isPolyphonic()) {
  53. for (int c = 0; c < channels; c += 4) {
  54. simd::float_4 cv = simd::float_4::load(lin.getVoltages(c)) / 10.f;
  55. cv = clamp(cv, 0.f, 1.f);
  56. v[c / 4] *= cv;
  57. }
  58. }
  59. else {
  60. float cv = lin.getVoltage() / 10.f;
  61. cv = clamp(cv, 0.f, 1.f);
  62. for (int c = 0; c < channels; c += 4) {
  63. v[c / 4] *= cv;
  64. }
  65. }
  66. }
  67. // Apply exponential CV gain
  68. const float expBase = 50.f;
  69. if (exp.isConnected()) {
  70. if (exp.isPolyphonic()) {
  71. for (int c = 0; c < channels; c += 4) {
  72. simd::float_4 cv = simd::float_4::load(exp.getVoltages(c)) / 10.f;
  73. cv = clamp(cv, 0.f, 1.f);
  74. cv = rescale(pow(expBase, cv), 1.f, expBase, 0.f, 1.f);
  75. v[c / 4] *= cv;
  76. }
  77. }
  78. else {
  79. float cv = exp.getVoltage() / 10.f;
  80. cv = clamp(cv, 0.f, 1.f);
  81. cv = rescale(std::pow(expBase, cv), 1.f, expBase, 0.f, 1.f);
  82. for (int c = 0; c < channels; c += 4) {
  83. v[c / 4] *= cv;
  84. }
  85. }
  86. }
  87. // Set output
  88. out.setChannels(channels);
  89. for (int c = 0; c < channels; c += 4) {
  90. v[c / 4].store(out.getVoltages(c));
  91. }
  92. }
  93. void process(const ProcessArgs& args) override {
  94. processChannel(inputs[IN1_INPUT], params[LEVEL1_PARAM], inputs[LIN1_INPUT], inputs[EXP1_INPUT], outputs[OUT1_OUTPUT]);
  95. processChannel(inputs[IN2_INPUT], params[LEVEL2_PARAM], inputs[LIN2_INPUT], inputs[EXP2_INPUT], outputs[OUT2_OUTPUT]);
  96. }
  97. };
  98. struct VCAWidget : ModuleWidget {
  99. VCAWidget(VCA* module) {
  100. setModule(module);
  101. setPanel(createPanel(asset::plugin(pluginInstance, "res/VCA.svg")));
  102. addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, 0)));
  103. addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0)));
  104. addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  105. addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  106. addParam(createParam<RoundLargeBlackKnob>(mm2px(Vec(6.35, 19.11753)), module, VCA::LEVEL1_PARAM));
  107. addParam(createParam<RoundLargeBlackKnob>(mm2px(Vec(6.35, 74.80544)), module, VCA::LEVEL2_PARAM));
  108. addInput(createInput<PJ301MPort>(mm2px(Vec(2.5907, 38.19371)), module, VCA::EXP1_INPUT));
  109. addInput(createInput<PJ301MPort>(mm2px(Vec(14.59752, 38.19371)), module, VCA::LIN1_INPUT));
  110. addInput(createInput<PJ301MPort>(mm2px(Vec(2.5907, 52.80642)), module, VCA::IN1_INPUT));
  111. addInput(createInput<PJ301MPort>(mm2px(Vec(2.5907, 93.53435)), module, VCA::EXP2_INPUT));
  112. addInput(createInput<PJ301MPort>(mm2px(Vec(14.59752, 93.53435)), module, VCA::LIN2_INPUT));
  113. addInput(createInput<PJ301MPort>(mm2px(Vec(2.5907, 108.14706)), module, VCA::IN2_INPUT));
  114. addOutput(createOutput<PJ301MPort>(mm2px(Vec(14.59752, 52.80642)), module, VCA::OUT1_OUTPUT));
  115. addOutput(createOutput<PJ301MPort>(mm2px(Vec(14.59752, 108.14706)), module, VCA::OUT2_OUTPUT));
  116. }
  117. };
  118. Model* modelVCA = createModel<VCA, VCAWidget>("VCA");