mixxx_controller_with_mux.ino 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  1. #include "Arduino.h"
  2. #include "MIDIUSB.h"
  3. #include <EncoderButton.h>
  4. /* This is a sketch that it transforms your Arduino Leonardo or Leonardo like (i.e. boards with atmega32u4) in a MIDI console for interfacing
  5. * with Mixxx (https://mixxx.org). Perhaps you can also use an UNO but you have to sacrifice some pins in order to add a MIDI interface to your Arduino.
  6. * Once you have flashed the board, you have to train Mixxx in Preferences/Controllers menu.
  7. * Remember to plug the Arduino before launching Mixxx, otherwise it won't be detected.
  8. *
  9. * This software is released under the Unlicense (see LICENSE for more info).
  10. *
  11. * Last revision 27-dec-2023
  12. */
  13. // Uncomment this line if you want pin and values printed on the serial, remember to open a console because otherwise it waits until a connection is established.
  14. #define DEBUG
  15. // Analog controls (sliders and potentiometers), the deadzone is the smallest increment that the control must have to trigger the effect.
  16. const int dead_zone = 10;
  17. // Stickyness is a deazone that lies around extreme positions (0-1023) and the middle (511, but trimmable) of readings.
  18. const int stickyness = 30;
  19. struct analogControl {
  20. const int pin;
  21. int value;
  22. int prev_value;
  23. const byte effect;
  24. const int middle;
  25. };
  26. /* Connect linear potentiometers (sliders and knobs) to Analog Inputs on your board.
  27. * On Leonardo, from A0 to A5 are on the left (with USB on top)
  28. * A6, A7, A8, A9, A10 and A11 are digital pins
  29. * 4, 6, 8, 9, 10, 12.
  30. *
  31. * Change the first value accordingly, the last one is the MIDI effect that is sent to
  32. * Mixxx, it's not important but every control need to have a unique number.
  33. */
  34. //If you aren't using any analog controls, comment these lines.
  35. /*
  36. const int analog_controls_pins[] = {A0,A1,A2,A3,A4,A5,A7,A10,A11};
  37. const int analog_controls_effects[] = {7,8,9,1,2,3,4,5,6};
  38. analogControl analog_controls[] = {
  39. analogControl {analog_controls_pins[0],0,0,analog_controls_effects[0],511},
  40. analogControl {analog_controls_pins[1],0,0,analog_controls_effects[1],520},
  41. analogControl {analog_controls_pins[2],0,0,analog_controls_effects[2],520},
  42. analogControl {analog_controls_pins[3],0,0,analog_controls_effects[3],511},
  43. analogControl {analog_controls_pins[4],0,0,analog_controls_effects[4],511},
  44. analogControl {analog_controls_pins[5],0,0,analog_controls_effects[5],511},
  45. analogControl {analog_controls_pins[6],0,0,analog_controls_effects[6],511},
  46. analogControl {analog_controls_pins[7],0,0,analog_controls_effects[7],511},
  47. analogControl {analog_controls_pins[8],0,0,analog_controls_effects[8],511},
  48. };
  49. const int active_analog_controls = sizeof(analog_controls)/sizeof(analog_controls[0]);
  50. */
  51. //These lines disable analog controls if uncommented.
  52. analogControl analog_controls[] = {};
  53. const int active_analog_controls = 0;
  54. /* Rotary Encorders needs two pins.
  55. * clk should be interrupts. On Leonardo interrups are on pin 0, 1, 2, 3 and 7.
  56. * dt are digital pins
  57. * effect_fd and effect_bk have to be unique
  58. */
  59. struct rotaryEncoder {
  60. const int clk;
  61. const int dt;
  62. volatile int val;
  63. volatile int val_changed;
  64. EncoderButton eb;
  65. const int effect_fd;
  66. const int effect_bk;
  67. };
  68. //Comment these lines if you don't have any rotary encoders.
  69. const int rot_clk_pins[] = {2,3,0};
  70. const int rot_dt_pins[] = {4,5,1};
  71. const int rot_effect_fd[] = {10,12,18};
  72. const int rot_effect_bk[] = {11,13,19};
  73. rotaryEncoder rotary_encoders[] = {
  74. {rot_clk_pins[0],rot_dt_pins[0],0,false,EncoderButton (rot_clk_pins[0],rot_dt_pins[0]),rot_effect_fd[0],rot_effect_bk[0]},
  75. {rot_clk_pins[1],rot_dt_pins[1],0,false,EncoderButton (rot_clk_pins[1],rot_dt_pins[1]),rot_effect_fd[1],rot_effect_bk[1]},
  76. {rot_clk_pins[2],rot_dt_pins[2],0,false,EncoderButton (rot_clk_pins[2],rot_dt_pins[2]),rot_effect_fd[2],rot_effect_bk[2]},
  77. };
  78. const int active_encoders = sizeof(rotary_encoders)/sizeof(rotary_encoders[1]);
  79. //These lines disable rotary encoders if uncommented.
  80. //rotaryEncoder rotary_encoders[] = {};
  81. //const int active_encoders = 0;
  82. // Digital buttons are connected to a digital pin. If you use toggle, long press or long press toggle rembember that the MIDI message byte has to be unique.
  83. // long_inteval is the interval of long clicks, toggle and long_toggle (for long presses) send two different messages for odd and even strokes
  84. // if their effect is 0 the toggle, long press or long press toggle is disabled.
  85. const int long_interval = 1000;
  86. struct digitalButton {
  87. const int pin;
  88. bool pressed;
  89. long debounce;
  90. long countdown;
  91. const byte effect;
  92. const byte effect_toggle;
  93. bool toggled;
  94. const byte effect_long;
  95. const byte effect_long_toggle;
  96. bool long_toggled;
  97. bool long_pressed;
  98. };
  99. struct mux{
  100. const int pinSIG;
  101. const int pinS0;
  102. const int pinS1;
  103. const int pinS2;
  104. const int pinS3;
  105. };
  106. struct mux_selector{
  107. const mux ph_mux;
  108. const byte selector;
  109. int value;
  110. int prev_value;
  111. const byte effect;
  112. const int middle;
  113. };
  114. //every multiplexer needs 1 pin for reading the analog signal and 4 digital pins for selecting the channel
  115. const int mux_signal[] = {A0};
  116. const int mux_pins[][4] = {{4,5,6,7}};
  117. mux muxes[] = {
  118. {mux_signal[0],mux_pins[0][0],mux_pins[0][1],mux_pins[0][2],mux_pins[0][3]}
  119. };
  120. const int active_muxes = sizeof(muxes)/sizeof(muxes[0]);
  121. //for every multiplexer, up to 16 different analog controllers are allowed
  122. const int selectors[] = {0,1,2,3,4,5,6,7,8};
  123. const int mux_effects[] = {7,8,9,1,2,3,4,5,6};
  124. const int mux_middle[] = {511,520,520,511,511,511,511,511};
  125. mux_selector mux_inputs[] = {
  126. mux_selector {muxes[0], selectors[0], 0, 0,mux_effects[0],mux_middle[0]},
  127. mux_selector {muxes[0], selectors[1], 0, 0,mux_effects[1],mux_middle[1]},
  128. mux_selector {muxes[0], selectors[2], 0, 0,mux_effects[2],mux_middle[2]},
  129. mux_selector {muxes[0], selectors[3], 0, 0,mux_effects[3],mux_middle[3]},
  130. mux_selector {muxes[0], selectors[4], 0, 0,mux_effects[4],mux_middle[4]},
  131. mux_selector {muxes[0], selectors[5], 0, 0,mux_effects[5],mux_middle[5]},
  132. mux_selector {muxes[0], selectors[6], 0, 0,mux_effects[6],mux_middle[6]},
  133. mux_selector {muxes[0], selectors[7], 0, 0,mux_effects[7],mux_middle[7]},
  134. mux_selector {muxes[0], selectors[8], 0, 0,mux_effects[8],mux_middle[8]},
  135. };
  136. const int active_mux_inputs = sizeof(mux_selector)/sizeof(mux_selector[0]);
  137. //Comment these lines if you don't use switches.
  138. const int button_pins[] = {9,11,8,7,13};
  139. const int button_effect[] = {14,15,16,17,20};
  140. const int button_effect_toggle[] = {0,0,0,0,0};
  141. const int button_effect_long[] {0,0,23,24,25};
  142. const int button_effect_toggle_long[] {0,0,0,0,26};
  143. digitalButton switches[] = {
  144. {button_pins[0],false,0,0,button_effect[0],button_effect_toggle[0],false,button_effect_long[0],button_effect_toggle_long[0],false,false},
  145. {button_pins[1],false,0,0,button_effect[1],button_effect_toggle[1],false,button_effect_long[1],button_effect_toggle_long[1],false,false},
  146. {button_pins[2],false,0,0,button_effect[2],button_effect_toggle[2],false,button_effect_long[2],button_effect_toggle_long[2],false,false},
  147. {button_pins[3],false,0,0,button_effect[3],button_effect_toggle[3],false,button_effect_long[3],button_effect_toggle_long[3],false,false},
  148. {button_pins[4],false,0,0,button_effect[4],button_effect_toggle[4],false,button_effect_long[4],button_effect_toggle_long[4],false,false}
  149. };
  150. const int active_switches = sizeof(switches)/sizeof(switches[0]);
  151. //These lines disables digital buttons.
  152. //digitalButton switches[] = {};
  153. //const int active_switches = 0;
  154. // MIDI
  155. byte midi_value;
  156. // First parameter is the event type (0x09 = note on, 0x08 = note off).
  157. // Second parameter is note-on/note-off, combined with the channel.
  158. // Channel can be anything between 0-15. Typically reported to the user as 1-16.
  159. // Third parameter is the note number (48 = middle C).
  160. // Fourth parameter is the velocity (64 = normal, 127 = fastest).
  161. // First parameter is the event type (0x0B = control change).
  162. // Second parameter is the event type, combined with the channel.
  163. // Third parameter is the control number number (0-119).
  164. // Fourth parameter is the control value (0-127).
  165. void noteOn(byte channel, byte pitch, byte velocity) {
  166. midiEventPacket_t noteOn = {0x09, 0x90 | channel, pitch, velocity};
  167. MidiUSB.sendMIDI(noteOn);
  168. }
  169. void noteOff(byte channel, byte pitch, byte velocity) {
  170. midiEventPacket_t noteOff = {0x08, 0x80 | channel, pitch, velocity};
  171. MidiUSB.sendMIDI(noteOff);
  172. }
  173. void controlChange(byte channel, byte control, byte value) {
  174. midiEventPacket_t event = {0x0B, 0xB0 | channel, control, value};
  175. MidiUSB.sendMIDI(event);
  176. }
  177. int eb_Encoder(EncoderButton& eb) {
  178. for (int i = 0; i < active_encoders; i++) {
  179. if (&eb == &rotary_encoders[i].eb){
  180. rotary_encoders[i].val = eb.increment();
  181. rotary_encoders[i].val_changed = true;
  182. }
  183. }
  184. }
  185. void setup() {
  186. #ifdef DEBUG
  187. while(!Serial);
  188. Serial.begin(115200);
  189. Serial.println("RDY");
  190. #endif
  191. for (int i = 0; i < active_muxes; i++) {
  192. pinMode(muxes[i].pinS0,INPUT);
  193. pinMode(muxes[i].pinS1,INPUT);
  194. pinMode(muxes[i].pinS2,INPUT);
  195. pinMode(muxes[i].pinS3,INPUT);
  196. }
  197. for (int i = 0; i < active_switches; i++) {
  198. pinMode(switches[i].pin,INPUT_PULLUP);
  199. }
  200. for (int i = 0; i < active_encoders; i++) {
  201. rotary_encoders[i].eb.setEncoderHandler(eb_Encoder);
  202. }
  203. }
  204. void loop() {
  205. // Analog controls check.
  206. for (int i = 0; i < active_analog_controls; i++) {
  207. analog_controls[i].value = analogRead(analog_controls[i].pin);
  208. if (analog_controls[i].value < 0+stickyness){
  209. analog_controls[i].value = 0;
  210. } else if (analog_controls[i].value > 1023-stickyness) {
  211. analog_controls[i].value = 1023;
  212. } else if (analog_controls[i].value > analog_controls[i].middle-stickyness && analog_controls[i].value < analog_controls[i].middle+stickyness) {
  213. analog_controls[i].value = analog_controls[i].middle;
  214. }
  215. if ( abs(analog_controls[i].value - analog_controls[i].prev_value) > dead_zone ){
  216. midi_value = map(analog_controls[i].value,0,1023,0,127);
  217. controlChange(1,analog_controls[i].effect,midi_value);
  218. #ifdef DEBUG
  219. Serial.print("Analog ");
  220. Serial.print(analog_controls[i].effect);
  221. Serial.print(",");
  222. Serial.println(analog_controls[i].value);
  223. #endif
  224. analog_controls[i].prev_value = analog_controls[i].value;
  225. MidiUSB.flush();
  226. }
  227. }
  228. // Analog signal from multiplexer check.
  229. for (int i = 0; i < active_mux_inputs; i++) {
  230. digitalWrite(mux_inputs[i].ph_mux.pinS0,bitRead(mux_inputs[i].selector,0));
  231. digitalWrite(mux_inputs[i].ph_mux.pinS1,bitRead(mux_inputs[i].selector,1));
  232. digitalWrite(mux_inputs[i].ph_mux.pinS2,bitRead(mux_inputs[i].selector,2));
  233. digitalWrite(mux_inputs[i].ph_mux.pinS3,bitRead(mux_inputs[i].selector,3));
  234. mux_inputs[i].value = analogRead(mux_inputs[i].ph_mux.pinSIG);
  235. if (mux_inputs[i].value < 0+stickyness){
  236. mux_inputs[i].value = 0;
  237. } else if (mux_inputs[i].value > 1023-stickyness) {
  238. mux_inputs[i].value = 1023;
  239. } else if (mux_inputs[i].value > mux_inputs[i].middle-stickyness && mux_inputs[i].value < mux_inputs[i].middle+stickyness) {
  240. mux_inputs[i].value = mux_inputs[i].middle;
  241. }
  242. if ( abs(mux_inputs[i].value - mux_inputs[i].prev_value) > dead_zone ){
  243. midi_value = map(mux_inputs[i].value,0,1023,0,127);
  244. controlChange(1,mux_inputs[i].effect,midi_value);
  245. #ifdef DEBUG
  246. Serial.print("Mux ");
  247. Serial.print(mux_inputs[i].effect);
  248. Serial.print(", ");
  249. Serial.println(mux_inputs[i].value);
  250. #endif
  251. mux_inputs[i].prev_value = mux_inputs[i].value;
  252. MidiUSB.flush();
  253. }
  254. }
  255. // Rotary encoders check.
  256. for (int i = 0; i < active_encoders; i++) {
  257. rotary_encoders[i].eb.update();
  258. if(rotary_encoders[i].val_changed) {
  259. if(rotary_encoders[i].val < 0){
  260. controlChange(1,rotary_encoders[i].effect_fd,1);
  261. } else {
  262. controlChange(1,rotary_encoders[i].effect_bk,1);
  263. }
  264. rotary_encoders[i].val_changed = false;
  265. MidiUSB.flush();
  266. #ifdef DEBUG
  267. Serial.print(i);
  268. Serial.print(" enc=");
  269. Serial.println(rotary_encoders[i].val);
  270. #endif
  271. }
  272. }
  273. // Switches check.
  274. for (int i = 0; i < active_switches; i++) {
  275. if (digitalRead(switches[i].pin) == LOW && switches[i].pressed == false) {
  276. switches[i].pressed = true;
  277. switches[i].long_pressed = false;
  278. switches[i].debounce = millis();
  279. #ifdef DEBUG
  280. Serial.print("Press SW ");
  281. Serial.println(switches[i].pin);
  282. #endif DEBUG
  283. }
  284. if (switches[i].pressed && (millis() - switches[i].debounce <= 10) && digitalRead(switches[i].pin) == HIGH) {
  285. switches[i].pressed = false;
  286. continue;
  287. }
  288. if (switches[i].pressed && (millis() - switches[i].debounce > 10) && digitalRead(switches[i].pin) == HIGH) {
  289. if (switches[i].long_pressed == true) {
  290. switches[i].long_pressed = false;
  291. } else if (switches[i].effect_toggle == 0) {
  292. controlChange(1,switches[i].effect,1);
  293. #ifdef DEBUG
  294. Serial.print("Release SW ");
  295. Serial.println(switches[i].pin);
  296. #endif
  297. } else if (switches[i].toggled) {
  298. controlChange(1,switches[i].effect,1);
  299. switches[i].toggled = false;
  300. #ifdef DEBUG
  301. Serial.print("Release SW - toggle 0 ");
  302. Serial.println(switches[i].pin);
  303. #endif
  304. } else {
  305. controlChange(1,switches[i].effect_toggle,1);
  306. switches[i].toggled = true;
  307. #ifdef DEBUG
  308. Serial.print("Release SW - toggle 1 ");
  309. Serial.println(switches[i].pin);
  310. #endif
  311. }
  312. MidiUSB.flush();
  313. switches[i].pressed = false;
  314. }
  315. if (switches[i].pressed && (millis() - switches[i].debounce > long_interval) && (digitalRead(switches[i].pin) == LOW) && (switches[i].long_pressed == false)) {
  316. switches[i].long_pressed = true;
  317. if (switches[i].effect_long_toggle == 0) {
  318. controlChange(1,switches[i].effect_long,1);
  319. #ifdef DEBUG
  320. Serial.print("Long press SW ");
  321. Serial.println(switches[i].pin);
  322. #endif
  323. } else if (switches[i].long_toggled) {
  324. controlChange(1,switches[i].effect_long,1);
  325. switches[i].long_toggled = false;
  326. #ifdef DEBUG
  327. Serial.print("Long press SW - toggle 0 ");
  328. Serial.println(switches[i].pin);
  329. #endif
  330. } else {
  331. controlChange(1,switches[i].effect_long_toggle,1);
  332. switches[i].long_toggled = true;
  333. #ifdef DEBUG
  334. Serial.print("Long press SW - toggle 1 ");
  335. Serial.println(switches[i].pin);
  336. #endif
  337. }
  338. MidiUSB.flush();
  339. }
  340. }
  341. }