Components and supplies
Arduino Micro
Project description
Code
ard-mididrum.ino
arduino
6 inputs MIDI interface for drums and pedals
1/* 2 * ard-mididrum.ino 3 * 4 * MIDI interface for 6 inputs as drum pads 'mono' (variable/analog from piezo sensor) with velocity value 5 * and for pedals 'stereo' ("expression" type with potentiometer inside) 6 * and for pedals 'mono' ("sustain" type with a switch inside NA or NC) 7 * 8 * it uses Arduino Micro, USB port as MIDI-OUT device, OLED 128x64 display (setup and monitor), 9 * rotary encoder + button for setup menu and options, 6 dimmable leds to monitor 6 inputs activity, 10 * MIDI-OUT serial port; parameters are memorized in the MPU EEPROM; 11 * 12 * 13 * by Marco Zonca 8-12/2020 14 * 15*/ 16 17/*table 18 * 19 * octave note pitchNr 20 * ------------------- 21 * -2 C 0 22 * -2 C# 1 23 * -2 D 2 24 * -2 D# 3 25 * -2 E 4 26 * -2 F 5 27 * -2 F# 6 28 * -2 G 7 29 * -2 G# 8 30 * -2 A 9 31 * -2 A# 10 32 * -2 B 11 33 * 34 * ...the same for the other octaves... 35 * 36 * octave note pitchNr 37 * ------------------- 38 * -1 (C-B) 12-23 39 * 0 (C-B) 24-35 40 * 1 (C-B) 36-47 41 * 2 (C-B) 48-59 42 * 3 (C-B) 60-71 43 * 4 (C-B) 72-83 44 * 5 (C-B) 84-95 45 * 6 (C-B) 96-107 46 * 7 (C-B) 108-119 47 * 8 (C-G) 120-127 48 * 49 * PitchNr [0 to 127] 50 * Octave = ((int(PitchNr / 12)) - 2) [-2 to 8] 51 * Note-Number = (PitchNr-((Octave+2)*12) + 1) [1 to 12] 52 * 53 * ---------------------- 54 * for pitchNr the maximum is 127 55 * for controlNr the maximum is 119 56 * 57*/ 58 59#include "MIDIUSB.h" 60#include <Wire.h> 61#include <Adafruit_GFX.h> 62#include <Adafruit_SSD1306.h> 63#include <EEPROM.h> 64 65#define NUM_INPUTS 6 66#define NUM_VALUES 9 67#define IS_DEBUG false 68 69Adafruit_SSD1306 display = Adafruit_SSD1306(128, 64, &Wire); 70 71// drums or pedals 72const uint8_t input1 = 18; // A0 73const uint8_t input2 = 19; // A1 74const uint8_t input3 = 20; // A2 75const uint8_t input4 = 21; // A3 76const uint8_t input5 = 22; // A4 77const uint8_t input6 = 23; // A5 78 79// leds 80const int led1Pin = 13; 81const int led2Pin = 11; 82const int led3Pin = 10; 83const int led4Pin = 9; 84const int led5Pin = 6; 85const int led6Pin = 5; 86const byte on = 255; 87const byte off = 0; 88 89const uint8_t inputs[NUM_INPUTS] = {input1, input2, input3, input4, input5, input6}; 90const uint8_t leds[NUM_INPUTS] = {led1Pin, led2Pin, led3Pin, led4Pin, led5Pin, led6Pin}; 91uint8_t prevValue[NUM_INPUTS] = {0, 0, 0, 0, 0, 0}; 92 93byte APitch = 48; 94int AOctave = (int(APitch/12)-2); 95byte ANote = (APitch-((AOctave+2)*12) + 1); 96char tableNotes[41] = "C C# D D# E F F# G G# A A# B "; 97char atext[31]=""; 98char apark[31]=""; 99 100uint8_t drum_velocity = 0; 101uint8_t velocity = 0; 102uint8_t controlvalue = 0; 103bool drum_isPressed = false; 104 105uint8_t bType[NUM_INPUTS] = {1, 1, 1, 1, 2, 3}; // 1=piezo drum 2=switch pedal 3=trimmer pedal (default setting) 106 107int KNOBinterval = 4000; // m/sec to enter Menu 108int KNOBmenuInterval = 1000; // m/sec to navigate Menu 109 110// rotary encoder 111int menuPin = 4; 112int encoderPin1 = 7; 113int encoderPin2 = 12; 114volatile int lastEncoded = 0; 115volatile long encoderValue = 0; 116volatile long encoderPrev = 0; 117volatile boolean IsMenu = false; 118volatile long lastencoderValue = 0; 119volatile int lastMSB = 0; 120volatile int lastLSB = 0; 121volatile int knob = 0; 122volatile byte preknob = 1; 123unsigned long prevKNOBmillis = 0; 124byte menuLevel=0; // 0-2 125byte menu_L0_Input=0; // 0-6 0=exit 126byte menu_L1_Voice=0; // 0-9 0=back 127byte menu_L2_Value=0; // 0-127 128byte menu_memory[NUM_INPUTS][NUM_VALUES]; 129 130 131/* Voices 0:Type 1=piezo/drum 2=switch/pedal 3=trimmer/pedal 132 * 1:Reverse 0=no 1=yes (only pedals) 133 * 2:Channel 1-16 134 * 3:PitchNr 0-127 (only drums) 135 * 4:Len 5-95 m/sec (only drums) 136 * 5:Min 0-63 137 * 6:Max 64-127 138 * 7:AntiBouncing 0-63 (only pedals) 139 * 8:ControlNr 0-119 (only pedals) 140 * 141 */ 142 143const byte menu_L2_Value_piezo_min[NUM_VALUES]= { 1, 255, 1, 0, 5, 0, 64, 255, 255}; // 255=not used 144const byte menu_L2_Value_piezo_max[NUM_VALUES]= { 3, 255, 16, 127, 95, 63, 127, 255, 255}; 145const byte menu_L2_Value_piezo_def[NUM_VALUES]= { 1, 255, 1, 48, 50, 30, 100, 255, 255}; 146const byte menu_L2_Value_switch_min[NUM_VALUES]= { 1, 0, 1, 255, 255, 0, 64, 0, 0}; 147const byte menu_L2_Value_switch_max[NUM_VALUES]= { 3, 1, 16, 255, 255, 63, 127, 63, 119}; 148const byte menu_L2_Value_switch_def[NUM_VALUES]= { 2, 1, 1, 255, 255, 0, 70, 60, 102}; 149const byte menu_L2_Value_trimmer_min[NUM_VALUES]={ 1, 0, 1, 255, 255, 0, 64, 0, 0}; 150const byte menu_L2_Value_trimmer_max[NUM_VALUES]={ 3, 1, 16, 255, 255, 63, 127, 63, 119}; 151const byte menu_L2_Value_trimmer_def[NUM_VALUES]={ 3, 0, 1, 255, 255, 0, 90, 2, 103}; 152const byte mId1=0xF1; 153const byte mId2=0xF2; 154 155void setup() { 156 int mAdr=0; 157 byte a=0; 158 byte b=0; 159 if (IS_DEBUG) Serial.begin(38400); 160 Serial1.begin(31250); // must be 31250 for MIDI standard 161 display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // Display Address 0x3C for 128x64 pixels 162 pinMode(encoderPin1, INPUT_PULLUP); 163 pinMode(encoderPin2, INPUT_PULLUP); 164 pinMode(menuPin, INPUT_PULLUP); 165 pinMode(led1Pin, OUTPUT); 166 pinMode(led2Pin, OUTPUT); 167 pinMode(led3Pin, OUTPUT); 168 pinMode(led4Pin, OUTPUT); 169 pinMode(led5Pin, OUTPUT); 170 pinMode(led6Pin, OUTPUT); 171 172 mAdr=0; // read EEPROM first 2 ID bytes and load, if necessary, all default parameters 173 if (EEPROM.read(mAdr) != mId1 || EEPROM.read(mAdr+1) != mId2) { 174 for (a=0;a<NUM_INPUTS;a++) { 175 loadDefaults(a, bType[a]); 176 }//for a 177 updateMemory(); 178 } else { 179 for (a=0;a<NUM_INPUTS;a++) { // read EEPROM 54 bytes (addr=2to55) 180 for (b=0;b<NUM_VALUES;b++) { 181 mAdr=(2+(a*9))+b; 182 menu_memory[a][b]=EEPROM.read(mAdr); 183 } 184 } 185 }//if EEPROM.read() 186 187 for (byte i=0;i<NUM_INPUTS;i++) { // pullup for switches 188 switch (menu_memory[i][0]) { //0=type 189 case 1: // drum 190 break; 191 case 2: // switch 192 pinMode(inputs[i], INPUT_PULLUP); 193 break; 194 case 3: // trimmer 195 break; 196 }//switch 197 }//for i 198 199 for (int i=1;i<=NUM_INPUTS;i++) { // leds show 200 if (i>1) { analogWrite(leds[i-2], off); } 201 analogWrite(leds[i-1], on); 202 delay(200); 203 } 204 analogWrite(leds[5], off); 205 206 showNormalDisplay(); 207}//setup() 208 209 210void loop() { 211 if (IsMenu==false) { 212 for (byte i=0;i<NUM_INPUTS;i++) { // ----------------- work on inputs 213 switch (menu_memory[i][0]) { //0=type 214 case 1: // drum 215 readDrum(i); 216 break; 217 case 2: // switch 218 readSwitch(i); 219 break; 220 case 3: // trimmer 221 readTrimmer(i); 222 break; 223 } //switch 224 } // for i 225 if ((prevKNOBmillis+KNOBinterval) < millis()) { // ---- check menu 226 if (digitalRead(menuPin) == LOW) { 227 IsMenu=true; 228 menuLevel=0; 229 menu_L0_Input=0; 230 if (IS_DEBUG) Serial.println("menu level 0 (input nr 0-6)"); 231 display.clearDisplay(); 232 printAt(2,2,false,"SETUP: type:"); 233 printAt(2,4,false,"rev: min :"); 234 printAt(2,5,false,"ch : max :"); 235 printAt(2,6,false,"ctr: note:"); 236 printAt(2,7,false,"len: abnc:"); 237 displayChoices(); 238 display.display(); 239 } 240 prevKNOBmillis=millis(); 241 } 242 } else { 243 updateEncoder(); 244 } // if IsMenu() 245} // loop() 246 247void showNormalDisplay() { //normal display 248 display.clearDisplay(); 249 display.setTextSize(2); 250 display.setTextColor(SSD1306_WHITE); 251 display.setCursor(0,0); 252 display.println("Z-MIDI 6dp"); 253 printAt(1,4,false,"Press knob for setup"); 254 printAt(1,6,true,"P T CH RAW VAL NT/CC"); 255 display.display(); 256} 257 258void loadDefaults(byte PortNr, byte PortType) { 259 byte a=0; 260 byte b=0; 261 a=PortNr; 262 switch (PortType) { 263 case 1: 264 for (b=0;b<NUM_VALUES;b++) { 265 menu_memory[a][b]=menu_L2_Value_piezo_def[b]; 266 } 267 break; 268 case 2: 269 for (b=0;b<NUM_VALUES;b++) { 270 menu_memory[a][b]=menu_L2_Value_switch_def[b]; 271 } 272 break; 273 case 3: 274 for (b=0;b<NUM_VALUES;b++) { 275 menu_memory[a][b]=menu_L2_Value_trimmer_def[b]; 276 } 277 break; 278 }//switch(a) 279}//loadDefaults() 280 281void updateMemory() { 282 int mAdr=0; 283 byte a=0; 284 byte b=0; 285 EEPROM.update(0,mId1); 286 EEPROM.update(1,mId2); 287 for (a=0;a<NUM_INPUTS;a++) { // update EEPROM 54 bytes (addr=2to55) 288 for (b=0;b<NUM_VALUES;b++) { 289 mAdr=(2+(a*9))+b; 290 EEPROM.update(mAdr,menu_memory[a][b]); 291 } 292 } 293} 294 295void displayChoices() { // live display during navigating inside menu 296 switch (menuLevel) { 297 case 0: 298 if (knob==0) { 299 printAt(9,2,true,"exit"); 300 } else { 301 sprintf(atext,"%-4d",knob); 302 printAt(9,2,true,atext); 303 } 304 break; 305 case 1: 306 if (menu_L0_Input==0) { 307 printAt(9,2,false,"exit"); 308 } else { 309 sprintf(atext,"%-4d",menu_L0_Input); 310 printAt(9,2,false,atext); 311 } 312 if (menu_memory[menu_L0_Input-1][1-1]==1) { // ------------- 1=drum 313 sprintf(atext,"%d",menu_memory[menu_L0_Input-1][1-1]); 314 printAt(20,2,false,atext); 315 printAt(7,4,false,"-"); 316 sprintf(atext,"%-2d ",menu_memory[menu_L0_Input-1][6-1]); 317 printAt(17,4,false,atext); 318 sprintf(atext,"%-2d",menu_memory[menu_L0_Input-1][3-1]); 319 printAt(7,5,false,atext); 320 sprintf(atext,"%-3d",menu_memory[menu_L0_Input-1][7-1]); 321 printAt(17,5,false,atext); 322 printAt(7,6,false,"---"); 323 APitch = menu_memory[menu_L0_Input-1][4-1]; 324 AOctave = ((int(APitch / 12)) - 2); 325 ANote = (APitch-((AOctave+2)*12) + 1); 326 s_substring(apark, sizeof(atext), tableNotes, sizeof(tableNotes), (ANote-1) * 3, ((ANote-1) * 3)+1); 327 sprintf(atext,"%s/%+1d",apark, AOctave); 328 printAt(17,6,false,atext); 329 sprintf(atext,"%-2d",menu_memory[menu_L0_Input-1][5-1]); 330 printAt(7,7,false,atext); 331 printAt(17,7,false,"--"); 332 } else { // ---------------------------------------------- 2=switch 3=trimmer 333 sprintf(atext,"%d",menu_memory[menu_L0_Input-1][1-1]); 334 printAt(20,2,false,atext); 335 if (menu_memory[menu_L0_Input-1][2-1]==0) { // reverse 336 printAt(7,4,false,"N"); 337 } else { 338 printAt(7,4,false,"Y"); 339 } 340 sprintf(atext,"%-2d",menu_memory[menu_L0_Input-1][6-1]); 341 printAt(17,4,false,atext); 342 sprintf(atext,"%-2d",menu_memory[menu_L0_Input-1][3-1]); 343 printAt(7,5,false,atext); 344 sprintf(atext,"%-3d",menu_memory[menu_L0_Input-1][7-1]); 345 printAt(17,5,false,atext); 346 sprintf(atext,"%-3d",menu_memory[menu_L0_Input-1][9-1]); 347 printAt(7,6,false,atext); 348 printAt(17,6,false,"--/--"); 349 printAt(7,7,false,"--"); 350 sprintf(atext,"%-2d",menu_memory[menu_L0_Input-1][8-1]); 351 printAt(17,7,false,atext); 352 } 353 printAt(8,2,false," "); // clear pointers ">" 354 printAt(19,2,false," "); 355 printAt(6,4,false," "); 356 printAt(6,5,false," "); 357 printAt(16,6,false," "); 358 printAt(6,7,false," "); 359 printAt(16,4,false," "); 360 printAt(16,5,false," "); 361 printAt(16,7,false," "); 362 printAt(6,6,false," "); 363 switch(knob) { // new pointer ">" 364 case 0: 365 printAt(8,2,false,">"); 366 break; 367 case 1: 368 printAt(19,2,false,">"); 369 break; 370 case 2: 371 printAt(6,4,false,">"); 372 break; 373 case 3: 374 printAt(6,5,false,">"); 375 break; 376 case 4: 377 printAt(16,6,false,">"); 378 break; 379 case 5: 380 printAt(6,7,false,">"); 381 break; 382 case 6: 383 printAt(16,4,false,">"); 384 break; 385 case 7: 386 printAt(16,5,false,">"); 387 break; 388 case 8: 389 printAt(16,7,false,">"); 390 break; 391 case 9: 392 printAt(6,6,false,">"); 393 break; 394 }//switch(knob) 395 break; 396 case 2: 397 switch(menu_L1_Voice) { // print new voice's value 398 case 0: 399 break; 400 case 1: 401 sprintf(atext,"%d",knob); 402 printAt(20,2,true,atext); 403 break; 404 case 2: 405 if (knob==0) { // reverse 406 printAt(7,4,true,"N"); 407 } else { 408 printAt(7,4,true,"Y"); 409 } 410 break; 411 case 3: 412 sprintf(atext,"%-2d",knob); 413 printAt(7,5,true,atext); 414 break; 415 case 4: 416 APitch = knob; 417 AOctave = ((int(APitch / 12)) - 2); 418 ANote = (APitch-((AOctave+2)*12) + 1); 419 s_substring(apark, sizeof(atext), tableNotes, sizeof(tableNotes), (ANote-1) * 3, ((ANote-1) * 3)+1); 420 sprintf(atext,"%s/%+1d",apark, AOctave); 421 printAt(17,6,true,atext); 422 break; 423 case 5: 424 sprintf(atext,"%-2d",knob); 425 printAt(7,7,true,atext); 426 break; 427 case 6: 428 sprintf(atext,"%-2d",knob); 429 printAt(17,4,true,atext); 430 break; 431 case 7: 432 sprintf(atext,"%-3d",knob); 433 printAt(17,5,true,atext); 434 break; 435 case 8: 436 sprintf(atext,"%-2d",knob); 437 printAt(17,7,true,atext); 438 break; 439 case 9: 440 sprintf(atext,"%-3d",knob); 441 printAt(7,6,true,atext); 442 break; 443 }//switch(menu_L1_Voice) 444 break; 445 }//switch(menuLevel) 446} 447 448void updateEncoder() { // ---------------------------------- encoder menu 449 int MSB = digitalRead(encoderPin1); //MSB = most significant bit 450 int LSB = digitalRead(encoderPin2); //LSB = least significant bit 451 int encoded = (MSB << 1) |LSB; //converting the 2 pin value to single number 452 int sum = (lastEncoded << 2) | encoded; //adding it to the previous encoded value 453 if(sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011) encoderValue ++; 454 if(sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000) encoderValue --; 455 lastEncoded = encoded; //store this value for next time 456 if ((encoderValue - encoderPrev) > 8) { // ------------------ right turn, clockwise ++ 457 knob ++; 458 if (menuLevel==0) if (knob>NUM_INPUTS) knob=0; 459 if (menuLevel==1) if (knob>9) knob=0; 460 if (menuLevel==1) if (knob==2) if (menu_memory[menu_L0_Input-1][1-1]==1) knob=3; // jump n.2 if drum 461 if (menuLevel==1) if (knob==8) if (menu_memory[menu_L0_Input-1][1-1]==1) knob=0; // jump n.8 if drum 462 if (menuLevel==1) if (knob==9) if (menu_memory[menu_L0_Input-1][1-1]==1) knob=0; // jump n.9 if drum 463 if (menuLevel==1) if (knob==4) if (menu_memory[menu_L0_Input-1][1-1]==2 || menu_memory[menu_L0_Input-1][1-1]==3) knob=6; // jump n.4 if pedal 464 if (menuLevel==1) if (knob==5) if (menu_memory[menu_L0_Input-1][1-1]==2 || menu_memory[menu_L0_Input-1][1-1]==3) knob=6; // jump n.5 if pedal 465 if (menuLevel==2) if (menu_memory[menu_L0_Input-1][1-1]==1) if (knob > menu_L2_Value_piezo_max[menu_L1_Voice-1]) knob=menu_L2_Value_piezo_min[menu_L1_Voice-1]; 466 if (menuLevel==2) if (menu_memory[menu_L0_Input-1][1-1]==2) if (knob > menu_L2_Value_switch_max[menu_L1_Voice-1]) knob=menu_L2_Value_switch_min[menu_L1_Voice-1]; 467 if (menuLevel==2) if (menu_memory[menu_L0_Input-1][1-1]==3) if (knob > menu_L2_Value_trimmer_max[menu_L1_Voice-1]) knob=menu_L2_Value_trimmer_min[menu_L1_Voice-1]; 468 if (menuLevel==2) if (menu_L1_Voice==1) loadDefaults((menu_L0_Input-1),knob); // load defaults if changing PortType 469 encoderPrev=encoderValue; 470 displayChoices(); 471 display.display(); 472 if (IS_DEBUG) Serial.println(knob); 473 } 474 if ((encoderValue - encoderPrev) < -8) { // ------------------ left turn, anticlockwise -- 475 knob --; 476 if (menuLevel==0) if (knob<0) knob=NUM_INPUTS; 477 if (menuLevel==1) if (knob<0) knob=9; 478 if (menuLevel==1) if (knob==2) if (menu_memory[menu_L0_Input-1][1-1]==1) knob=1; // jump n.2 if drum 479 if (menuLevel==1) if (knob==8) if (menu_memory[menu_L0_Input-1][1-1]==1) knob=7; // jump n.8 if drum 480 if (menuLevel==1) if (knob==9) if (menu_memory[menu_L0_Input-1][1-1]==1) knob=7; // jump n.9 if drum 481 if (menuLevel==1) if (knob==4) if (menu_memory[menu_L0_Input-1][1-1]==2 || menu_memory[menu_L0_Input-1][1-1]==3) knob=3; // jump n.4 if pedal 482 if (menuLevel==1) if (knob==5) if (menu_memory[menu_L0_Input-1][1-1]==2 || menu_memory[menu_L0_Input-1][1-1]==3) knob=3; // jump n.5 if pedal 483 if (menuLevel==2) if (menu_memory[menu_L0_Input-1][1-1]==1) if (knob < menu_L2_Value_piezo_min[menu_L1_Voice-1]) knob=menu_L2_Value_piezo_max[menu_L1_Voice-1]; 484 if (menuLevel==2) if (menu_memory[menu_L0_Input-1][1-1]==2) if (knob < menu_L2_Value_switch_min[menu_L1_Voice-1]) knob=menu_L2_Value_switch_max[menu_L1_Voice-1]; 485 if (menuLevel==2) if (menu_memory[menu_L0_Input-1][1-1]==3) if (knob < menu_L2_Value_trimmer_min[menu_L1_Voice-1]) knob=menu_L2_Value_trimmer_max[menu_L1_Voice-1]; 486 if (menuLevel==2) if (menu_L1_Voice==1) loadDefaults((menu_L0_Input-1),knob); // load defaults if changing PortType 487 encoderPrev=encoderValue; 488 displayChoices(); 489 display.display(); 490 if (IS_DEBUG) Serial.println(knob); 491 } 492 if (((prevKNOBmillis+KNOBmenuInterval) < millis()) && (digitalRead(menuPin) == LOW)) { // pressed knob 493 switch (menuLevel) { 494 case 0: 495 if (knob==0) { // exit from menu 496 showNormalDisplay(); 497 updateMemory(); 498 IsMenu=false; 499 if (IS_DEBUG) Serial.println("menu off"); 500 } else { // chosen input nr 501 menuLevel=1; 502 menu_L0_Input=knob; 503 knob=0; 504 displayChoices(); 505 display.display(); 506 if (IS_DEBUG) Serial.print("chosen: "); 507 if (IS_DEBUG) Serial.print(menu_L0_Input); 508 if (IS_DEBUG) Serial.println(", menu level 1 (voice 0-9)"); 509 } 510 break; 511 case 1: 512 if (knob==0) { // back previous level 0 513 menuLevel=0; 514 knob=menu_L0_Input; 515 displayChoices(); 516 display.display(); 517 if (IS_DEBUG) Serial.println("back menu level 0 (input nr 0-6)"); 518 } else { // chosen voice 519 menuLevel=2; 520 menu_L1_Voice=knob; 521 knob=menu_memory[menu_L0_Input-1][menu_L1_Voice-1]; // propose value in memory 522 displayChoices(); 523 display.display(); 524 if (IS_DEBUG) Serial.print("chosen: "); 525 if (IS_DEBUG) Serial.print(menu_L1_Voice); 526 if (IS_DEBUG) Serial.println(", menu level 2 (VALUE 0-127)"); 527 } 528 break; 529 case 2: 530 menuLevel=1; // save value & back previous level 1 531 menu_L2_Value=knob; 532 menu_memory[menu_L0_Input-1][menu_L1_Voice-1]=menu_L2_Value; 533 knob=menu_L1_Voice; 534 displayChoices(); 535 display.display(); 536 if (IS_DEBUG) Serial.print("chosen: "); 537 if (IS_DEBUG) Serial.print(menu_L2_Value); 538 if (IS_DEBUG) Serial.println(", save VALUE & back level 1 (voice 0-9)"); 539 break; 540 } // switch menuLevel 541 prevKNOBmillis=millis(); 542 } // if millis() 543} // updateEncoder() 544 545 546void printAt(const byte col, const byte row, const bool blackonwhite, const char thetext[31]) { // ------- printAt 547 // display: 21 col. x 8 row [setcursor(x,y)] x=(col-1)*6 y=(row-1)*8 548 // x=0,6,12,18,24,30,36,42,48,54,60,66,72,78,84,90,96,102,108,114,120 549 // y=0,8,16,24,32,40,48,56 550 display.setTextSize(1); 551 if (blackonwhite==true) { 552 display.setTextColor(SSD1306_BLACK, SSD1306_WHITE); // b/w 553 } else { 554 display.setTextColor(SSD1306_WHITE, SSD1306_BLACK); // normal 555 } 556 display.setCursor((col-1)*6,(row-1)*8); 557 display.print(thetext); 558} // printAt() 559 560 561void readSwitch(byte btnr) { // ---------------------------------- switch 562 int val = 0; 563 val = map(analogRead(inputs[btnr]), 0, 1023, 0, 127); 564 int raw = val; 565 if (val > menu_memory[btnr][6]) { //6=maxValue 566 val = menu_memory[btnr][6]; 567 } 568 if (val < menu_memory[btnr][5]) { //5=minValue 569 val = menu_memory[btnr][5]; 570 } 571 controlvalue = map(val, menu_memory[btnr][5], menu_memory[btnr][6], 0, 127); // expand value 5=minValue 6=maxValue 572 if (controlvalue < (128/2)) { // .. off 573 if (menu_memory[btnr][1]==0) { //1=reverse 574 controlvalue=0; 575 } else { 576 controlvalue=127; 577 } 578 } else { // ....................... on 579 if (menu_memory[btnr][1]==0) { //1=reverse 580 controlvalue=127; 581 } else { 582 controlvalue=0; 583 } 584 } 585 if (controlvalue <= (prevValue[btnr]-menu_memory[btnr][7]) || controlvalue >= (prevValue[btnr]+menu_memory[btnr][7])) { //7=antibouncing 586 controlChange((menu_memory[btnr][2]-1), menu_memory[btnr][8], controlvalue); //8=controlNr 2=channel 587 588 if (IS_DEBUG) Serial.print(btnr+1); 589 if (IS_DEBUG) Serial.print(" "); 590 if (IS_DEBUG) Serial.print(menu_memory[btnr][2]); //2=channel 591 if (IS_DEBUG) Serial.print(" "); 592 if (IS_DEBUG) Serial.print(menu_memory[btnr][8]); //8=controlNr 593 if (IS_DEBUG) Serial.print(" "); 594 if (IS_DEBUG) Serial.print(raw); 595 if (IS_DEBUG) Serial.print(" "); 596 if (IS_DEBUG) Serial.println(controlvalue); 597 598 sprintf(atext,"%d ",btnr+1); // live monitor 599 printAt(1,7,false,atext); 600 printAt(3,7,false,"S"); 601 sprintf(atext,"%d ",menu_memory[btnr][2]); //2=channel 602 printAt(5,7,false,atext); 603 sprintf(atext,"%d ",raw); 604 printAt(8,7,false,atext); 605 sprintf(atext,"%d ",controlvalue); 606 printAt(12,7,false,atext); 607 sprintf(atext,"%d ",menu_memory[btnr][8]); //8=controlNr 608 printAt(16,7,false,atext); 609 display.display(); 610 611 prevValue[btnr]=controlvalue; 612 analogWrite(leds[btnr], (controlvalue*2)); 613 } 614} // readSwitch() 615 616void readTrimmer(byte btnr) { // ---------------------------------- trimmer 617 int val = 0; 618 val = map(analogRead(inputs[btnr]), 0, 1023, 0, 127); 619 int raw = val; 620 if (val > menu_memory[btnr][6]) { //6=maxValue 621 val = menu_memory[btnr][6]; 622 } 623 if (val < menu_memory[btnr][5]) { //5=minValue 624 val = menu_memory[btnr][5]; 625 } 626 if (menu_memory[btnr][1]==0) { controlvalue = map(val, menu_memory[btnr][5], menu_memory[btnr][6], 0, 127);} // expand value if reverse=no 5=minValue 6=maxValue 627 if (menu_memory[btnr][1]==1) { controlvalue = map(val, menu_memory[btnr][5], menu_memory[btnr][6], 127, 0);} // expand value if reverse=yes 5=minValue 6=maxValue 628 if (controlvalue <= (prevValue[btnr]-menu_memory[btnr][7]) || controlvalue >= (prevValue[btnr]+menu_memory[btnr][7])) { //7=antibouncing 629 controlChange((menu_memory[btnr][2]-1), menu_memory[btnr][8], controlvalue); //8=controlNr 2=channel 630 631 if (IS_DEBUG) Serial.print(btnr+1); 632 if (IS_DEBUG) Serial.print(" "); 633 if (IS_DEBUG) Serial.print((menu_memory[btnr][2])); //2=channel 634 if (IS_DEBUG) Serial.print(" "); 635 if (IS_DEBUG) Serial.print(menu_memory[btnr][8]); //8=controlNr 636 if (IS_DEBUG) Serial.print(" "); 637 if (IS_DEBUG) Serial.print(raw); 638 if (IS_DEBUG) Serial.print(" "); 639 if (IS_DEBUG) Serial.println(controlvalue); 640 641 sprintf(atext,"%d ",btnr+1); // live monitor 642 printAt(1,7,false,atext); 643 printAt(3,7,false,"T"); 644 sprintf(atext,"%d ",menu_memory[btnr][2]); //2=channel 645 printAt(5,7,false,atext); 646 sprintf(atext,"%d ",raw); 647 printAt(8,7,false,atext); 648 sprintf(atext,"%d ",controlvalue); 649 printAt(12,7,false,atext); 650 sprintf(atext,"%d ",menu_memory[btnr][8]); //8=controlNr 651 printAt(16,7,false,atext); 652 display.display(); 653 654 prevValue[btnr]=controlvalue; 655 analogWrite(leds[btnr], (controlvalue*2)); 656 } 657} // readTrimmer() 658 659void readDrum(byte btnr) { // -------------------------------------- drum 660 int val=0; 661 val = map(analogRead(inputs[btnr]), 0, 1023, 0, 127); 662 int raw = val; 663 while (val >= menu_memory[btnr][5]) { //5=minValue as threshold 664 drum_isPressed = true; 665 if (val >= drum_velocity) { // take the peak of wave 666 drum_velocity=val; 667 } 668 val = map(analogRead(inputs[btnr]), 0, 1023, 0, 127); 669 }//while 670 if (drum_isPressed == true) { 671 if (drum_velocity > menu_memory[btnr][6]) { //6=maxValue 672 drum_velocity = menu_memory[btnr][6]; 673 } 674 velocity = map(drum_velocity, menu_memory[btnr][5], menu_memory[btnr][6], 1, 127); // expand velocity 5=minValue 6=maxValue 675 playNoteOn((menu_memory[btnr][2]-1), menu_memory[btnr][3], velocity); //3=pitchNr 2=channel 676 677 if (IS_DEBUG) Serial.print(btnr+1); 678 if (IS_DEBUG) Serial.print(" "); 679 if (IS_DEBUG) Serial.print((menu_memory[btnr][2])); //2=channel 680 if (IS_DEBUG) Serial.print(" "); 681 if (IS_DEBUG) Serial.print(menu_memory[btnr][3]); //3=pitchNr 682 if (IS_DEBUG) Serial.print(" "); 683 if (IS_DEBUG) Serial.print(raw); 684 if (IS_DEBUG) Serial.print(" "); 685 if (IS_DEBUG) Serial.print(velocity); 686 if (IS_DEBUG) Serial.print(" --> "); 687 688 sprintf(atext,"%d ",btnr+1); // live monitor 689 printAt(1,7,false,atext); 690 printAt(3,7,false,"P"); 691 sprintf(atext,"%d ",menu_memory[btnr][2]); //2=channel 692 printAt(5,7,false,atext); 693 sprintf(atext,"%d ",raw); 694 printAt(8,7,false,atext); 695 sprintf(atext,"%d ",velocity); 696 printAt(12,7,false,atext); 697 sprintf(atext,"%d ",menu_memory[btnr][3]); //3=pitchNr 698 APitch = menu_memory[btnr][3]; 699 AOctave = ((int(APitch / 12)) - 2); 700 ANote = (APitch-((AOctave+2)*12) + 1); 701 s_substring(apark, sizeof(atext), tableNotes, sizeof(tableNotes), (ANote-1) * 3, ((ANote-1) * 3)+1); 702 sprintf(atext,"%s/%d ",apark,AOctave); 703 printAt(16,7,false,atext); 704 display.display(); 705 706 if (IS_DEBUG) Serial.print(APitch); 707 if (IS_DEBUG) Serial.print(" "); 708 if (IS_DEBUG) Serial.print(AOctave); 709 if (IS_DEBUG) Serial.print(" "); 710 if (IS_DEBUG) Serial.print(ANote); 711 if (IS_DEBUG) Serial.print(" "); 712 if (IS_DEBUG) Serial.println(atext); 713 714 prevValue[btnr]=velocity; 715 drum_velocity=0; 716 drum_isPressed = false; 717 analogWrite(leds[btnr], (velocity*2)); 718 delay(menu_memory[btnr][4]); //4=timeinterval 719 analogWrite(leds[btnr], off); 720 } // if(drum1_isPressed) 721} // readDrum() 722 723 724// First parameter is the event type (0x0B = control change) 4 bits 725// Second parameter is the event type, combined with the channel, above 4 bits + channel 4 bits 726// Third parameter is the control number (0-119). 727// Fourth parameter is the control value (0-127). 728// -------------------------------------------------------------- 729void controlChange(byte channel, byte control, byte value) { 730 midiEventPacket_t midiCc = {0x0B, byte (0xB0 | channel), control, value}; 731 MidiUSB.sendMIDI(midiCc); // to USB MIDI 732 MidiUSB.flush(); 733 Serial1.write(0xB0 | channel); // to serial1 MIDI 734 Serial1.write(control); 735 Serial1.write(value); 736} 737 738// First parameter is the event type (0x09 = note on, 0x08 = note off) 4 bits 739// Second parameter is note-on/note-off, combined with the channel, above 4 bits + channel 4 bits 740// Channel between 0-15. Typically reported to the user as 1-16 741// Third parameter is the note number, the pitch, (48 = middle C). 742// Fourth parameter is the velocity (0 = none, 64 = normal, 127 = louder/faster). 743// -------------------------------------------------------------- 744void playNoteOn(byte channel, byte pitch, byte velocity) { 745 midiEventPacket_t noteOn = {0x09, byte (0x90 | channel), pitch, velocity}; 746 MidiUSB.sendMIDI(noteOn); // to USB MIDI 747 MidiUSB.flush(); 748 Serial1.write(0x90 | channel); // to serial1 MIDI 749 Serial1.write(pitch); 750 Serial1.write(velocity); 751} 752void playNoteOff(byte channel, byte pitch, byte velocity) { 753 midiEventPacket_t noteOff = {0x08, byte (0x80 | channel), pitch, velocity}; 754 MidiUSB.sendMIDI(noteOff); // to USB MIDI 755 MidiUSB.flush(); 756 Serial1.write(0x80 | channel); // to serial1 MIDI 757 Serial1.write(pitch); 758 Serial1.write(velocity); 759} 760 761//------------------------------------------------------------------------- SUBSTRING 762bool s_substring(char *dest_string, const int dest_sizeof, const char *source_string, 763 const int source_sizeof, const int source_from, const int source_to) { // copies source(from, to) to dest 764 if ((source_from < 0) || (source_to < source_from) || ((source_to - source_from + 1) > (dest_sizeof - 1)) 765 || (source_to >= (source_sizeof-1)) || ((source_to - source_from + 1) > (strlen(source_string)))) { 766 dest_string[0]=0; // NUL 767 return true; // err 1 768 } else { 769 int _Count=0; 770 for (int i=source_from;i<(source_to+1);i++) { 771 dest_string[_Count]=source_string[i]; 772 _Count++; 773 } 774 dest_string[_Count]=0; // ends with NUL 775 return false; // ok 0 776 } 777} // end s_substring()
ard-mididrum.ino
arduino
6 inputs MIDI interface for drums and pedals
1/* 2 * ard-mididrum.ino 3 * 4 * MIDI interface for 6 inputs as drum pads 'mono' (variable/analog from piezo sensor) with velocity value 5 * and for pedals 'stereo' ("expression" type with potentiometer inside) 6 * and for pedals 'mono' ("sustain" type with a switch inside NA or NC) 7 * 8 * it uses Arduino Micro, USB port as MIDI-OUT device, OLED 128x64 display (setup and monitor), 9 * rotary encoder + button for setup menu and options, 6 dimmable leds to monitor 6 inputs activity, 10 * MIDI-OUT serial port; parameters are memorized in the MPU EEPROM; 11 * 12 * 13 * by Marco Zonca 8-12/2020 14 * 15*/ 16 17/*table 18 * 19 * octave note pitchNr 20 * ------------------- 21 * -2 C 0 22 * -2 C# 1 23 * -2 D 2 24 * -2 D# 3 25 * -2 E 4 26 * -2 F 5 27 * -2 F# 6 28 * -2 G 7 29 * -2 G# 8 30 * -2 A 9 31 * -2 A# 10 32 * -2 B 11 33 * 34 * ...the same for the other octaves... 35 * 36 * octave note pitchNr 37 * ------------------- 38 * -1 (C-B) 12-23 39 * 0 (C-B) 24-35 40 * 1 (C-B) 36-47 41 * 2 (C-B) 48-59 42 * 3 (C-B) 60-71 43 * 4 (C-B) 72-83 44 * 5 (C-B) 84-95 45 * 6 (C-B) 96-107 46 * 7 (C-B) 108-119 47 * 8 (C-G) 120-127 48 * 49 * PitchNr [0 to 127] 50 * Octave = ((int(PitchNr / 12)) - 2) [-2 to 8] 51 * Note-Number = (PitchNr-((Octave+2)*12) + 1) [1 to 12] 52 * 53 * ---------------------- 54 * for pitchNr the maximum is 127 55 * for controlNr the maximum is 119 56 * 57*/ 58 59#include "MIDIUSB.h" 60#include <Wire.h> 61#include <Adafruit_GFX.h> 62#include <Adafruit_SSD1306.h> 63#include <EEPROM.h> 64 65#define NUM_INPUTS 6 66#define NUM_VALUES 9 67#define IS_DEBUG false 68 69Adafruit_SSD1306 display = Adafruit_SSD1306(128, 64, &Wire); 70 71// drums or pedals 72const uint8_t input1 = 18; // A0 73const uint8_t input2 = 19; // A1 74const uint8_t input3 = 20; // A2 75const uint8_t input4 = 21; // A3 76const uint8_t input5 = 22; // A4 77const uint8_t input6 = 23; // A5 78 79// leds 80const int led1Pin = 13; 81const int led2Pin = 11; 82const int led3Pin = 10; 83const int led4Pin = 9; 84const int led5Pin = 6; 85const int led6Pin = 5; 86const byte on = 255; 87const byte off = 0; 88 89const uint8_t inputs[NUM_INPUTS] = {input1, input2, input3, input4, input5, input6}; 90const uint8_t leds[NUM_INPUTS] = {led1Pin, led2Pin, led3Pin, led4Pin, led5Pin, led6Pin}; 91uint8_t prevValue[NUM_INPUTS] = {0, 0, 0, 0, 0, 0}; 92 93byte APitch = 48; 94int AOctave = (int(APitch/12)-2); 95byte ANote = (APitch-((AOctave+2)*12) + 1); 96char tableNotes[41] = "C C# D D# E F F# G G# A A# B "; 97char atext[31]=""; 98char apark[31]=""; 99 100uint8_t drum_velocity = 0; 101uint8_t velocity = 0; 102uint8_t controlvalue = 0; 103bool drum_isPressed = false; 104 105uint8_t bType[NUM_INPUTS] = {1, 1, 1, 1, 2, 3}; // 1=piezo drum 2=switch pedal 3=trimmer pedal (default setting) 106 107int KNOBinterval = 4000; // m/sec to enter Menu 108int KNOBmenuInterval = 1000; // m/sec to navigate Menu 109 110// rotary encoder 111int menuPin = 4; 112int encoderPin1 = 7; 113int encoderPin2 = 12; 114volatile int lastEncoded = 0; 115volatile long encoderValue = 0; 116volatile long encoderPrev = 0; 117volatile boolean IsMenu = false; 118volatile long lastencoderValue = 0; 119volatile int lastMSB = 0; 120volatile int lastLSB = 0; 121volatile int knob = 0; 122volatile byte preknob = 1; 123unsigned long prevKNOBmillis = 0; 124byte menuLevel=0; // 0-2 125byte menu_L0_Input=0; // 0-6 0=exit 126byte menu_L1_Voice=0; // 0-9 0=back 127byte menu_L2_Value=0; // 0-127 128byte menu_memory[NUM_INPUTS][NUM_VALUES]; 129 130 131/* Voices 0:Type 1=piezo/drum 2=switch/pedal 3=trimmer/pedal 132 * 1:Reverse 0=no 1=yes (only pedals) 133 * 2:Channel 1-16 134 * 3:PitchNr 0-127 (only drums) 135 * 4:Len 5-95 m/sec (only drums) 136 * 5:Min 0-63 137 * 6:Max 64-127 138 * 7:AntiBouncing 0-63 (only pedals) 139 * 8:ControlNr 0-119 (only pedals) 140 * 141 */ 142 143const byte menu_L2_Value_piezo_min[NUM_VALUES]= { 1, 255, 1, 0, 5, 0, 64, 255, 255}; // 255=not used 144const byte menu_L2_Value_piezo_max[NUM_VALUES]= { 3, 255, 16, 127, 95, 63, 127, 255, 255}; 145const byte menu_L2_Value_piezo_def[NUM_VALUES]= { 1, 255, 1, 48, 50, 30, 100, 255, 255}; 146const byte menu_L2_Value_switch_min[NUM_VALUES]= { 1, 0, 1, 255, 255, 0, 64, 0, 0}; 147const byte menu_L2_Value_switch_max[NUM_VALUES]= { 3, 1, 16, 255, 255, 63, 127, 63, 119}; 148const byte menu_L2_Value_switch_def[NUM_VALUES]= { 2, 1, 1, 255, 255, 0, 70, 60, 102}; 149const byte menu_L2_Value_trimmer_min[NUM_VALUES]={ 1, 0, 1, 255, 255, 0, 64, 0, 0}; 150const byte menu_L2_Value_trimmer_max[NUM_VALUES]={ 3, 1, 16, 255, 255, 63, 127, 63, 119}; 151const byte menu_L2_Value_trimmer_def[NUM_VALUES]={ 3, 0, 1, 255, 255, 0, 90, 2, 103}; 152const byte mId1=0xF1; 153const byte mId2=0xF2; 154 155void setup() { 156 int mAdr=0; 157 byte a=0; 158 byte b=0; 159 if (IS_DEBUG) Serial.begin(38400); 160 Serial1.begin(31250); // must be 31250 for MIDI standard 161 display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // Display Address 0x3C for 128x64 pixels 162 pinMode(encoderPin1, INPUT_PULLUP); 163 pinMode(encoderPin2, INPUT_PULLUP); 164 pinMode(menuPin, INPUT_PULLUP); 165 pinMode(led1Pin, OUTPUT); 166 pinMode(led2Pin, OUTPUT); 167 pinMode(led3Pin, OUTPUT); 168 pinMode(led4Pin, OUTPUT); 169 pinMode(led5Pin, OUTPUT); 170 pinMode(led6Pin, OUTPUT); 171 172 mAdr=0; // read EEPROM first 2 ID bytes and load, if necessary, all default parameters 173 if (EEPROM.read(mAdr) != mId1 || EEPROM.read(mAdr+1) != mId2) { 174 for (a=0;a<NUM_INPUTS;a++) { 175 loadDefaults(a, bType[a]); 176 }//for a 177 updateMemory(); 178 } else { 179 for (a=0;a<NUM_INPUTS;a++) { // read EEPROM 54 bytes (addr=2to55) 180 for (b=0;b<NUM_VALUES;b++) { 181 mAdr=(2+(a*9))+b; 182 menu_memory[a][b]=EEPROM.read(mAdr); 183 } 184 } 185 }//if EEPROM.read() 186 187 for (byte i=0;i<NUM_INPUTS;i++) { // pullup for switches 188 switch (menu_memory[i][0]) { //0=type 189 case 1: // drum 190 break; 191 case 2: // switch 192 pinMode(inputs[i], INPUT_PULLUP); 193 break; 194 case 3: // trimmer 195 break; 196 }//switch 197 }//for i 198 199 for (int i=1;i<=NUM_INPUTS;i++) { // leds show 200 if (i>1) { analogWrite(leds[i-2], off); } 201 analogWrite(leds[i-1], on); 202 delay(200); 203 } 204 analogWrite(leds[5], off); 205 206 showNormalDisplay(); 207}//setup() 208 209 210void loop() { 211 if (IsMenu==false) { 212 for (byte i=0;i<NUM_INPUTS;i++) { // ----------------- work on inputs 213 switch (menu_memory[i][0]) { //0=type 214 case 1: // drum 215 readDrum(i); 216 break; 217 case 2: // switch 218 readSwitch(i); 219 break; 220 case 3: // trimmer 221 readTrimmer(i); 222 break; 223 } //switch 224 } // for i 225 if ((prevKNOBmillis+KNOBinterval) < millis()) { // ---- check menu 226 if (digitalRead(menuPin) == LOW) { 227 IsMenu=true; 228 menuLevel=0; 229 menu_L0_Input=0; 230 if (IS_DEBUG) Serial.println("menu level 0 (input nr 0-6)"); 231 display.clearDisplay(); 232 printAt(2,2,false,"SETUP: type:"); 233 printAt(2,4,false,"rev: min :"); 234 printAt(2,5,false,"ch : max :"); 235 printAt(2,6,false,"ctr: note:"); 236 printAt(2,7,false,"len: abnc:"); 237 displayChoices(); 238 display.display(); 239 } 240 prevKNOBmillis=millis(); 241 } 242 } else { 243 updateEncoder(); 244 } // if IsMenu() 245} // loop() 246 247void showNormalDisplay() { //normal display 248 display.clearDisplay(); 249 display.setTextSize(2); 250 display.setTextColor(SSD1306_WHITE); 251 display.setCursor(0,0); 252 display.println("Z-MIDI 6dp"); 253 printAt(1,4,false,"Press knob for setup"); 254 printAt(1,6,true,"P T CH RAW VAL NT/CC"); 255 display.display(); 256} 257 258void loadDefaults(byte PortNr, byte PortType) { 259 byte a=0; 260 byte b=0; 261 a=PortNr; 262 switch (PortType) { 263 case 1: 264 for (b=0;b<NUM_VALUES;b++) { 265 menu_memory[a][b]=menu_L2_Value_piezo_def[b]; 266 } 267 break; 268 case 2: 269 for (b=0;b<NUM_VALUES;b++) { 270 menu_memory[a][b]=menu_L2_Value_switch_def[b]; 271 } 272 break; 273 case 3: 274 for (b=0;b<NUM_VALUES;b++) { 275 menu_memory[a][b]=menu_L2_Value_trimmer_def[b]; 276 } 277 break; 278 }//switch(a) 279}//loadDefaults() 280 281void updateMemory() { 282 int mAdr=0; 283 byte a=0; 284 byte b=0; 285 EEPROM.update(0,mId1); 286 EEPROM.update(1,mId2); 287 for (a=0;a<NUM_INPUTS;a++) { // update EEPROM 54 bytes (addr=2to55) 288 for (b=0;b<NUM_VALUES;b++) { 289 mAdr=(2+(a*9))+b; 290 EEPROM.update(mAdr,menu_memory[a][b]); 291 } 292 } 293} 294 295void displayChoices() { // live display during navigating inside menu 296 switch (menuLevel) { 297 case 0: 298 if (knob==0) { 299 printAt(9,2,true,"exit"); 300 } else { 301 sprintf(atext,"%-4d",knob); 302 printAt(9,2,true,atext); 303 } 304 break; 305 case 1: 306 if (menu_L0_Input==0) { 307 printAt(9,2,false,"exit"); 308 } else { 309 sprintf(atext,"%-4d",menu_L0_Input); 310 printAt(9,2,false,atext); 311 } 312 if (menu_memory[menu_L0_Input-1][1-1]==1) { // ------------- 1=drum 313 sprintf(atext,"%d",menu_memory[menu_L0_Input-1][1-1]); 314 printAt(20,2,false,atext); 315 printAt(7,4,false,"-"); 316 sprintf(atext,"%-2d ",menu_memory[menu_L0_Input-1][6-1]); 317 printAt(17,4,false,atext); 318 sprintf(atext,"%-2d",menu_memory[menu_L0_Input-1][3-1]); 319 printAt(7,5,false,atext); 320 sprintf(atext,"%-3d",menu_memory[menu_L0_Input-1][7-1]); 321 printAt(17,5,false,atext); 322 printAt(7,6,false,"---"); 323 APitch = menu_memory[menu_L0_Input-1][4-1]; 324 AOctave = ((int(APitch / 12)) - 2); 325 ANote = (APitch-((AOctave+2)*12) + 1); 326 s_substring(apark, sizeof(atext), tableNotes, sizeof(tableNotes), (ANote-1) * 3, ((ANote-1) * 3)+1); 327 sprintf(atext,"%s/%+1d",apark, AOctave); 328 printAt(17,6,false,atext); 329 sprintf(atext,"%-2d",menu_memory[menu_L0_Input-1][5-1]); 330 printAt(7,7,false,atext); 331 printAt(17,7,false,"--"); 332 } else { // ---------------------------------------------- 2=switch 3=trimmer 333 sprintf(atext,"%d",menu_memory[menu_L0_Input-1][1-1]); 334 printAt(20,2,false,atext); 335 if (menu_memory[menu_L0_Input-1][2-1]==0) { // reverse 336 printAt(7,4,false,"N"); 337 } else { 338 printAt(7,4,false,"Y"); 339 } 340 sprintf(atext,"%-2d",menu_memory[menu_L0_Input-1][6-1]); 341 printAt(17,4,false,atext); 342 sprintf(atext,"%-2d",menu_memory[menu_L0_Input-1][3-1]); 343 printAt(7,5,false,atext); 344 sprintf(atext,"%-3d",menu_memory[menu_L0_Input-1][7-1]); 345 printAt(17,5,false,atext); 346 sprintf(atext,"%-3d",menu_memory[menu_L0_Input-1][9-1]); 347 printAt(7,6,false,atext); 348 printAt(17,6,false,"--/--"); 349 printAt(7,7,false,"--"); 350 sprintf(atext,"%-2d",menu_memory[menu_L0_Input-1][8-1]); 351 printAt(17,7,false,atext); 352 } 353 printAt(8,2,false," "); // clear pointers ">" 354 printAt(19,2,false," "); 355 printAt(6,4,false," "); 356 printAt(6,5,false," "); 357 printAt(16,6,false," "); 358 printAt(6,7,false," "); 359 printAt(16,4,false," "); 360 printAt(16,5,false," "); 361 printAt(16,7,false," "); 362 printAt(6,6,false," "); 363 switch(knob) { // new pointer ">" 364 case 0: 365 printAt(8,2,false,">"); 366 break; 367 case 1: 368 printAt(19,2,false,">"); 369 break; 370 case 2: 371 printAt(6,4,false,">"); 372 break; 373 case 3: 374 printAt(6,5,false,">"); 375 break; 376 case 4: 377 printAt(16,6,false,">"); 378 break; 379 case 5: 380 printAt(6,7,false,">"); 381 break; 382 case 6: 383 printAt(16,4,false,">"); 384 break; 385 case 7: 386 printAt(16,5,false,">"); 387 break; 388 case 8: 389 printAt(16,7,false,">"); 390 break; 391 case 9: 392 printAt(6,6,false,">"); 393 break; 394 }//switch(knob) 395 break; 396 case 2: 397 switch(menu_L1_Voice) { // print new voice's value 398 case 0: 399 break; 400 case 1: 401 sprintf(atext,"%d",knob); 402 printAt(20,2,true,atext); 403 break; 404 case 2: 405 if (knob==0) { // reverse 406 printAt(7,4,true,"N"); 407 } else { 408 printAt(7,4,true,"Y"); 409 } 410 break; 411 case 3: 412 sprintf(atext,"%-2d",knob); 413 printAt(7,5,true,atext); 414 break; 415 case 4: 416 APitch = knob; 417 AOctave = ((int(APitch / 12)) - 2); 418 ANote = (APitch-((AOctave+2)*12) + 1); 419 s_substring(apark, sizeof(atext), tableNotes, sizeof(tableNotes), (ANote-1) * 3, ((ANote-1) * 3)+1); 420 sprintf(atext,"%s/%+1d",apark, AOctave); 421 printAt(17,6,true,atext); 422 break; 423 case 5: 424 sprintf(atext,"%-2d",knob); 425 printAt(7,7,true,atext); 426 break; 427 case 6: 428 sprintf(atext,"%-2d",knob); 429 printAt(17,4,true,atext); 430 break; 431 case 7: 432 sprintf(atext,"%-3d",knob); 433 printAt(17,5,true,atext); 434 break; 435 case 8: 436 sprintf(atext,"%-2d",knob); 437 printAt(17,7,true,atext); 438 break; 439 case 9: 440 sprintf(atext,"%-3d",knob); 441 printAt(7,6,true,atext); 442 break; 443 }//switch(menu_L1_Voice) 444 break; 445 }//switch(menuLevel) 446} 447 448void updateEncoder() { // ---------------------------------- encoder menu 449 int MSB = digitalRead(encoderPin1); //MSB = most significant bit 450 int LSB = digitalRead(encoderPin2); //LSB = least significant bit 451 int encoded = (MSB << 1) |LSB; //converting the 2 pin value to single number 452 int sum = (lastEncoded << 2) | encoded; //adding it to the previous encoded value 453 if(sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011) encoderValue ++; 454 if(sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000) encoderValue --; 455 lastEncoded = encoded; //store this value for next time 456 if ((encoderValue - encoderPrev) > 8) { // ------------------ right turn, clockwise ++ 457 knob ++; 458 if (menuLevel==0) if (knob>NUM_INPUTS) knob=0; 459 if (menuLevel==1) if (knob>9) knob=0; 460 if (menuLevel==1) if (knob==2) if (menu_memory[menu_L0_Input-1][1-1]==1) knob=3; // jump n.2 if drum 461 if (menuLevel==1) if (knob==8) if (menu_memory[menu_L0_Input-1][1-1]==1) knob=0; // jump n.8 if drum 462 if (menuLevel==1) if (knob==9) if (menu_memory[menu_L0_Input-1][1-1]==1) knob=0; // jump n.9 if drum 463 if (menuLevel==1) if (knob==4) if (menu_memory[menu_L0_Input-1][1-1]==2 || menu_memory[menu_L0_Input-1][1-1]==3) knob=6; // jump n.4 if pedal 464 if (menuLevel==1) if (knob==5) if (menu_memory[menu_L0_Input-1][1-1]==2 || menu_memory[menu_L0_Input-1][1-1]==3) knob=6; // jump n.5 if pedal 465 if (menuLevel==2) if (menu_memory[menu_L0_Input-1][1-1]==1) if (knob > menu_L2_Value_piezo_max[menu_L1_Voice-1]) knob=menu_L2_Value_piezo_min[menu_L1_Voice-1]; 466 if (menuLevel==2) if (menu_memory[menu_L0_Input-1][1-1]==2) if (knob > menu_L2_Value_switch_max[menu_L1_Voice-1]) knob=menu_L2_Value_switch_min[menu_L1_Voice-1]; 467 if (menuLevel==2) if (menu_memory[menu_L0_Input-1][1-1]==3) if (knob > menu_L2_Value_trimmer_max[menu_L1_Voice-1]) knob=menu_L2_Value_trimmer_min[menu_L1_Voice-1]; 468 if (menuLevel==2) if (menu_L1_Voice==1) loadDefaults((menu_L0_Input-1),knob); // load defaults if changing PortType 469 encoderPrev=encoderValue; 470 displayChoices(); 471 display.display(); 472 if (IS_DEBUG) Serial.println(knob); 473 } 474 if ((encoderValue - encoderPrev) < -8) { // ------------------ left turn, anticlockwise -- 475 knob --; 476 if (menuLevel==0) if (knob<0) knob=NUM_INPUTS; 477 if (menuLevel==1) if (knob<0) knob=9; 478 if (menuLevel==1) if (knob==2) if (menu_memory[menu_L0_Input-1][1-1]==1) knob=1; // jump n.2 if drum 479 if (menuLevel==1) if (knob==8) if (menu_memory[menu_L0_Input-1][1-1]==1) knob=7; // jump n.8 if drum 480 if (menuLevel==1) if (knob==9) if (menu_memory[menu_L0_Input-1][1-1]==1) knob=7; // jump n.9 if drum 481 if (menuLevel==1) if (knob==4) if (menu_memory[menu_L0_Input-1][1-1]==2 || menu_memory[menu_L0_Input-1][1-1]==3) knob=3; // jump n.4 if pedal 482 if (menuLevel==1) if (knob==5) if (menu_memory[menu_L0_Input-1][1-1]==2 || menu_memory[menu_L0_Input-1][1-1]==3) knob=3; // jump n.5 if pedal 483 if (menuLevel==2) if (menu_memory[menu_L0_Input-1][1-1]==1) if (knob < menu_L2_Value_piezo_min[menu_L1_Voice-1]) knob=menu_L2_Value_piezo_max[menu_L1_Voice-1]; 484 if (menuLevel==2) if (menu_memory[menu_L0_Input-1][1-1]==2) if (knob < menu_L2_Value_switch_min[menu_L1_Voice-1]) knob=menu_L2_Value_switch_max[menu_L1_Voice-1]; 485 if (menuLevel==2) if (menu_memory[menu_L0_Input-1][1-1]==3) if (knob < menu_L2_Value_trimmer_min[menu_L1_Voice-1]) knob=menu_L2_Value_trimmer_max[menu_L1_Voice-1]; 486 if (menuLevel==2) if (menu_L1_Voice==1) loadDefaults((menu_L0_Input-1),knob); // load defaults if changing PortType 487 encoderPrev=encoderValue; 488 displayChoices(); 489 display.display(); 490 if (IS_DEBUG) Serial.println(knob); 491 } 492 if (((prevKNOBmillis+KNOBmenuInterval) < millis()) && (digitalRead(menuPin) == LOW)) { // pressed knob 493 switch (menuLevel) { 494 case 0: 495 if (knob==0) { // exit from menu 496 showNormalDisplay(); 497 updateMemory(); 498 IsMenu=false; 499 if (IS_DEBUG) Serial.println("menu off"); 500 } else { // chosen input nr 501 menuLevel=1; 502 menu_L0_Input=knob; 503 knob=0; 504 displayChoices(); 505 display.display(); 506 if (IS_DEBUG) Serial.print("chosen: "); 507 if (IS_DEBUG) Serial.print(menu_L0_Input); 508 if (IS_DEBUG) Serial.println(", menu level 1 (voice 0-9)"); 509 } 510 break; 511 case 1: 512 if (knob==0) { // back previous level 0 513 menuLevel=0; 514 knob=menu_L0_Input; 515 displayChoices(); 516 display.display(); 517 if (IS_DEBUG) Serial.println("back menu level 0 (input nr 0-6)"); 518 } else { // chosen voice 519 menuLevel=2; 520 menu_L1_Voice=knob; 521 knob=menu_memory[menu_L0_Input-1][menu_L1_Voice-1]; // propose value in memory 522 displayChoices(); 523 display.display(); 524 if (IS_DEBUG) Serial.print("chosen: "); 525 if (IS_DEBUG) Serial.print(menu_L1_Voice); 526 if (IS_DEBUG) Serial.println(", menu level 2 (VALUE 0-127)"); 527 } 528 break; 529 case 2: 530 menuLevel=1; // save value & back previous level 1 531 menu_L2_Value=knob; 532 menu_memory[menu_L0_Input-1][menu_L1_Voice-1]=menu_L2_Value; 533 knob=menu_L1_Voice; 534 displayChoices(); 535 display.display(); 536 if (IS_DEBUG) Serial.print("chosen: "); 537 if (IS_DEBUG) Serial.print(menu_L2_Value); 538 if (IS_DEBUG) Serial.println(", save VALUE & back level 1 (voice 0-9)"); 539 break; 540 } // switch menuLevel 541 prevKNOBmillis=millis(); 542 } // if millis() 543} // updateEncoder() 544 545 546void printAt(const byte col, const byte row, const bool blackonwhite, const char thetext[31]) { // ------- printAt 547 // display: 21 col. x 8 row [setcursor(x,y)] x=(col-1)*6 y=(row-1)*8 548 // x=0,6,12,18,24,30,36,42,48,54,60,66,72,78,84,90,96,102,108,114,120 549 // y=0,8,16,24,32,40,48,56 550 display.setTextSize(1); 551 if (blackonwhite==true) { 552 display.setTextColor(SSD1306_BLACK, SSD1306_WHITE); // b/w 553 } else { 554 display.setTextColor(SSD1306_WHITE, SSD1306_BLACK); // normal 555 } 556 display.setCursor((col-1)*6,(row-1)*8); 557 display.print(thetext); 558} // printAt() 559 560 561void readSwitch(byte btnr) { // ---------------------------------- switch 562 int val = 0; 563 val = map(analogRead(inputs[btnr]), 0, 1023, 0, 127); 564 int raw = val; 565 if (val > menu_memory[btnr][6]) { //6=maxValue 566 val = menu_memory[btnr][6]; 567 } 568 if (val < menu_memory[btnr][5]) { //5=minValue 569 val = menu_memory[btnr][5]; 570 } 571 controlvalue = map(val, menu_memory[btnr][5], menu_memory[btnr][6], 0, 127); // expand value 5=minValue 6=maxValue 572 if (controlvalue < (128/2)) { // .. off 573 if (menu_memory[btnr][1]==0) { //1=reverse 574 controlvalue=0; 575 } else { 576 controlvalue=127; 577 } 578 } else { // ....................... on 579 if (menu_memory[btnr][1]==0) { //1=reverse 580 controlvalue=127; 581 } else { 582 controlvalue=0; 583 } 584 } 585 if (controlvalue <= (prevValue[btnr]-menu_memory[btnr][7]) || controlvalue >= (prevValue[btnr]+menu_memory[btnr][7])) { //7=antibouncing 586 controlChange((menu_memory[btnr][2]-1), menu_memory[btnr][8], controlvalue); //8=controlNr 2=channel 587 588 if (IS_DEBUG) Serial.print(btnr+1); 589 if (IS_DEBUG) Serial.print(" "); 590 if (IS_DEBUG) Serial.print(menu_memory[btnr][2]); //2=channel 591 if (IS_DEBUG) Serial.print(" "); 592 if (IS_DEBUG) Serial.print(menu_memory[btnr][8]); //8=controlNr 593 if (IS_DEBUG) Serial.print(" "); 594 if (IS_DEBUG) Serial.print(raw); 595 if (IS_DEBUG) Serial.print(" "); 596 if (IS_DEBUG) Serial.println(controlvalue); 597 598 sprintf(atext,"%d ",btnr+1); // live monitor 599 printAt(1,7,false,atext); 600 printAt(3,7,false,"S"); 601 sprintf(atext,"%d ",menu_memory[btnr][2]); //2=channel 602 printAt(5,7,false,atext); 603 sprintf(atext,"%d ",raw); 604 printAt(8,7,false,atext); 605 sprintf(atext,"%d ",controlvalue); 606 printAt(12,7,false,atext); 607 sprintf(atext,"%d ",menu_memory[btnr][8]); //8=controlNr 608 printAt(16,7,false,atext); 609 display.display(); 610 611 prevValue[btnr]=controlvalue; 612 analogWrite(leds[btnr], (controlvalue*2)); 613 } 614} // readSwitch() 615 616void readTrimmer(byte btnr) { // ---------------------------------- trimmer 617 int val = 0; 618 val = map(analogRead(inputs[btnr]), 0, 1023, 0, 127); 619 int raw = val; 620 if (val > menu_memory[btnr][6]) { //6=maxValue 621 val = menu_memory[btnr][6]; 622 } 623 if (val < menu_memory[btnr][5]) { //5=minValue 624 val = menu_memory[btnr][5]; 625 } 626 if (menu_memory[btnr][1]==0) { controlvalue = map(val, menu_memory[btnr][5], menu_memory[btnr][6], 0, 127);} // expand value if reverse=no 5=minValue 6=maxValue 627 if (menu_memory[btnr][1]==1) { controlvalue = map(val, menu_memory[btnr][5], menu_memory[btnr][6], 127, 0);} // expand value if reverse=yes 5=minValue 6=maxValue 628 if (controlvalue <= (prevValue[btnr]-menu_memory[btnr][7]) || controlvalue >= (prevValue[btnr]+menu_memory[btnr][7])) { //7=antibouncing 629 controlChange((menu_memory[btnr][2]-1), menu_memory[btnr][8], controlvalue); //8=controlNr 2=channel 630 631 if (IS_DEBUG) Serial.print(btnr+1); 632 if (IS_DEBUG) Serial.print(" "); 633 if (IS_DEBUG) Serial.print((menu_memory[btnr][2])); //2=channel 634 if (IS_DEBUG) Serial.print(" "); 635 if (IS_DEBUG) Serial.print(menu_memory[btnr][8]); //8=controlNr 636 if (IS_DEBUG) Serial.print(" "); 637 if (IS_DEBUG) Serial.print(raw); 638 if (IS_DEBUG) Serial.print(" "); 639 if (IS_DEBUG) Serial.println(controlvalue); 640 641 sprintf(atext,"%d ",btnr+1); // live monitor 642 printAt(1,7,false,atext); 643 printAt(3,7,false,"T"); 644 sprintf(atext,"%d ",menu_memory[btnr][2]); //2=channel 645 printAt(5,7,false,atext); 646 sprintf(atext,"%d ",raw); 647 printAt(8,7,false,atext); 648 sprintf(atext,"%d ",controlvalue); 649 printAt(12,7,false,atext); 650 sprintf(atext,"%d ",menu_memory[btnr][8]); //8=controlNr 651 printAt(16,7,false,atext); 652 display.display(); 653 654 prevValue[btnr]=controlvalue; 655 analogWrite(leds[btnr], (controlvalue*2)); 656 } 657} // readTrimmer() 658 659void readDrum(byte btnr) { // -------------------------------------- drum 660 int val=0; 661 val = map(analogRead(inputs[btnr]), 0, 1023, 0, 127); 662 int raw = val; 663 while (val >= menu_memory[btnr][5]) { //5=minValue as threshold 664 drum_isPressed = true; 665 if (val >= drum_velocity) { // take the peak of wave 666 drum_velocity=val; 667 } 668 val = map(analogRead(inputs[btnr]), 0, 1023, 0, 127); 669 }//while 670 if (drum_isPressed == true) { 671 if (drum_velocity > menu_memory[btnr][6]) { //6=maxValue 672 drum_velocity = menu_memory[btnr][6]; 673 } 674 velocity = map(drum_velocity, menu_memory[btnr][5], menu_memory[btnr][6], 1, 127); // expand velocity 5=minValue 6=maxValue 675 playNoteOn((menu_memory[btnr][2]-1), menu_memory[btnr][3], velocity); //3=pitchNr 2=channel 676 677 if (IS_DEBUG) Serial.print(btnr+1); 678 if (IS_DEBUG) Serial.print(" "); 679 if (IS_DEBUG) Serial.print((menu_memory[btnr][2])); //2=channel 680 if (IS_DEBUG) Serial.print(" "); 681 if (IS_DEBUG) Serial.print(menu_memory[btnr][3]); //3=pitchNr 682 if (IS_DEBUG) Serial.print(" "); 683 if (IS_DEBUG) Serial.print(raw); 684 if (IS_DEBUG) Serial.print(" "); 685 if (IS_DEBUG) Serial.print(velocity); 686 if (IS_DEBUG) Serial.print(" --> "); 687 688 sprintf(atext,"%d ",btnr+1); // live monitor 689 printAt(1,7,false,atext); 690 printAt(3,7,false,"P"); 691 sprintf(atext,"%d ",menu_memory[btnr][2]); //2=channel 692 printAt(5,7,false,atext); 693 sprintf(atext,"%d ",raw); 694 printAt(8,7,false,atext); 695 sprintf(atext,"%d ",velocity); 696 printAt(12,7,false,atext); 697 sprintf(atext,"%d ",menu_memory[btnr][3]); //3=pitchNr 698 APitch = menu_memory[btnr][3]; 699 AOctave = ((int(APitch / 12)) - 2); 700 ANote = (APitch-((AOctave+2)*12) + 1); 701 s_substring(apark, sizeof(atext), tableNotes, sizeof(tableNotes), (ANote-1) * 3, ((ANote-1) * 3)+1); 702 sprintf(atext,"%s/%d ",apark,AOctave); 703 printAt(16,7,false,atext); 704 display.display(); 705 706 if (IS_DEBUG) Serial.print(APitch); 707 if (IS_DEBUG) Serial.print(" "); 708 if (IS_DEBUG) Serial.print(AOctave); 709 if (IS_DEBUG) Serial.print(" "); 710 if (IS_DEBUG) Serial.print(ANote); 711 if (IS_DEBUG) Serial.print(" "); 712 if (IS_DEBUG) Serial.println(atext); 713 714 prevValue[btnr]=velocity; 715 drum_velocity=0; 716 drum_isPressed = false; 717 analogWrite(leds[btnr], (velocity*2)); 718 delay(menu_memory[btnr][4]); //4=timeinterval 719 analogWrite(leds[btnr], off); 720 } // if(drum1_isPressed) 721} // readDrum() 722 723 724// First parameter is the event type (0x0B = control change) 4 bits 725// Second parameter is the event type, combined with the channel, above 4 bits + channel 4 bits 726// Third parameter is the control number (0-119). 727// Fourth parameter is the control value (0-127). 728// -------------------------------------------------------------- 729void controlChange(byte channel, byte control, byte value) { 730 midiEventPacket_t midiCc = {0x0B, byte (0xB0 | channel), control, value}; 731 MidiUSB.sendMIDI(midiCc); // to USB MIDI 732 MidiUSB.flush(); 733 Serial1.write(0xB0 | channel); // to serial1 MIDI 734 Serial1.write(control); 735 Serial1.write(value); 736} 737 738// First parameter is the event type (0x09 = note on, 0x08 = note off) 4 bits 739// Second parameter is note-on/note-off, combined with the channel, above 4 bits + channel 4 bits 740// Channel between 0-15. Typically reported to the user as 1-16 741// Third parameter is the note number, the pitch, (48 = middle C). 742// Fourth parameter is the velocity (0 = none, 64 = normal, 127 = louder/faster). 743// -------------------------------------------------------------- 744void playNoteOn(byte channel, byte pitch, byte velocity) { 745 midiEventPacket_t noteOn = {0x09, byte (0x90 | channel), pitch, velocity}; 746 MidiUSB.sendMIDI(noteOn); // to USB MIDI 747 MidiUSB.flush(); 748 Serial1.write(0x90 | channel); // to serial1 MIDI 749 Serial1.write(pitch); 750 Serial1.write(velocity); 751} 752void playNoteOff(byte channel, byte pitch, byte velocity) { 753 midiEventPacket_t noteOff = {0x08, byte (0x80 | channel), pitch, velocity}; 754 MidiUSB.sendMIDI(noteOff); // to USB MIDI 755 MidiUSB.flush(); 756 Serial1.write(0x80 | channel); // to serial1 MIDI 757 Serial1.write(pitch); 758 Serial1.write(velocity); 759} 760 761//------------------------------------------------------------------------- SUBSTRING 762bool s_substring(char *dest_string, const int dest_sizeof, const char *source_string, 763 const int source_sizeof, const int source_from, const int source_to) { // copies source(from, to) to dest 764 if ((source_from < 0) || (source_to < source_from) || ((source_to - source_from + 1) > (dest_sizeof - 1)) 765 || (source_to >= (source_sizeof-1)) || ((source_to - source_from + 1) > (strlen(source_string)))) { 766 dest_string[0]=0; // NUL 767 return true; // err 1 768 } else { 769 int _Count=0; 770 for (int i=source_from;i<(source_to+1);i++) { 771 dest_string[_Count]=source_string[i]; 772 _Count++; 773 } 774 dest_string[_Count]=0; // ends with NUL 775 return false; // ok 0 776 } 777} // end s_substring()
Downloadable files
PCB #2 overview
PCB #2 overview
Fritzing schematic picture
Fritzing schematic picture
PCB board #1 (components side)
PCB board #1 (components side)
PCB board #1
PCB board #1
Fritzing schematic diagram
Fritzing schematic diagram
PCB board #2 (components side)
PCB board #2 (components side)
PCB board #2
PCB board #2
PCB board #1
PCB board #1
Fritzing schematic diagram
Fritzing schematic diagram
PCB board #2 (components side)
PCB board #2 (components side)
PCB board #2
PCB board #2
PCB #1 overview
PCB #1 overview
PCB #2 overview
PCB #2 overview
Fritzing schematic picture
Fritzing schematic picture
PCB board #1 (components side)
PCB board #1 (components side)
Comments
Only logged in users can leave comments