MIDI Merger and Patchbay
A MIDI merger and patchbay with MIDI expression capabilities for the ARKeytar Arduino MIDI controller or other devices, based on Mega 2560.
Components and supplies
Arduino Mega 2560 Rev3
Toggle Switch, SPDT
MIDI 5 pins connector DIN 41524
Metal Enclosure, Electrical / Industrial
Rotary Encoder with Push-Button
Stereo jack socket
3PDT STOMP FOOT / PEDAL SWITCH
Tools and machines
Soldering iron (generic)
Solder Wire, Lead Free
Apps and platforms
Arduino IDE
Project description
Code
MIDI merger v1.11.1
arduino
1/* 2MIDI Merger v1.11.1 32022-10-16 4*/ 5 6/* MIDI and ShiftIn libraries */ 7#include <MIDI.h> 8#include <ShiftIn.h> 9ShiftIn<2> shift; // Two shift registers 10 11 12/* A MIDI instance is created for each of the two serial ports used */ 13MIDI_CREATE_INSTANCE(HardwareSerial, Serial2, M1); 14MIDI_CREATE_INSTANCE(HardwareSerial, Serial3, M2); 15 16 17 18/* Shift registers variables */ 19int num; 20int incoming; 21int newRegRead; 22 23/* Switches state. The variable contains: switch number, first and second pin state */ 24int s1[3] = {0,0,0}; int s1Old[3] = {0,0,0}; 25int s2[3] = {1,0,0}; int s2Old[3] = {1,0,0}; 26int s3[2] = {2,0}; int s3Old[2] = {2,0}; 27 28int s4[3] = {3,0,0}; int s4Old[3] = {3,0,0}; 29int s5[3] = {4,0,0}; int s5Old[3] = {4,0,0}; 30int s6[2] = {5,0}; int s6Old[2] = {5,0}; 31 32/* Encoder and stomps state */ 33int e[4] = {6,0,0,0}; int eOld[4] = {6,0,0,0}; 34int f[4] = {7,0,0,0}; int fOld[4] = {7,0,0,0}; 35 36/* Leds */ 37const int ledR = 43; 38const int ledG = 45; 39const int ledB = 41; 40const int ledPow = 39; 41int ledList[4] = {ledB, ledR, ledG, ledPow}; 42 43/* Pedals variables */ 44const int p[2] = {3,2}; 45const int p2A = A4; 46int susVal[2]; 47int susValOld[2]; 48int ccVal[2]; 49int sPedal[5] = {0,0,0,0,0}; 50 51int expVal[2]; 52int expValOld[2]; 53int expcc[2]; 54int expccOld[2]; 55 56int button = 0; int buttonOld = 0; 57 58/* Settings list */ 59/* 0. MIDI channel pedal 1, Digital - Default: ch8 60 1. MIDI channel pedal 2, Digital - Default: ch8 61 2. MIDI channel pedal 2, Analog - Default: ch8 62 3. CC pedal 1, Digital - Default: sustain 63 4. CC pedal 2, Digital - Default: sustain 64 5. CC pedal 2, Analog - Default: volume 65*/ 66int setting[6] = {8, 8, 8, 1, 1, 2}; 67/* The settings are: 0.midi channel for pedal 1; 68 1. midi channel for pedal 2, digital 69 2. midi channel for pedal 2, analog 70 3. index for listcc, cc destination of pedal 1 71 4. index for listcc, cc destination of pedal 2, digital 72 5. index for listcc, cc destination of pedal 2, analog*/ 73/* Control change number to be selected for expression pedal */ 74const int listCC[12] = {64, 7, 74, 71, 11, 1, 5, 73, 91, 93, 72, 10}; 75 76 77 78 79void setup() { 80 /* turn on the "power on led" */ 81 pinMode(ledPow, OUTPUT); 82 digitalWrite(ledPow, HIGH); 83 84 M1.begin(MIDI_CHANNEL_OMNI); 85 M2.begin(MIDI_CHANNEL_OMNI); 86 Serial.begin(9600); 87 88 /* Shift registers setup */ 89 shift.begin(4, 5, 6, 7); 90 if(shift.update()) 91 incoming = readShiftReg(); 92 saveShiftReg(); 93 e[1] = 0; 94 95 /* LEDs pins */ 96 pinMode(ledR, OUTPUT); 97 pinMode(ledG, OUTPUT); 98 pinMode(ledB, OUTPUT); 99 100 101 /* pedals */ 102 pinMode(p2A, INPUT_PULLUP); 103 pinMode(p[0], INPUT_PULLUP); 104 105 /* Defines digital/analog pedal behaviour */ 106 /* Digital */ 107 if (s3[1] == 0) { 108 pinMode(p[1], INPUT_PULLUP); 109 } 110 /* Analog */ 111 if (s3[1] == 1) { 112 pinMode(p[1], OUTPUT); 113 digitalWrite(p[1], HIGH); 114 } 115 116 /* Blink the leds after setup is done */ 117 for (int ii=0; ii<=2; ii++) { 118 digitalWrite(ledList[ii],HIGH); 119 delay(250); 120 digitalWrite(ledList[ii],LOW); 121 } 122} 123 124 125 126 127void loop() { 128 129 shiftReg(); 130 131 merger(); 132 merger(); 133 merger(); 134 135 pedals(); 136 137 merger(); 138 merger(); 139 merger(); 140 141} 142 143 144 145 146 147void shiftReg() { 148 149 if(shift.update()) {newRegRead = 1;} else {newRegRead = 0;} 150 incoming = readShiftReg(); 151 152 if(newRegRead){ 153 saveShiftReg(); 154 } 155} 156 157int readShiftReg() { 158 159 for(int i = 0; i < shift.getDataWidth(); i++){ 160 bitWrite(num, i, shift.state(i)); 161 } 162 163 int incomingNumber = 0; 164 for (int bitNumber = 8; bitNumber <= 15; bitNumber++) { 165 bitWrite(incoming, incomingNumber, bitRead(num,bitNumber)); 166 incomingNumber++; 167 } 168 for (int bitNumber = 0; bitNumber <= 7; bitNumber++) { 169 bitWrite(incoming, incomingNumber, bitRead(num,bitNumber)); 170 incomingNumber++; 171 } 172 merger(); 173 return incoming; 174} 175 176 177 178void saveShiftReg() { 179 /* Assign shift register values to variables */ 180 e[1] = bitRead(incoming,0); 181 e[2] = bitRead(incoming,1); 182 e[3] = bitRead(incoming,2); 183 f[1] = bitRead(incoming,3); 184 f[3] = bitRead(incoming,4); 185 f[2] = bitRead(incoming,5); 186 s3[1] = bitRead(incoming,6); 187 s6[1] = bitRead(incoming,7); 188 189 merger(); 190 191 s2[2] = bitRead(incoming,8); 192 s2[1] = bitRead(incoming,9); 193 s1[2] = bitRead(incoming,10); 194 s1[1] = bitRead(incoming,11); 195 s4[2] = bitRead(incoming,12); 196 s4[1] = bitRead(incoming,13); 197 s5[2] = bitRead(incoming,14); 198 s5[1] = bitRead(incoming,15); 199 200 sPedal[1] = s4[2]; 201 sPedal[2] = s4[1]; 202 sPedal[3] = s5[2]; 203 sPedal[4] = s5[1]; 204 205 206 if (s1[1] == 1) { 207 M1.turnThruOn(); 208 } 209 if (s1[2] == 1) { 210 M1.turnThruOff(); 211 } 212 if (s1[1] == 0 && s1[2] == 0) { 213 M1.turnThruOn(); 214 } 215 if (s2[2] == 1) { 216 M2.turnThruOn(); 217 } 218 if (s2[1] == 1) { 219 M2.turnThruOff(); 220 } 221 if (s2[1] == 0 && s2[2] == 0) { 222 M2.turnThruOff(); 223 } 224 merger(); 225} 226 227 228 229void merger() { 230 /* Manages the MIDI routing */ 231 if (M1.read()) { 232 if (s1[2] == 1) { 233 M2.send(M1.getType(), M1.getData1(), M1.getData2(), M1.getChannel()); 234 } 235 if (s1[1] == 0 && s1[2] == 0) { 236 M2.send(M1.getType(), M1.getData1(), M1.getData2(), M1.getChannel()); 237 } 238 } 239 240 if (M2.read()) { 241 if (s2[1] == 1) { 242 M1.send(M2.getType(), M2.getData1(), M2.getData2(), M2.getChannel()); 243 } 244 } 245 switchLed(); 246} 247 248 249 250void switchLed() { 251 /* LED color based on the MIDI message type */ 252 switch(M1.getType()) { 253 case midi::NoteOn: 254 ledOn(ledG); 255 break; 256 case midi::NoteOff: 257 ledOn(ledR); 258 break; 259 case midi::PitchBend: 260 ledOn(ledB); 261 break; 262 case midi::ControlChange: 263 ledOn(ledR); 264 break; 265 } 266 switch(M2.getType()) { 267 case midi::NoteOn: 268 ledOn(ledG); 269 break; 270 case midi::NoteOff: 271 ledOn(ledR); 272 break; 273 case midi::PitchBend: 274 ledOn(ledB); 275 break; 276 case midi::ControlChange: 277 ledOn(ledR); 278 break; 279 } 280 281} 282 283 284 285void ledOn(int ledPin) { 286 /* Turns on the led having pin number equal to the argument of the function. 287 Otherwise, it turns the LED off */ 288 for (int ii = ledList[0]; ii <= ledList[2]+2; ii = ii+2) { 289 if (ledPin == ii) { 290 digitalWrite(ledPin, HIGH); 291 } else { 292 digitalWrite(ledPin, LOW); 293 } 294 } 295} 296 297 298 299void pedals() { 300 /* Manages the pedals */ 301 302 if (s3[1] != s3Old[1]) { 303 if (s3[1] == 1) { 304 pinMode(p[1], INPUT_PULLUP); 305 } else if (s3[1] == 0) { 306 pinMode(p[1], OUTPUT); 307 digitalWrite(p[1], HIGH); 308 } 309 s3Old[1] = s3[1]; 310 } 311 312 for (int ii = 0; ii <= 1; ii++) { 313 314 /* Always proceed with pedal 1 */ 315 /* Proceed with pedal two if it is set on digital/switch */ 316 if (ii == 0 || ((s3[1] == 1) && (ii == 1))) { 317 susVal[ii] = digitalRead(p[ii]); 318 if (susVal[ii] != susValOld[ii]) { 319 if (susVal[ii] == 1) { 320 ccVal[ii] = 127; 321 } 322 if (susVal[ii] == 0) { 323 ccVal[ii] = 0; 324 } 325 326 if (sPedal[ii*2+1] == 1) { 327 M1.sendControlChange(listCC[setting[ii+3]],ccVal[ii],setting[ii]); 328 } 329 if (sPedal[ii*2+2] == 1) { 330 M2.sendControlChange(listCC[setting[ii+3]],ccVal[ii],setting[ii]); 331 } 332 if (sPedal[ii*2+1] == 0 && sPedal[ii*2+2] == 0) { 333 M1.sendControlChange(listCC[setting[ii+3]],ccVal[ii],setting[ii]); 334 M2.sendControlChange(listCC[setting[ii+3]],ccVal[ii],setting[ii]); 335 } 336 337 susValOld[ii] = susVal[ii]; 338 merger(); 339 } 340 } 341 342 if (ii == 1 && s3[1] == 0) { 343 expVal[1] = analogRead(p2A); 344 expcc[1] = map(expVal[1],30,1023,0,127); 345 346 if (expcc[1] != expccOld[1] && abs(expccOld[1]-expcc[1])>= 5) { 347 if (s5[1] == 1) { 348 M1.sendControlChange(listCC[setting[2+3]],expcc[1],setting[2]); 349 } 350 if (s5[2] == 1) { 351 M2.sendControlChange(listCC[setting[2+3]],expcc[1],setting[2]); 352 } 353 if (s5[1] == 0 && s5[2] == 0) { 354 M1.sendControlChange(listCC[setting[2+3]],expcc[1],setting[2]); 355 M2.sendControlChange(listCC[setting[2+3]],expcc[1],setting[2]); 356 } 357 358 359 expccOld[1] = expcc[1]; 360 } 361 } 362 merger(); 363 364 } 365 366}
Downloadable files
MIDI ports on serial3
MIDI ports on serial3

MIDI ports on serial2
MIDI ports on serial2

Pedals
This scheme represents the wiring and setting of the interchangable digital/analog port. A switch is used to change between these two modes.
Pedals

Shift registers
A single switch position is represented as an example for the connection that is repeated for all the 8 central pins of each shift register. The central pin of a switch is connected to 5V, the two remaining pins are connected to the shift registers as indicated in the example.
Shift registers

Comments
Only logged in users can leave comments