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.

310 lines
12KB

  1. //**************************************************************************************
  2. //4 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 Mixer4ch : Module {
  10. enum ParamIds {
  11. MIX_PARAM,
  12. CH1_PARAM,
  13. CH2_PARAM,
  14. CH3_PARAM,
  15. CH4_PARAM,
  16. CH1_PAN_PARAM,
  17. CH2_PAN_PARAM,
  18. CH3_PAN_PARAM,
  19. CH4_PAN_PARAM,
  20. CH1MUTE,
  21. CH2MUTE,
  22. CH3MUTE,
  23. CH4MUTE,
  24. MASTER_MUTE,
  25. NUM_PARAMS
  26. };
  27. enum InputIds {
  28. MIX_CV_INPUT,
  29. CH1_INPUT,
  30. CH1_CV_INPUT,
  31. CH1_CV_PAN_INPUT,
  32. CH2_INPUT,
  33. CH2_CV_INPUT,
  34. CH2_CV_PAN_INPUT,
  35. CH3_INPUT,
  36. CH3_CV_INPUT,
  37. CH3_CV_PAN_INPUT,
  38. CH4_INPUT,
  39. CH4_CV_INPUT,
  40. CH4_CV_PAN_INPUT,
  41. LINK_L,
  42. LINK_R,
  43. NUM_INPUTS
  44. };
  45. enum OutputIds {
  46. MIX_OUTPUTL,
  47. MIX_OUTPUTR,
  48. CH1_OUTPUT,
  49. CH2_OUTPUT,
  50. CH3_OUTPUT,
  51. CH4_OUTPUT,
  52. NUM_OUTPUTS
  53. };
  54. enum LightIds {
  55. MUTE_LIGHT1,
  56. MUTE_LIGHT2,
  57. MUTE_LIGHT3,
  58. MUTE_LIGHT4,
  59. MUTE_LIGHT_MASTER,
  60. NUM_LIGHTS
  61. };
  62. Mixer4ch() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {
  63. reset();
  64. }
  65. void step() override;
  66. SchmittTrigger ch1mute;
  67. SchmittTrigger ch2mute;
  68. SchmittTrigger ch3mute;
  69. SchmittTrigger ch4mute;
  70. SchmittTrigger chMmute;
  71. float ch1m = false;
  72. float ch2m = false;
  73. float ch3m = false;
  74. float ch4m = false;
  75. float chMm = false;
  76. float mixL = 0.0f;
  77. float mixR = 0.0f;
  78. json_t *toJson()override {
  79. json_t *rootJm = json_object();
  80. json_t *mutesJ = json_array();
  81. json_t *muteJ1 = json_integer((int) ch1m);
  82. json_t *muteJ2 = json_integer((int) ch2m);
  83. json_t *muteJ3 = json_integer((int) ch3m);
  84. json_t *muteJ4 = json_integer((int) ch4m);
  85. json_t *muteJ5 = json_integer((int) chMm);
  86. json_array_append_new(mutesJ, muteJ1);
  87. json_array_append_new(mutesJ, muteJ2);
  88. json_array_append_new(mutesJ, muteJ3);
  89. json_array_append_new(mutesJ, muteJ4);
  90. json_array_append_new(mutesJ, muteJ5);
  91. json_object_set_new(rootJm, "as_Mixer4Mutes", mutesJ);
  92. return rootJm;
  93. }
  94. void fromJson(json_t *rootJm)override {
  95. json_t *mutesJ = json_object_get(rootJm, "as_Mixer4Mutes");
  96. json_t *muteJ1 = json_array_get(mutesJ, 0);
  97. json_t *muteJ2 = json_array_get(mutesJ, 1);
  98. json_t *muteJ3 = json_array_get(mutesJ, 2);
  99. json_t *muteJ4 = json_array_get(mutesJ, 3);
  100. json_t *muteJ5 = json_array_get(mutesJ, 4);
  101. ch1m = !!json_integer_value(muteJ1);
  102. ch2m = !!json_integer_value(muteJ2);
  103. ch3m = !!json_integer_value(muteJ3);
  104. ch4m = !!json_integer_value(muteJ4);
  105. chMm = !!json_integer_value(muteJ5);
  106. }
  107. //PAN LEVEL
  108. float PanL(float balance, float cv) { // -1...+1
  109. float p, inp;
  110. inp = balance + cv / 5;
  111. p = M_PI * (clamp(inp, -1.0f, 1.0f) + 1) / 4;
  112. return ::cos(p);
  113. }
  114. float PanR(float balance , float cv) {
  115. float p, inp;
  116. inp = balance + cv / 5;
  117. p = M_PI * (clamp(inp, -1.0f, 1.0f) + 1) / 4;
  118. return ::sin(p);
  119. }
  120. };
  121. void Mixer4ch::step() {
  122. //MUTE BUTTONS
  123. if (ch1mute.process(params[CH1MUTE].value)) {
  124. ch1m = !ch1m;
  125. }
  126. lights[MUTE_LIGHT1].value = ch1m ? 1.0f : 0.0f;
  127. if (ch2mute.process(params[CH2MUTE].value)) {
  128. ch2m = !ch2m;
  129. }
  130. lights[MUTE_LIGHT2].value = ch2m ? 1.0f : 0.0f;
  131. if (ch3mute.process(params[CH3MUTE].value)) {
  132. ch3m = !ch3m;
  133. }
  134. lights[MUTE_LIGHT3].value = ch3m ? 1.0f : 0.0f;
  135. if (ch4mute.process(params[CH4MUTE].value)) {
  136. ch4m = !ch4m;
  137. }
  138. lights[MUTE_LIGHT4].value = ch4m ? 1.0f : 0.0f;
  139. if (chMmute.process(params[MASTER_MUTE].value)) {
  140. chMm = !chMm;
  141. }
  142. lights[MUTE_LIGHT_MASTER].value = chMm ? 1.0f : 0.0f;
  143. //CHANNEL RESULTS
  144. 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);
  145. 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);
  146. 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);
  147. 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);
  148. float ch3L = (1-ch3m) *(inputs[CH3_INPUT].value) * params[CH3_PARAM].value * PanL(params[CH3_PAN_PARAM].value,(inputs[CH3_CV_PAN_INPUT].value)) * clamp(inputs[CH3_CV_INPUT].normalize(10.0f) / 10.0f, 0.0f, 1.0f);
  149. float ch3R = (1-ch3m) *(inputs[CH3_INPUT].value) * params[CH3_PARAM].value * PanR(params[CH3_PAN_PARAM].value,(inputs[CH3_CV_PAN_INPUT].value)) * clamp(inputs[CH3_CV_INPUT].normalize(10.0f) / 10.0f, 0.0f, 1.0f);
  150. float ch4L = (1-ch4m) *(inputs[CH4_INPUT].value) * params[CH4_PARAM].value * PanL(params[CH4_PAN_PARAM].value,(inputs[CH4_CV_PAN_INPUT].value)) * clamp(inputs[CH4_CV_INPUT].normalize(10.0f) / 10.0f, 0.0f, 1.0f);
  151. float ch4R = (1-ch4m) *(inputs[CH4_INPUT].value) * params[CH4_PARAM].value * PanR(params[CH4_PAN_PARAM].value,(inputs[CH4_CV_PAN_INPUT].value)) * clamp(inputs[CH4_CV_INPUT].normalize(10.0f) / 10.0f, 0.0f, 1.0f);
  152. if(!chMm){
  153. mixL = (ch1L + ch2L + ch3L +ch4L) * params[MIX_PARAM].value * clamp(inputs[MIX_CV_INPUT].normalize(10.0f) / 10.0f, 0.0f, 1.0f);
  154. mixR = (ch1R + ch2R + ch3R +ch4R) * params[MIX_PARAM].value * clamp(inputs[MIX_CV_INPUT].normalize(10.0f) / 10.0f, 0.0f, 1.0f);
  155. //CHECK FOR INPUT FROM ANOTHER MIXER
  156. if(inputs[LINK_L].active && inputs[LINK_R].active){
  157. mixL += inputs[LINK_L].value;
  158. mixR += inputs[LINK_R].value;
  159. }
  160. }else{
  161. mixL = 0.0f;
  162. mixR = 0.0f;
  163. }
  164. outputs[CH1_OUTPUT].value= ch1L+ch1R;
  165. outputs[CH2_OUTPUT].value= ch2L+ch2R;
  166. outputs[CH3_OUTPUT].value= ch3L+ch3R;
  167. outputs[CH4_OUTPUT].value= ch4L+ch4R;
  168. //check for MONO OUTPUT
  169. if(!outputs[MIX_OUTPUTR].active){
  170. outputs[MIX_OUTPUTL].value= mixL+mixR;
  171. outputs[MIX_OUTPUTR].value= 0.0f;
  172. }else{
  173. outputs[MIX_OUTPUTL].value= mixL;
  174. outputs[MIX_OUTPUTR].value= mixR;
  175. }
  176. //outputs[MIX_OUTPUTL].value= mixL;
  177. //outputs[MIX_OUTPUTR].value= mixR;
  178. }
  179. struct Mixer4chWidget : ModuleWidget
  180. {
  181. Mixer4chWidget(Mixer4ch *module);
  182. };
  183. Mixer4chWidget::Mixer4chWidget(Mixer4ch *module) : ModuleWidget(module) {
  184. setPanel(SVG::load(assetPlugin(plugin, "res/4chMixer.svg")));
  185. //SCREWS
  186. addChild(Widget::create<as_HexScrew>(Vec(RACK_GRID_WIDTH, 0)));
  187. addChild(Widget::create<as_HexScrew>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0)));
  188. addChild(Widget::create<as_HexScrew>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  189. addChild(Widget::create<as_HexScrew>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  190. //PAN KNOBS
  191. static const float columnPos[8] = {33,73,113,153, 193, 233, 273, 313};
  192. static const float panPosY = 180;
  193. addParam(ParamWidget::create<as_KnobBlack>(Vec(columnPos[0]-5, panPosY), module, Mixer4ch::CH1_PAN_PARAM, -1.0f, 1.0f, 0.0f));
  194. addParam(ParamWidget::create<as_KnobBlack>(Vec(columnPos[1]-5, panPosY), module, Mixer4ch::CH2_PAN_PARAM, -1.0f, 1.0f, 0.0f));
  195. addParam(ParamWidget::create<as_KnobBlack>(Vec(columnPos[2]-5, panPosY), module, Mixer4ch::CH3_PAN_PARAM, -1.0f, 1.0f, 0.0f));
  196. addParam(ParamWidget::create<as_KnobBlack>(Vec(columnPos[3]-5, panPosY), module, Mixer4ch::CH4_PAN_PARAM, -1.0f, 1.0f, 0.0f));
  197. //VOLUME FADERS
  198. static const float volPosY = 223;
  199. addParam(ParamWidget::create<as_FaderPot>(Vec(columnPos[0]+2, volPosY), module, Mixer4ch::CH1_PARAM, 0.0f, 1.0f, 0.8f));
  200. addParam(ParamWidget::create<as_FaderPot>(Vec(columnPos[1]+2, volPosY), module, Mixer4ch::CH2_PARAM, 0.0f, 1.0f, 0.8f));
  201. addParam(ParamWidget::create<as_FaderPot>(Vec(columnPos[2]+2, volPosY), module, Mixer4ch::CH3_PARAM, 0.0f, 1.0f, 0.8f));
  202. addParam(ParamWidget::create<as_FaderPot>(Vec(columnPos[3]+2, volPosY), module, Mixer4ch::CH4_PARAM, 0.0f, 1.0f, 0.8f));
  203. //MUTES
  204. static const float mutePosY = 310;
  205. addParam(ParamWidget::create<LEDBezel>(Vec(columnPos[0]+3, mutePosY), module, Mixer4ch::CH1MUTE , 0.0f, 1.0f, 0.0f));
  206. addChild(ModuleLightWidget::create<LedLight<RedLight>>(Vec(columnPos[0]+5.2, mutePosY+2), module, Mixer4ch::MUTE_LIGHT1));
  207. addParam(ParamWidget::create<LEDBezel>(Vec(columnPos[1]+3, mutePosY), module, Mixer4ch::CH2MUTE , 0.0f, 1.0f, 0.0f));
  208. addChild(ModuleLightWidget::create<LedLight<RedLight>>(Vec(columnPos[1]+5.2, mutePosY+2), module, Mixer4ch::MUTE_LIGHT2));
  209. addParam(ParamWidget::create<LEDBezel>(Vec(columnPos[2]+3, mutePosY), module, Mixer4ch::CH3MUTE , 0.0f, 1.0f, 0.0f));
  210. addChild(ModuleLightWidget::create<LedLight<RedLight>>(Vec(columnPos[2]+5.2, mutePosY+2), module, Mixer4ch::MUTE_LIGHT3));
  211. addParam(ParamWidget::create<LEDBezel>(Vec(columnPos[3]+3, mutePosY), module, Mixer4ch::CH4MUTE , 0.0f, 1.0f, 0.0f));
  212. addChild(ModuleLightWidget::create<LedLight<RedLight>>(Vec(columnPos[3]+5.2, mutePosY+2), module, Mixer4ch::MUTE_LIGHT4));
  213. //PORTS
  214. static const float portsY[4] = {60,90,120,150};
  215. addInput(Port::create<as_PJ301MPort>(Vec(columnPos[0], portsY[0]), Port::INPUT, module, Mixer4ch::CH1_INPUT));
  216. addInput(Port::create<as_PJ301MPort>(Vec(columnPos[0], portsY[1]), Port::INPUT, module, Mixer4ch::CH1_CV_INPUT));
  217. addInput(Port::create<as_PJ301MPort>(Vec(columnPos[0], portsY[2]), Port::INPUT, module, Mixer4ch::CH1_CV_PAN_INPUT));
  218. addInput(Port::create<as_PJ301MPort>(Vec(columnPos[1], portsY[0]), Port::INPUT, module, Mixer4ch::CH2_INPUT));
  219. addInput(Port::create<as_PJ301MPort>(Vec(columnPos[1], portsY[1]), Port::INPUT, module, Mixer4ch::CH2_CV_INPUT));
  220. addInput(Port::create<as_PJ301MPort>(Vec(columnPos[1], portsY[2]), Port::INPUT, module, Mixer4ch::CH2_CV_PAN_INPUT));
  221. addInput(Port::create<as_PJ301MPort>(Vec(columnPos[2], portsY[0]), Port::INPUT, module, Mixer4ch::CH3_INPUT));
  222. addInput(Port::create<as_PJ301MPort>(Vec(columnPos[2], portsY[1]), Port::INPUT, module, Mixer4ch::CH3_CV_INPUT));
  223. addInput(Port::create<as_PJ301MPort>(Vec(columnPos[2], portsY[2]), Port::INPUT, module, Mixer4ch::CH3_CV_PAN_INPUT));
  224. addInput(Port::create<as_PJ301MPort>(Vec(columnPos[3], portsY[0]), Port::INPUT, module, Mixer4ch::CH4_INPUT));
  225. addInput(Port::create<as_PJ301MPort>(Vec(columnPos[3], portsY[1]), Port::INPUT, module, Mixer4ch::CH4_CV_INPUT));
  226. addInput(Port::create<as_PJ301MPort>(Vec(columnPos[3], portsY[2]), Port::INPUT, module, Mixer4ch::CH4_CV_PAN_INPUT));
  227. addOutput(Port::create<as_PJ301MPort>(Vec(columnPos[0], portsY[3]), Port::OUTPUT, module, Mixer4ch::CH1_OUTPUT));
  228. addOutput(Port::create<as_PJ301MPort>(Vec(columnPos[1], portsY[3]), Port::OUTPUT, module, Mixer4ch::CH2_OUTPUT));
  229. addOutput(Port::create<as_PJ301MPort>(Vec(columnPos[2], portsY[3]), Port::OUTPUT, module, Mixer4ch::CH3_OUTPUT));
  230. addOutput(Port::create<as_PJ301MPort>(Vec(columnPos[3], portsY[3]), Port::OUTPUT, module, Mixer4ch::CH4_OUTPUT));
  231. //OUTPUT
  232. static const float mstrX = 206;
  233. addOutput(Port::create<as_PJ301MPort>(Vec(mstrX, portsY[0]), Port::OUTPUT, module, Mixer4ch::MIX_OUTPUTL));
  234. addOutput(Port::create<as_PJ301MPort>(Vec(mstrX, portsY[1]), Port::OUTPUT, module, Mixer4ch::MIX_OUTPUTR));
  235. addInput(Port::create<as_PJ301MPort>(Vec(mstrX, portsY[3]), Port::INPUT, module, Mixer4ch::MIX_CV_INPUT));
  236. addParam(ParamWidget::create<as_FaderPot>(Vec(mstrX, volPosY), module, Mixer4ch::MIX_PARAM, 0.0f, 1.0f, 0.8f));
  237. addParam(ParamWidget::create<LEDBezel>(Vec(mstrX, mutePosY), module, Mixer4ch::MASTER_MUTE , 0.0f, 1.0f, 0.0f));
  238. addChild(ModuleLightWidget::create<LedLight<RedLight>>(Vec(mstrX+2.2, mutePosY+2), module, Mixer4ch::MUTE_LIGHT_MASTER));
  239. //LINK
  240. addInput(Port::create<as_PJ301MPort>(Vec(columnPos[0], 30), Port::INPUT, module, Mixer4ch::LINK_L));
  241. addInput(Port::create<as_PJ301MPort>(Vec(columnPos[1], 30), Port::INPUT, module, Mixer4ch::LINK_R));
  242. }
  243. RACK_PLUGIN_MODEL_INIT(AS, Mixer4ch) {
  244. Model *modelMixer4ch = Model::create<Mixer4ch, Mixer4chWidget>("AS", "Mixer4ch", "4-CH Mixer", MIXER_TAG, AMPLIFIER_TAG);
  245. return modelMixer4ch;
  246. }