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.

137 lines
5.0KB

  1. #include "plugin.hpp"
  2. struct VCMixer : Module {
  3. enum ParamIds {
  4. MIX_LVL_PARAM,
  5. ENUMS(LVL_PARAM, 4),
  6. NUM_PARAMS
  7. };
  8. enum InputIds {
  9. MIX_CV_INPUT,
  10. ENUMS(CH_INPUT, 4),
  11. ENUMS(CV_INPUT, 4),
  12. NUM_INPUTS
  13. };
  14. enum OutputIds {
  15. MIX_OUTPUT,
  16. ENUMS(CH_OUTPUT, 4),
  17. NUM_OUTPUTS
  18. };
  19. VCMixer() {
  20. config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS);
  21. // x^1 scaling up to 6 dB
  22. configParam(MIX_LVL_PARAM, 0.0, 2.0, 1.0, "Master level", " dB", -10, 20);
  23. // x^2 scaling up to 6 dB
  24. configParam(LVL_PARAM + 0, 0.0, M_SQRT2, 1.0, "Ch 1 level", " dB", -10, 40);
  25. configParam(LVL_PARAM + 1, 0.0, M_SQRT2, 1.0, "Ch 2 level", " dB", -10, 40);
  26. configParam(LVL_PARAM + 2, 0.0, M_SQRT2, 1.0, "Ch 3 level", " dB", -10, 40);
  27. configParam(LVL_PARAM + 3, 0.0, M_SQRT2, 1.0, "Ch 4 level", " dB", -10, 40);
  28. }
  29. void process(const ProcessArgs &args) override {
  30. float mix[16] = {};
  31. int maxChannels = 1;
  32. // Channels
  33. for (int i = 0; i < 4; i++) {
  34. int channels = 1;
  35. float in[16] = {};
  36. if (inputs[CH_INPUT + i].isConnected()) {
  37. channels = inputs[CH_INPUT + i].getChannels();
  38. maxChannels = std::max(maxChannels, channels);
  39. // Get input
  40. inputs[CH_INPUT + i].readVoltages(in);
  41. // Apply fader gain
  42. float gain = std::pow(params[LVL_PARAM + i].getValue(), 2.f);
  43. for (int c = 0; c < channels; c++) {
  44. in[c] *= gain;
  45. }
  46. // Apply CV gain
  47. if (inputs[CV_INPUT + i].isConnected()) {
  48. for (int c = 0; c < channels; c++) {
  49. float cv = clamp(inputs[CV_INPUT + i].getPolyVoltage(c) / 10.f, 0.f, 1.f);
  50. in[c] *= cv;
  51. }
  52. }
  53. // Add to mix
  54. for (int c = 0; c < channels; c++) {
  55. mix[c] += in[c];
  56. }
  57. }
  58. // Set channel output
  59. if (outputs[CH_OUTPUT + i].isConnected()) {
  60. outputs[CH_OUTPUT + i].setChannels(channels);
  61. outputs[CH_OUTPUT + i].writeVoltages(in);
  62. }
  63. }
  64. // Mix output
  65. if (outputs[MIX_OUTPUT].isConnected()) {
  66. // Apply mix knob gain
  67. float gain = params[MIX_LVL_PARAM].getValue();
  68. for (int c = 0; c < maxChannels; c++) {
  69. mix[c] *= gain;
  70. }
  71. // Apply mix CV gain
  72. if (inputs[MIX_CV_INPUT].isConnected()) {
  73. for (int c = 0; c < maxChannels; c++) {
  74. float cv = clamp(inputs[MIX_CV_INPUT].getPolyVoltage(c) / 10.f, 0.f, 1.f);
  75. mix[c] *= cv;
  76. }
  77. }
  78. // Set mix output
  79. outputs[MIX_OUTPUT].setChannels(maxChannels);
  80. outputs[MIX_OUTPUT].writeVoltages(mix);
  81. }
  82. }
  83. };
  84. struct VCMixerWidget : ModuleWidget {
  85. VCMixerWidget(VCMixer *module) {
  86. setModule(module);
  87. setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/VCMixer.svg")));
  88. addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, 0)));
  89. addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0)));
  90. addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  91. addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  92. addParam(createParam<RoundLargeBlackKnob>(mm2px(Vec(19.049999, 21.161154)), module, VCMixer::MIX_LVL_PARAM));
  93. addParam(createParam<LEDSliderGreen>(mm2px(Vec(5.8993969, 44.33149).plus(Vec(-2, 0))), module, VCMixer::LVL_PARAM + 0));
  94. addParam(createParam<LEDSliderGreen>(mm2px(Vec(17.899343, 44.331486).plus(Vec(-2, 0))), module, VCMixer::LVL_PARAM + 1));
  95. addParam(createParam<LEDSliderGreen>(mm2px(Vec(29.899292, 44.331486).plus(Vec(-2, 0))), module, VCMixer::LVL_PARAM + 2));
  96. addParam(createParam<LEDSliderGreen>(mm2px(Vec(41.90065, 44.331486).plus(Vec(-2, 0))), module, VCMixer::LVL_PARAM + 3));
  97. // Use old interleaved order for backward compatibility with <0.6
  98. addInput(createInput<PJ301MPort>(mm2px(Vec(3.2935331, 23.404598)), module, VCMixer::MIX_CV_INPUT));
  99. addInput(createInput<PJ301MPort>(mm2px(Vec(3.2935331, 78.531639)), module, VCMixer::CH_INPUT + 0));
  100. addInput(createInput<PJ301MPort>(mm2px(Vec(3.2935331, 93.531586)), module, VCMixer::CV_INPUT + 0));
  101. addInput(createInput<PJ301MPort>(mm2px(Vec(15.29348, 78.531639)), module, VCMixer::CH_INPUT + 1));
  102. addInput(createInput<PJ301MPort>(mm2px(Vec(15.29348, 93.531586)), module, VCMixer::CV_INPUT + 1));
  103. addInput(createInput<PJ301MPort>(mm2px(Vec(27.293465, 78.531639)), module, VCMixer::CH_INPUT + 2));
  104. addInput(createInput<PJ301MPort>(mm2px(Vec(27.293465, 93.531586)), module, VCMixer::CV_INPUT + 2));
  105. addInput(createInput<PJ301MPort>(mm2px(Vec(39.293411, 78.531639)), module, VCMixer::CH_INPUT + 3));
  106. addInput(createInput<PJ301MPort>(mm2px(Vec(39.293411, 93.531586)), module, VCMixer::CV_INPUT + 3));
  107. addOutput(createOutput<PJ301MPort>(mm2px(Vec(39.293411, 23.4046)), module, VCMixer::MIX_OUTPUT));
  108. addOutput(createOutput<PJ301MPort>(mm2px(Vec(3.2935331, 108.53153)), module, VCMixer::CH_OUTPUT + 0));
  109. addOutput(createOutput<PJ301MPort>(mm2px(Vec(15.29348, 108.53153)), module, VCMixer::CH_OUTPUT + 1));
  110. addOutput(createOutput<PJ301MPort>(mm2px(Vec(27.293465, 108.53153)), module, VCMixer::CH_OUTPUT + 2));
  111. addOutput(createOutput<PJ301MPort>(mm2px(Vec(39.293411, 108.53153)), module, VCMixer::CH_OUTPUT + 3));
  112. }
  113. };
  114. Model *modelVCMixer = createModel<VCMixer, VCMixerWidget>("VCMixer");