Arduino MIDI Controller with Encoder + OLED Display + EEPROM
Unlimited MIDI channels, XY plotter, faders, buttons, and settings. Also visual support with OLED display!
Components and supplies
1
Analog joystick (Generic)
1
Breadboard (generic)
1
USB-A to Mini-USB Cable
1
Arduino Nano R3
6
Switch Actuator, Head for spring return push-button
1
MIDI Socket
1
Rotary Encoder with Push-Button
4
Rotary potentiometer (generic)
1
Jumper wires (generic)
1
Graphic OLED, 128 x 64
Tools and machines
1
Soldering iron (generic)
1
CNC Machine
Apps and platforms
1
Hairless MIDI
1
Arduino IDE
1
loopMIDI
Project description
Code
Arduino IDE Codes
arduino
Improved encoder Improved settings menu Added notes equation for midi messages on buttons Screen improvement Added 31250 and 115200 baud rate menu
1#include <SPI.h> 2#include <Wire.h> 3#include <Adafruit_GFX.h> 4#include <Adafruit_SSD1306.h> 5#include <EEPROM.h> 6#define SCREEN_WIDTH 128 // OLED display width, in pixels 7#define SCREEN_HEIGHT 64 // OLED display height, in pixels 8 9#define OLED_RESET 4 // Reset pin # (or -1 if sharing Arduino reset pin) 10Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); 11 12 13#define encoder0PinA 9 14#define encoder0PinB 2 15 16byte selectedVal = 0; 17float inc = 0; 18 19const byte rxPin = 12; // not used for the moment 20const byte txPin = 11; 21 22byte clk = 4; 23long buttonTimer = 0; 24long longPressTime = 500; 25boolean buttonActive = false; 26boolean longPressActive = false; 27 28byte val1; 29byte val1Last; 30byte val2; 31byte val2Last; 32byte val3; 33byte val3Last; 34byte val4; 35byte val4Last; 36byte val5; 37byte val5Last; 38 39int xVal; 40byte xValLast; 41int yVal; 42byte yValLast; 43int aVal; 44byte aValLast; 45int bVal; 46byte bValLast; 47int cVal; 48byte cValLast; 49int dVal; 50byte dValLast; 51 52byte b1Val; //button series 53byte b1ValLast; 54 55byte b2Val; 56byte b2ValLast; 57 58byte b3Val; 59byte b3ValLast; 60 61byte b4Val; 62byte b4ValLast; 63 64byte b5Val; 65byte b5ValLast; 66 67//values for screen 68byte xVals; 69byte yVals; 70byte aVals; 71byte bVals; 72byte cVals; 73byte dVals; 74 75byte yValsOld; 76byte xValsOld; 77 78byte ch = 1; 79int oldVal; 80 81bool enabled = false; 82 83byte noteON = 144;//144 = 10010000 in binary, note on command 84byte noteOFF = 128;//128 = 10000000 in binary, note off command 85 86byte note1 = 47; 87byte note1Old; 88byte note2 = 48; 89byte note2Old; 90byte note3 = 50; 91byte note3Old; 92byte note4 = 52; 93byte note4Old; 94byte note5 = 53; 95byte note5Old; 96byte velocity; 97byte velocityOld; 98 99byte octave = 0; 100char octaveBank = 'A'; 101 102byte countLimit = 10; 103int changeVal = 1; 104 105bool flag1 = false; 106bool flag2 = false; 107 108byte baudSet; 109byte baudNum = 1; 110byte baudSetOld; 111 112const char noteNames[12] = {'C', 'C', 'D', 'D', 'E', 'F', 'F', 'G', 'G', 'A', 'A', 'B'}; 113const char noteNames2[12] = {' ', '#', ' ', '#', ' ', ' ', '#', ' ', '#', ' ', '#', ' '}; 114 115void setup() { 116 note1 = EEPROM.read(1); 117 note2 = EEPROM.read(2); 118 note3 = EEPROM.read(3); 119 note4 = EEPROM.read(4); 120 note5 = EEPROM.read(5); 121 velocity = EEPROM.read(6); 122 baudSet = EEPROM.read(7); 123 124 note1Old = note1; 125 note2Old = note2; 126 note3Old = note3; 127 note4Old = note4; 128 note5Old = note5; 129 velocityOld = velocity; 130 baudSetOld = baudSet; 131 132 pinMode(encoder0PinA, INPUT_PULLUP); 133 pinMode(encoder0PinB, INPUT_PULLUP); 134 pinMode(clk, INPUT_PULLUP); 135 136 pinMode(5, INPUT_PULLUP); 137 pinMode(6, INPUT_PULLUP); 138 pinMode(7, INPUT_PULLUP); 139 pinMode(8, INPUT_PULLUP); 140 pinMode(10, INPUT_PULLUP); 141 142 attachInterrupt(0, doEncoder, CHANGE); // encoder pin on interrupt 0 - pin 2 143 if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3D for 128x64 144 Serial.println(F("SSD1306 allocation failed")); 145 for (;;); // Don't proceed, loop forever 146 } 147 display.clearDisplay(); 148 display.setRotation(2); 149 display.setTextSize(2); 150 display.setCursor(0, 0); 151 152 pinMode( rxPin, INPUT_PULLUP ); 153 pinMode( txPin, OUTPUT); 154 155 if (baudSet == 1) { 156 Serial.begin(115200); 157 } 158 if (baudSet == 2) { 159 Serial.begin(31250); 160 } 161 162} 163 164void loop() { 165 if (selectedVal != oldVal || yVals != yValsOld || xVals != yValsOld) { 166 display.clearDisplay(); 167 oldVal = selectedVal; 168 yValsOld = yVals; 169 xValsOld = xVals; 170 valKeep(); 171 } 172 173 buttonCheck(); 174 175 if (digitalRead(10) == LOW) { 176 b5Val = noteON; 177 } else { 178 b5Val = noteOFF; 179 } 180 if (digitalRead(8) == LOW) { 181 b1Val = noteON; 182 } else { 183 b1Val = noteOFF; 184 } 185 if (digitalRead(7) == LOW) { 186 b2Val = noteON; 187 } else { 188 b2Val = noteOFF; 189 } 190 if (digitalRead(6) == LOW) { 191 b3Val = noteON; 192 } else { 193 b3Val = noteOFF; 194 } 195 if (digitalRead(5) == LOW) { 196 b4Val = noteON; 197 } else { 198 b4Val = noteOFF; 199 } 200 201 //Joystick starts here------------------------ 202 xVal = analogRead(A6); 203 xVal = map(xVal, 0, 1023, 0, 127); 204 xVals = map(xVal, 127, 0, 121, 80); 205 206 yVal = analogRead(A7); 207 yVal = map(yVal, 0, 1023, 0, 127); 208 yVals = map(yVal, 127, 0, 0, 40); 209 //Joystick ends here-------------------------- 210 211 aVal = analogRead(A3); 212 aVal = map(aVal, 0, 1022, 0, 127); 213 aVals = map(aVal, 0, 127, 0, 70); 214 215 bVal = analogRead(A2); 216 bVal = map(bVal, 0, 1022, 0, 127); 217 bVals = map(bVal, 0, 127, 0, 70); 218 219 cVal = analogRead(A1); 220 cVal = map(cVal, 0, 1022, 0, 127); 221 cVals = map(cVal, 0, 127, 0, 70); 222 223 dVal = analogRead(A0); 224 dVal = map(dVal, 0, 1022, 0, 127); 225 dVals = map(dVal, 0, 127, 0, 70); 226 227 //-XY Plotter--------------------------- 228 display.drawRect(80, 0, 48, 48, WHITE); 229 display.setCursor(xVals, yVals); 230 display.println("."); 231 //-XY plotter ends---------------------- 232 //-Val Control-------------------------- 233 display.setTextSize(2); 234 display.setTextColor(WHITE); 235 if (ch < 6) { 236 237 //- Pot Val---------------------------- 238 display.drawRect(0, 16, 70, 6, WHITE); 239 display.fillRect(0, 16, aVals, 6, INVERSE); 240 //- Pot Val---------------------------- 241 display.drawRect(0, 24, 70, 6, WHITE); 242 display.fillRect(0, 24, bVals, 6, INVERSE); 243 //- Pot Val---------------------. 244 display.drawRect(0, 32, 70, 6, WHITE); 245 display.fillRect(0, 32, cVals, 6, INVERSE); 246 //- Pot Val---------------------. 247 display.drawRect(0, 40, 70, 6, WHITE); 248 display.fillRect(0, 40, dVals, 6, INVERSE); 249 250 display.setTextSize(2); 251 display.setCursor(0, 0); 252 display.println(ch); 253 display.setCursor(20, 0); 254 display.println(":"); 255 256 display.setCursor(40, 0); 257 display.println(selectedVal); 258 //-Val Control----------------------- 259 } else if (ch == 6) { 260 display.setTextSize(1); 261 display.setCursor(0, 0); 262 display.println("Velocity"); 263 264 display.setTextSize(2); 265 display.setCursor(0, 20); 266 display.println(velocity); 267 268 if (velocityOld == velocity) { 269 display.setTextSize(1); 270 display.setCursor(35, 30); 271 display.println("Saved"); 272 } else { 273 display.setTextSize(1); 274 display.setCursor(35, 30); 275 display.println("Unsaved"); 276 if (digitalRead(6) == LOW && digitalRead(5) == LOW) { 277 EEPROM.write(6, velocity); 278 delay(20); 279 velocityOld = velocity; 280 } 281 } 282 } else if (ch == 7) { 283 display.setTextSize(1); 284 display.setCursor(0, 0); 285 display.println("Button 1"); 286 display.setTextSize(2); 287 display.setCursor(0, 20); 288 display.println(note1); 289 290 display.setTextSize(1); 291 display.setCursor(35, 20); 292 display.println(noteNames[note1 % 12]); 293 display.setCursor(45, 20); 294 display.println(noteNames2[note1 % 12]); 295 //------------------------------------------------------------------------------- 296 if (note1Old == note1) { 297 display.setTextSize(1); 298 display.setCursor(35, 30); 299 display.println("Saved"); 300 } else { 301 display.setTextSize(1); 302 display.setCursor(35, 30); 303 display.println("Unsaved"); 304 if (digitalRead(6) == LOW && digitalRead(5) == LOW) { 305 EEPROM.write(1, note1); 306 delay(20); 307 note1Old = note1; 308 } 309 } 310 //------------------------------------------------------------------------------ 311 } else if (ch == 8) { 312 display.setTextSize(1); 313 display.setCursor(0, 0); 314 display.println("Button 2"); 315 display.setTextSize(2); 316 display.setCursor(0, 20); 317 display.println(note2); 318 319 display.setTextSize(1); 320 display.setCursor(35, 20); 321 display.println(noteNames[note2 % 12]); 322 display.setCursor(45, 20); 323 display.println(noteNames2[note2 % 12]); 324 325 if (note2Old == note2) { 326 display.setTextSize(1); 327 display.setCursor(35, 30); 328 display.println("Saved"); 329 } else { 330 display.setTextSize(1); 331 display.setCursor(35, 30); 332 display.println("Unsaved"); 333 if (digitalRead(6) == LOW && digitalRead(5) == LOW) { 334 EEPROM.write(2, note2); 335 delay(20); 336 note2Old = note2; 337 } 338 } 339 } else if (ch == 9) { 340 display.setTextSize(1); 341 display.setCursor(0, 0); 342 display.println("Button 3"); 343 display.setTextSize(2); 344 display.setCursor(0, 20); 345 display.println(note3); 346 347 display.setTextSize(1); 348 display.setCursor(35, 20); 349 display.println(noteNames[note3 % 12]); 350 display.setCursor(45, 20); 351 display.println(noteNames2[note3 % 12]); 352 353 if (note3Old == note3) { 354 display.setTextSize(1); 355 display.setCursor(35, 30); 356 display.println("Saved"); 357 } else { 358 display.setTextSize(1); 359 display.setCursor(35, 30); 360 display.println("Unsaved"); 361 if (digitalRead(6) == LOW && digitalRead(5) == LOW) { 362 EEPROM.write(3, note3); 363 delay(20); 364 note3Old = note3; 365 } 366 } 367 } else if (ch == 10) { 368 display.setTextSize(1); 369 display.setCursor(0, 0); 370 display.println("Button 4"); 371 display.setTextSize(2); 372 display.setCursor(0, 20); 373 display.println(note4); 374 375 display.setTextSize(1); 376 display.setCursor(35, 20); 377 display.println(noteNames[note4 % 12]); 378 display.setCursor(45, 20); 379 display.println(noteNames2[note4 % 12]); 380 381 if (note4Old == note4) { 382 display.setTextSize(1); 383 display.setCursor(35, 30); 384 display.println("Saved"); 385 } else { 386 display.setTextSize(1); 387 display.setCursor(35, 30); 388 display.println("Unsaved"); 389 if (digitalRead(6) == LOW && digitalRead(5) == LOW) { 390 EEPROM.write(4, note4); 391 delay(20); 392 note4Old = note4; 393 } 394 } 395 } else if (ch == 11) { 396 display.setTextSize(1); 397 display.setCursor(0, 0); 398 display.println("Button 5"); 399 display.setTextSize(2); 400 display.setCursor(0, 20); 401 display.println(note5); 402 403 display.setTextSize(1); 404 display.setCursor(35, 20); 405 display.println(noteNames[note5 % 12]); 406 display.setCursor(45, 20); 407 display.println(noteNames2[note5 % 12]); 408 409 if (note5Old == note5) { 410 display.setTextSize(1); 411 display.setCursor(35, 30); 412 display.println("Saved"); 413 } else { 414 display.setTextSize(1); 415 display.setCursor(35, 30); 416 display.println("Unsaved"); 417 if (digitalRead(6) == LOW && digitalRead(5) == LOW) { 418 EEPROM.write(5, note5); 419 delay(20); 420 note5Old = note5; 421 } 422 } 423 } else if (ch == 12) { 424 display.setTextSize(1); 425 display.setCursor(0, 0); 426 display.println("Output"); 427 display.setTextSize(2); 428 429 display.setCursor(0, 20); 430 431 if (baudNum > 10) { 432 display.println("USB"); 433 baudSet = 1; 434 } else { 435 display.println("MIDI"); 436 baudSet = 2; 437 } 438 439 if (baudSet == baudSetOld) { 440 display.setTextSize(1); 441 display.setCursor(35, 30); 442 display.println("Saved"); 443 } else { 444 display.setTextSize(1); 445 display.setCursor(35, 30); 446 display.println("Unsaved"); 447 if (digitalRead(6) == LOW && digitalRead(5) == LOW) { 448 EEPROM.write(7, baudSet); 449 delay(20); 450 baudSetOld = baudSet; 451 } 452 } 453 } 454 //Velocity Value View 455 display.setTextSize(1); 456 display.setCursor(70, 50); 457 display.println("V:"); 458 display.setCursor(80, 50); 459 display.println(velocity); 460 //Output view 461 display.setCursor(102, 50); 462 if (baudSet == 1) { 463 display.println("USB"); 464 } else { 465 display.println("MIDI"); 466 } 467 468 //-Enable Disable Control------- 469 display.setCursor(0, 50); 470 471 if (enabled == false) { 472 flag1 = false; 473 474 if (flag2 == false) 475 { 476 tone(3, 440, 100); 477 flag2 = true; 478 } 479 480 display.println("Edit"); 481 countLimit = 12; 482 flag1 = false; 483 484 //Octave Control ------------------------ 485 if (digitalRead(8) == LOW) { 486 octave = 0; 487 octaveBank = 'A'; 488 } 489 if (digitalRead(7) == LOW) { 490 octave = 12; 491 octaveBank = 'B'; 492 } 493 if (digitalRead(6) == LOW) { 494 octave = 24; 495 octaveBank = 'C'; 496 } 497 if (digitalRead(5) == LOW) { 498 octave = 36; 499 octaveBank = 'D'; 500 } 501 //Octave Control-------------------------- 502 503 //Enabled Section ------------- 504 } else if (enabled == true) { 505 countLimit = 5; 506 flag2 = false; 507 508 if (flag1 == false) 509 { 510 ch = 1; 511 tone(3, 880, 100); 512 flag1 = true; 513 } 514 //Enable Section End----------- 515 516 display.println("Run!"); 517 midiMsg(); 518 } 519 520 display.setCursor(30, 50); 521 display.println("Bank:"); 522 display.setCursor(60, 50); 523 display.println(octaveBank); 524 display.display(); 525} 526 527void MIDImessage(byte command, byte data1, byte data2) 528{ 529 Serial.write(command); 530 Serial.write(data1); 531 Serial.write(data2); 532 533} 534 535void midiMsg() { 536 if (val1 != val1Last) // If the value does not = the last value the following command is made. This is because the pot has been turned. Otherwise the pot remains the same and no midi message is output. 537 { 538 MIDImessage(176, 1, val1); 539 } // 176 = CC command (channel 1 control change), 1 = Which Control, val = value read from Potentionmeter 1 NOTE THIS SAYS VAL not VA1 (lowercase of course) 540 val1Last = val1; 541 //--- 542 if (val2 != val2Last) 543 { 544 MIDImessage(176, 2, val2); 545 } 546 val2Last = val2; 547 //--- 548 if (val3 != val3Last) 549 { 550 MIDImessage(176, 3, val3); 551 } 552 val3Last = val3; 553 //--- 554 if (val4 != val4Last) 555 { 556 MIDImessage(176, 4, val4); 557 } 558 val4Last = val4; 559 //--- 560 if (val5 != val5Last) 561 { 562 MIDImessage(176, 5, val5); 563 } 564 val5Last = val5; 565 //--- 566 567 //--X Y Value to MIDI------------------------------ 568 if (xVal != xValLast) 569 { 570 MIDImessage(176, 11, xVal); 571 } 572 xValLast = xVal; 573 //------------------ 574 if (yVal != yValLast) 575 { 576 MIDImessage(176, 12, yVal); 577 } 578 yValLast = yVal; 579 580 //------------------ 581 if (aVal != aValLast) 582 { 583 MIDImessage(176, 13, aVal); 584 } 585 aValLast = aVal; 586 //------------------ 587 if (bVal != bValLast) 588 { 589 MIDImessage(176, 14, bVal); 590 } 591 bValLast = bVal; 592 //------------------ 593 if (cVal != cValLast) 594 { 595 MIDImessage(176, 15, cVal); 596 } 597 cValLast = cVal; 598 //------------------ 599 if (dVal != dValLast) 600 { 601 MIDImessage(176, 16, dVal); 602 } 603 dValLast = dVal; 604 //Button Section ------------------------------------- 605 if (b1Val != b1ValLast) 606 { 607 MIDImessage(b1Val, note1 + octave, velocity); 608 } 609 b1ValLast = b1Val; 610 611 if (b2Val != b2ValLast) 612 { 613 MIDImessage(b2Val, note2 + octave, velocity); 614 } 615 b2ValLast = b2Val; 616 617 if (b3Val != b3ValLast) 618 { 619 MIDImessage(b3Val, note3 + octave, velocity); 620 } 621 b3ValLast = b3Val; 622 623 if (b4Val != b4ValLast) 624 { 625 MIDImessage(b4Val, note4 + octave, velocity); 626 } 627 b4ValLast = b4Val; 628 629 if (b5Val != b5ValLast) 630 { 631 MIDImessage(b5Val, note5 + octave, velocity); 632 } 633 b5ValLast = b5Val; 634} 635 636void buttonCheck() { 637 if (digitalRead(clk) == LOW) { 638 if (buttonActive == false) { 639 buttonActive = true; 640 buttonTimer = millis(); 641 } 642 if ((millis() - buttonTimer > longPressTime) && (longPressActive == false)) { 643 longPressActive = true; 644 enabled = !enabled; 645 } 646 } else { 647 if (buttonActive == true) { 648 if (longPressActive == true) { 649 longPressActive = false; 650 } else { 651 652 if (ch < countLimit) { 653 ch++; 654 display.clearDisplay(); 655 } else { 656 ch = 1; 657 display.clearDisplay(); 658 } 659 valGet(); 660 inc = selectedVal; 661 } 662 buttonActive = false; 663 } 664 } 665} 666 667void valGet() { 668 switch (ch) { 669 case 1: 670 selectedVal = val1; 671 break; 672 case 2: 673 selectedVal = val2; 674 break; 675 case 3: 676 selectedVal = val3; 677 break; 678 case 4: 679 selectedVal = val4; 680 break; 681 case 5: 682 selectedVal = val5; 683 break; 684 case 6: 685 selectedVal = velocity; 686 break; 687 case 7: 688 selectedVal = note1; 689 break; 690 case 8: 691 selectedVal = note2; 692 break; 693 case 9: 694 selectedVal = note3; 695 break; 696 case 10: 697 selectedVal = note4; 698 break; 699 case 11: 700 selectedVal = note5; 701 break; 702 case 12: 703 selectedVal = baudNum; 704 break; 705 } 706} 707 708void valKeep() { 709 switch (ch) { 710 case 1: 711 val1 = selectedVal; 712 break; 713 case 2: 714 val2 = selectedVal; 715 break; 716 case 3: 717 val3 = selectedVal; 718 break; 719 case 4: 720 val4 = selectedVal; 721 break; 722 case 5: 723 val5 = selectedVal; 724 break; 725 case 6: 726 velocity = selectedVal; 727 break; 728 case 7: 729 note1 = selectedVal; 730 break; 731 case 8: 732 note2 = selectedVal; 733 break; 734 case 9: 735 note3 = selectedVal; 736 break; 737 case 10: 738 note4 = selectedVal; 739 break; 740 case 11: 741 note5 = selectedVal; 742 break; 743 case 12: 744 baudNum = selectedVal; 745 break; 746 } 747} 748void doEncoder() 749{ 750 if (digitalRead(encoder0PinA) == digitalRead(encoder0PinB)) 751 { 752 if (selectedVal < 127) { 753 inc = inc + 0.5; 754 } 755 } 756 else 757 { 758 if (selectedVal > 0) { 759 inc = inc - 0.5; 760 } 761 } 762 selectedVal = inc; 763}
Comments
Only logged in users can leave comments