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.

250 lines
8.3KB

  1. //**************************************************************************************
  2. //2 channel mixer module for VCV Rack by Alfredo Santamaria - AS - https://github.com/AScustomWorks/AS
  3. //
  4. //Based on DrumsMixer VCV Rack by Autodafe http://www.autodafe.net
  5. //Based on code taken from the Fundamentals plugins by Andrew Belt http://www.vcvrack.com
  6. //**************************************************************************************
  7. #include "AS.hpp"
  8. #include "dsp/digital.hpp"
  9. struct Mixer2ch : Module {
  10. enum ParamIds {
  11. MIX_PARAM,
  12. CH1_PARAM,
  13. CH2_PARAM,
  14. CH1_PAN_PARAM,
  15. CH2_PAN_PARAM,
  16. CH1MUTE,
  17. CH2MUTE,
  18. MASTER_MUTE,
  19. NUM_PARAMS
  20. };
  21. enum InputIds {
  22. MIX_CV_INPUT,
  23. CH1_INPUT,
  24. CH1_CV_INPUT,
  25. CH1_CV_PAN_INPUT,
  26. CH2_INPUT,
  27. CH2_CV_INPUT,
  28. CH2_CV_PAN_INPUT,
  29. LINK_L,
  30. LINK_R,
  31. NUM_INPUTS
  32. };
  33. enum OutputIds {
  34. MIX_OUTPUTL,
  35. MIX_OUTPUTR,
  36. CH1_OUTPUT,
  37. CH2_OUTPUT,
  38. NUM_OUTPUTS
  39. };
  40. enum LightIds {
  41. MUTE_LIGHT1,
  42. MUTE_LIGHT2,
  43. MUTE_LIGHT_MASTER,
  44. NUM_LIGHTS
  45. };
  46. Mixer2ch() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {
  47. reset();
  48. }
  49. void step() override;
  50. SchmittTrigger ch1mute;
  51. SchmittTrigger ch2mute;
  52. SchmittTrigger chMmute;
  53. float ch1m = false;
  54. float ch2m = false;
  55. float chMm = false;
  56. float mixL = 0.0f;
  57. float mixR = 0.0f;
  58. json_t *toJson()override {
  59. json_t *rootJm = json_object();
  60. json_t *mutesJ = json_array();
  61. json_t *muteJ1 = json_integer((int) ch1m);
  62. json_t *muteJ2 = json_integer((int) ch2m);
  63. json_t *muteJ3 = json_integer((int) chMm);
  64. json_array_append_new(mutesJ, muteJ1);
  65. json_array_append_new(mutesJ, muteJ2);
  66. json_array_append_new(mutesJ, muteJ3);
  67. json_object_set_new(rootJm, "as_Mixer2Mutes", mutesJ);
  68. return rootJm;
  69. }
  70. void fromJson(json_t *rootJm)override {
  71. json_t *mutesJ = json_object_get(rootJm, "as_Mixer2Mutes");
  72. json_t *muteJ1 = json_array_get(mutesJ, 0);
  73. json_t *muteJ2 = json_array_get(mutesJ, 1);
  74. json_t *muteJ3 = json_array_get(mutesJ, 2);
  75. ch1m = !!json_integer_value(muteJ1);
  76. ch2m = !!json_integer_value(muteJ2);
  77. chMm = !!json_integer_value(muteJ3);
  78. }
  79. //PAN LEVEL
  80. float PanL(float balance, float cv) { // -1...+1
  81. float p, inp;
  82. inp = balance + cv / 5;
  83. p = M_PI * (clamp(inp, -1.0f, 1.0f) + 1) / 4;
  84. return ::cos(p);
  85. }
  86. float PanR(float balance , float cv) {
  87. float p, inp;
  88. inp = balance + cv / 5;
  89. p = M_PI * (clamp(inp, -1.0f, 1.0f) + 1) / 4;
  90. return ::sin(p);
  91. }
  92. };
  93. void Mixer2ch::step() {
  94. //MUTE BUTTONS
  95. if (ch1mute.process(params[CH1MUTE].value)) {
  96. ch1m = !ch1m;
  97. }
  98. lights[MUTE_LIGHT1].value = ch1m ? 1.0f : 0.0f;
  99. if (ch2mute.process(params[CH2MUTE].value)) {
  100. ch2m = !ch2m;
  101. }
  102. lights[MUTE_LIGHT2].value = ch2m ? 1.0f : 0.0f;
  103. if (chMmute.process(params[MASTER_MUTE].value)) {
  104. chMm = !chMm;
  105. }
  106. lights[MUTE_LIGHT_MASTER].value = chMm ? 1.0f : 0.0f;
  107. //CHANNEL RESULTS
  108. float ch1L = (1-ch1m) * (inputs[CH1_INPUT].value) * params[CH1_PARAM].value * PanL(params[CH1_PAN_PARAM].value,(inputs[CH1_CV_PAN_INPUT].value))* clamp(inputs[CH1_CV_INPUT].normalize(10.0f) / 10.0f, 0.0f, 1.0f);
  109. float ch1R = (1-ch1m) * (inputs[CH1_INPUT].value) * params[CH1_PARAM].value * PanR(params[CH1_PAN_PARAM].value,(inputs[CH1_CV_PAN_INPUT].value)) * clamp(inputs[CH1_CV_INPUT].normalize(10.0f) / 10.0f, 0.0f, 1.0f);
  110. float ch2L = (1-ch2m) *(inputs[CH2_INPUT].value) * params[CH2_PARAM].value * PanL(params[CH2_PAN_PARAM].value,(inputs[CH2_CV_PAN_INPUT].value)) * clamp(inputs[CH2_CV_INPUT].normalize(10.0f) / 10.0f, 0.0f, 1.0f);
  111. float ch2R = (1-ch2m) *(inputs[CH2_INPUT].value) * params[CH2_PARAM].value * PanR(params[CH2_PAN_PARAM].value,(inputs[CH2_CV_PAN_INPUT].value)) * clamp(inputs[CH2_CV_INPUT].normalize(10.0f) / 10.0f, 0.0f, 1.0f);
  112. if(!chMm){
  113. mixL = (ch1L + ch2L) * params[MIX_PARAM].value * clamp(inputs[MIX_CV_INPUT].normalize(10.0f) / 10.0f, 0.0f, 1.0f);
  114. mixR = (ch1R + ch2R) * params[MIX_PARAM].value * clamp(inputs[MIX_CV_INPUT].normalize(10.0f) / 10.0f, 0.0f, 1.0f);
  115. //CHECK FOR INPUT FROM ANOTHER MIXER
  116. if(inputs[LINK_L].active && inputs[LINK_R].active){
  117. mixL += inputs[LINK_L].value;
  118. mixR += inputs[LINK_R].value;
  119. }
  120. }else{
  121. mixL = 0.0f;
  122. mixR = 0.0f;
  123. }
  124. outputs[CH1_OUTPUT].value= ch1L+ch1R;
  125. outputs[CH2_OUTPUT].value= ch2L+ch2R;
  126. //check for MONO OUTPUT
  127. if(!outputs[MIX_OUTPUTR].active){
  128. outputs[MIX_OUTPUTL].value= mixL+mixR;
  129. outputs[MIX_OUTPUTR].value= 0.0f;
  130. }else{
  131. outputs[MIX_OUTPUTL].value= mixL;
  132. outputs[MIX_OUTPUTR].value= mixR;
  133. }
  134. //outputs[MIX_OUTPUTL].value= mixL;
  135. //outputs[MIX_OUTPUTR].value= mixR;
  136. }
  137. struct Mixer2chWidget : ModuleWidget
  138. {
  139. Mixer2chWidget(Mixer2ch *module);
  140. };
  141. Mixer2chWidget::Mixer2chWidget(Mixer2ch *module) : ModuleWidget(module) {
  142. setPanel(SVG::load(assetPlugin(plugin, "res/2chMixer.svg")));
  143. //SCREWS
  144. addChild(Widget::create<as_HexScrew>(Vec(RACK_GRID_WIDTH, 0)));
  145. addChild(Widget::create<as_HexScrew>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0)));
  146. addChild(Widget::create<as_HexScrew>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  147. addChild(Widget::create<as_HexScrew>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  148. //PAN KNOBS
  149. static const float columnPos[8] = {33,73,113,153, 193, 233, 273, 313};
  150. static const float panPosY = 180;
  151. addParam(ParamWidget::create<as_KnobBlack>(Vec(columnPos[0]-5, panPosY), module, Mixer2ch::CH1_PAN_PARAM, -1.0f, 1.0f, 0.0f));
  152. addParam(ParamWidget::create<as_KnobBlack>(Vec(columnPos[1]-5, panPosY), module, Mixer2ch::CH2_PAN_PARAM, -1.0f, 1.0f, 0.0f));
  153. //VOLUME FADERS
  154. static const float volPosY = 223;
  155. addParam(ParamWidget::create<as_FaderPot>(Vec(columnPos[0]+2, volPosY), module, Mixer2ch::CH1_PARAM, 0.0f, 1.0f, 0.8f));
  156. addParam(ParamWidget::create<as_FaderPot>(Vec(columnPos[1]+2, volPosY), module, Mixer2ch::CH2_PARAM, 0.0f, 1.0f, 0.8f));
  157. //MUTES
  158. static const float mutePosY = 310;
  159. addParam(ParamWidget::create<LEDBezel>(Vec(columnPos[0]+3, mutePosY), module, Mixer2ch::CH1MUTE , 0.0f, 1.0f, 0.0f));
  160. addChild(ModuleLightWidget::create<LedLight<RedLight>>(Vec(columnPos[0]+5.2, mutePosY+2), module, Mixer2ch::MUTE_LIGHT1));
  161. addParam(ParamWidget::create<LEDBezel>(Vec(columnPos[1]+3, mutePosY), module, Mixer2ch::CH2MUTE , 0.0f, 1.0f, 0.0f));
  162. addChild(ModuleLightWidget::create<LedLight<RedLight>>(Vec(columnPos[1]+5.2, mutePosY+2), module, Mixer2ch::MUTE_LIGHT2));
  163. //PORTS
  164. static const float portsY[4] = {60,90,120,150};
  165. addInput(Port::create<as_PJ301MPort>(Vec(columnPos[0], portsY[0]), Port::INPUT, module, Mixer2ch::CH1_INPUT));
  166. addInput(Port::create<as_PJ301MPort>(Vec(columnPos[0], portsY[1]), Port::INPUT, module, Mixer2ch::CH1_CV_INPUT));
  167. addInput(Port::create<as_PJ301MPort>(Vec(columnPos[0], portsY[2]), Port::INPUT, module, Mixer2ch::CH1_CV_PAN_INPUT));
  168. addInput(Port::create<as_PJ301MPort>(Vec(columnPos[1], portsY[0]), Port::INPUT, module, Mixer2ch::CH2_INPUT));
  169. addInput(Port::create<as_PJ301MPort>(Vec(columnPos[1], portsY[1]), Port::INPUT, module, Mixer2ch::CH2_CV_INPUT));
  170. addInput(Port::create<as_PJ301MPort>(Vec(columnPos[1], portsY[2]), Port::INPUT, module, Mixer2ch::CH2_CV_PAN_INPUT));
  171. addOutput(Port::create<as_PJ301MPort>(Vec(columnPos[0], portsY[3]), Port::OUTPUT, module, Mixer2ch::CH1_OUTPUT));
  172. addOutput(Port::create<as_PJ301MPort>(Vec(columnPos[1], portsY[3]), Port::OUTPUT, module, Mixer2ch::CH2_OUTPUT));
  173. //OUTPUT
  174. static const float mstrX = 130;
  175. addOutput(Port::create<as_PJ301MPort>(Vec(mstrX, portsY[0]), Port::OUTPUT, module, Mixer2ch::MIX_OUTPUTL));
  176. addOutput(Port::create<as_PJ301MPort>(Vec(mstrX, portsY[1]), Port::OUTPUT, module, Mixer2ch::MIX_OUTPUTR));
  177. addInput(Port::create<as_PJ301MPort>(Vec(mstrX, portsY[3]), Port::INPUT, module, Mixer2ch::MIX_CV_INPUT));
  178. addParam(ParamWidget::create<as_FaderPot>(Vec(mstrX, volPosY), module, Mixer2ch::MIX_PARAM, 0.0f, 1.0f, 0.8f));
  179. addParam(ParamWidget::create<LEDBezel>(Vec(mstrX, mutePosY), module, Mixer2ch::MASTER_MUTE , 0.0f, 1.0f, 0.0f));
  180. addChild(ModuleLightWidget::create<LedLight<RedLight>>(Vec(mstrX+2.2, mutePosY+2), module, Mixer2ch::MUTE_LIGHT_MASTER));
  181. //LINK
  182. addInput(Port::create<as_PJ301MPort>(Vec(columnPos[0], 30), Port::INPUT, module, Mixer2ch::LINK_L));
  183. addInput(Port::create<as_PJ301MPort>(Vec(columnPos[1], 30), Port::INPUT, module, Mixer2ch::LINK_R));
  184. }
  185. RACK_PLUGIN_MODEL_INIT(AS, Mixer2ch) {
  186. Model *modelMixer2ch = Model::create<Mixer2ch, Mixer2chWidget>("AS", "Mixer2ch", "2-CH Mixer", MIXER_TAG, AMPLIFIER_TAG);
  187. return modelMixer2ch;
  188. }