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.

182 lines
6.4KB

  1. #include "plugin.hpp"
  2. struct VCMixer : Module {
  3. enum ParamIds {
  4. MIX_LVL_PARAM,
  5. ENUMS(LVL_PARAMS, 4),
  6. NUM_PARAMS
  7. };
  8. enum InputIds {
  9. MIX_CV_INPUT,
  10. ENUMS(CH_INPUTS, 4),
  11. ENUMS(CV_INPUTS, 4),
  12. NUM_INPUTS
  13. };
  14. enum OutputIds {
  15. MIX_OUTPUT,
  16. ENUMS(CH_OUTPUTS, 4),
  17. NUM_OUTPUTS
  18. };
  19. enum LightIds {
  20. ENUMS(LVL_LIGHTS, 4),
  21. NUM_LIGHTS
  22. };
  23. dsp::VuMeter2 chMeters[4];
  24. dsp::ClockDivider lightDivider;
  25. VCMixer() {
  26. config(0, 0, 0, 0);
  27. config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
  28. // x^1 scaling up to 6 dB
  29. configParam(MIX_LVL_PARAM, 0.0, 2.0, 1.0, "Mix level", " dB", -10, 20);
  30. // x^2 scaling up to 6 dB
  31. configParam(LVL_PARAMS + 0, 0.0, M_SQRT2, 1.0, "Channel 1 level", " dB", -10, 40);
  32. configParam(LVL_PARAMS + 1, 0.0, M_SQRT2, 1.0, "Channel 2 level", " dB", -10, 40);
  33. configParam(LVL_PARAMS + 2, 0.0, M_SQRT2, 1.0, "Channel 3 level", " dB", -10, 40);
  34. configParam(LVL_PARAMS + 3, 0.0, M_SQRT2, 1.0, "Channel 4 level", " dB", -10, 40);
  35. configInput(MIX_CV_INPUT, "Mix CV");
  36. for (int i = 0; i < 4; i++)
  37. configInput(CH_INPUTS + i, string::f("Channel %d", i + 1));
  38. for (int i = 0; i < 4; i++)
  39. configInput(CV_INPUTS + i, string::f("Channel %d CV", i + 1));
  40. configOutput(MIX_OUTPUT, "Mix");
  41. for (int i = 0; i < 4; i++)
  42. configOutput(CH_OUTPUTS + i, string::f("Channel %d", i + 1));
  43. lightDivider.setDivision(512);
  44. }
  45. void process(const ProcessArgs& args) override {
  46. // Get number of poly channels for mix output
  47. int mixChannels = 1;
  48. for (int i = 0; i < 4; i++) {
  49. mixChannels = std::max(mixChannels, inputs[CH_INPUTS + i].getChannels());
  50. }
  51. float mix[16] = {};
  52. // Channel strips
  53. for (int i = 0; i < 4; i++) {
  54. int channels = 1;
  55. float in[16] = {};
  56. float sum = 0.f;
  57. if (inputs[CH_INPUTS + i].isConnected()) {
  58. channels = inputs[CH_INPUTS + i].getChannels();
  59. // Get input
  60. inputs[CH_INPUTS + i].readVoltages(in);
  61. // Apply fader gain
  62. float gain = std::pow(params[LVL_PARAMS + i].getValue(), 2.f);
  63. for (int c = 0; c < channels; c++) {
  64. in[c] *= gain;
  65. }
  66. // Apply CV gain
  67. if (inputs[CV_INPUTS + i].isConnected()) {
  68. for (int c = 0; c < channels; c++) {
  69. float cv = clamp(inputs[CV_INPUTS + i].getPolyVoltage(c) / 10.f, 0.f, 1.f);
  70. in[c] *= cv;
  71. }
  72. }
  73. // Add to mix
  74. if (channels == 1) {
  75. // Copy the mono signal to all mix channels
  76. for (int c = 0; c < mixChannels; c++) {
  77. mix[c] += in[0];
  78. }
  79. }
  80. else {
  81. // Copy each poly channel to the corresponding mix channel
  82. for (int c = 0; c < channels; c++) {
  83. mix[c] += in[c];
  84. }
  85. }
  86. // Sum channel for VU meter
  87. for (int c = 0; c < channels; c++) {
  88. sum += in[c];
  89. }
  90. }
  91. chMeters[i].process(args.sampleTime, sum / 5.f);
  92. // Set channel output
  93. if (outputs[CH_OUTPUTS + i].isConnected()) {
  94. outputs[CH_OUTPUTS + i].setChannels(channels);
  95. outputs[CH_OUTPUTS + i].writeVoltages(in);
  96. }
  97. }
  98. // Mix output
  99. if (outputs[MIX_OUTPUT].isConnected()) {
  100. // Apply mix knob gain
  101. float gain = params[MIX_LVL_PARAM].getValue();
  102. for (int c = 0; c < mixChannels; c++) {
  103. mix[c] *= gain;
  104. }
  105. // Apply mix CV gain
  106. if (inputs[MIX_CV_INPUT].isConnected()) {
  107. for (int c = 0; c < mixChannels; c++) {
  108. float cv = clamp(inputs[MIX_CV_INPUT].getPolyVoltage(c) / 10.f, 0.f, 1.f);
  109. mix[c] *= cv;
  110. }
  111. }
  112. // Set mix output
  113. outputs[MIX_OUTPUT].setChannels(mixChannels);
  114. outputs[MIX_OUTPUT].writeVoltages(mix);
  115. }
  116. // VU lights
  117. if (lightDivider.process()) {
  118. for (int i = 0; i < 4; i++) {
  119. float b = chMeters[i].getBrightness(-24.f, 0.f);
  120. lights[LVL_LIGHTS + i].setBrightness(b);
  121. }
  122. }
  123. }
  124. };
  125. struct VCMixerWidget : ModuleWidget {
  126. VCMixerWidget(VCMixer* module) {
  127. setModule(module);
  128. setPanel(createPanel(asset::plugin(pluginInstance, "res/VCMixer.svg")));
  129. addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, 0)));
  130. addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0)));
  131. addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  132. addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  133. addParam(createLightParamCentered<VCVLightSlider<YellowLight>>(mm2px(Vec(6.604, 33.605)), module, VCMixer::LVL_PARAMS + 0, VCMixer::LVL_LIGHTS + 0));
  134. addParam(createLightParamCentered<VCVLightSlider<YellowLight>>(mm2px(Vec(17.441, 33.605)), module, VCMixer::LVL_PARAMS + 1, VCMixer::LVL_LIGHTS + 1));
  135. addParam(createLightParamCentered<VCVLightSlider<YellowLight>>(mm2px(Vec(28.279, 33.605)), module, VCMixer::LVL_PARAMS + 2, VCMixer::LVL_LIGHTS + 2));
  136. addParam(createLightParamCentered<VCVLightSlider<YellowLight>>(mm2px(Vec(39.116, 33.605)), module, VCMixer::LVL_PARAMS + 3, VCMixer::LVL_LIGHTS + 3));
  137. addParam(createParamCentered<RoundBlackKnob>(mm2px(Vec(22.776, 64.366)), module, VCMixer::MIX_LVL_PARAM));
  138. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(6.604, 64.347)), module, VCMixer::MIX_CV_INPUT));
  139. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(6.604, 80.549)), module, VCMixer::CV_INPUTS + 0));
  140. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(17.441, 80.549)), module, VCMixer::CV_INPUTS + 1));
  141. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(28.279, 80.549)), module, VCMixer::CV_INPUTS + 2));
  142. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(39.116, 80.549)), module, VCMixer::CV_INPUTS + 3));
  143. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(6.604, 96.859)), module, VCMixer::CH_INPUTS + 0));
  144. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(17.441, 96.859)), module, VCMixer::CH_INPUTS + 1));
  145. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(28.279, 96.859)), module, VCMixer::CH_INPUTS + 2));
  146. addInput(createInputCentered<PJ301MPort>(mm2px(Vec(39.116, 96.821)), module, VCMixer::CH_INPUTS + 3));
  147. addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(39.116, 64.347)), module, VCMixer::MIX_OUTPUT));
  148. addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(6.604, 113.115)), module, VCMixer::CH_OUTPUTS + 0));
  149. addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(17.441, 113.115)), module, VCMixer::CH_OUTPUTS + 1));
  150. addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(28.279, 113.115)), module, VCMixer::CH_OUTPUTS + 2));
  151. addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(39.116, 113.115)), module, VCMixer::CH_OUTPUTS + 3));
  152. }
  153. };
  154. Model* modelVCMixer = createModel<VCMixer, VCMixerWidget>("VCMixer");