//Leszek D. //Midi Keyb LCD version:6.0 //Obsługuje PitchBend i Modulation (PB) i Modulation //JEDEN przycisk funkcyjny - sw1 //Transpozycja klawiszami C1,D1, - +12/-12 //Kanał MIDI klawiszami - E1, F1 - +/- //Przesuwanie półtonami - klawiszami C#1(+) i D#1(-), - co półton //Zwora "zwora" wyłącza obsługę PB i Modulation przy fizycznym braku modulatorów.. #include #include #include #include MIDI_CREATE_DEFAULT_INSTANCE(); //====Modulation Wheel ResponsiveAnalogRead modulationPot(A0, true); // Modulation Pot //====Pitch Bend ResponsiveAnalogRead pitchbendPot(A1, true); // PitchBend Pot LiquidCrystal_I2C lcd(0x27, 16, 2); // ust.adresu LCD 0x27 i rozmiarów #define NUM_ROWS 6 #define NUM_COLS 11 //MIDI baud rate #define SERIAL_RATE 31250 // Pin Definitions // Row input pins const int row1Pin = 2; const int row2Pin = 3; const int row3Pin = 4; const int row4Pin = 5; const int row5Pin = 6; const int row6Pin = 7; // 74HC595 pins const int dataPin = 8; const int latchPin = 9; const int clockPin = 10; // zmiana kanalu MIDI, transpozycja const int sw1 = 11; // przycisk funkcyjny const int zwora = 12; // zwora Pitch Bend - OFF boolean keyPressed[NUM_ROWS][NUM_COLS]; uint8_t keyToMidiMap[NUM_ROWS][NUM_COLS]; // bitmasks for scanning columns int bits[] = { B00000001, B00000010, B00000100, B00001000, B00010000, B00100000, B01000000, B10000000 }; int channel = 1; void setup() { lcd.init(); // initialize the lcd lcd.backlight(); // podświetlenie lcd.print("*musel* L.Dorski"); // wyświetl info pocz. na LCD. delay(2000); lcd.clear(); lcd.print("MIDI Keyb+PB 6.0"); // "górna" linia lcd.setCursor(0, 1); // "dolna" linia lcd.print("Ch:"); lcd.setCursor(5, 1); lcd.print("Oct:"); lcd.setCursor(12, 1); lcd.print("n:"); lcd.setCursor(15, 1); lcd.print(0); // setup pins output/input mode pinMode(dataPin, OUTPUT); pinMode(clockPin, OUTPUT); pinMode(latchPin, OUTPUT); pinMode(row1Pin, INPUT); pinMode(row2Pin, INPUT); pinMode(row3Pin, INPUT); pinMode(row4Pin, INPUT); pinMode(row5Pin, INPUT); pinMode(row6Pin, INPUT); pinMode(sw1, INPUT_PULLUP); pinMode(zwora, INPUT_PULLUP); Serial.begin(SERIAL_RATE); // MIDI MIDI.begin(); delay(100); } int NOTE_VELOCITY = 127; int ON_CMD = 0x90; //ustalenie początkowego kanału - "1" int OFF_CMD = 0x80; //ustalenie początkowego kanału - "1" int PB = 0xE0; //ustalenie pocz.kanału PitchBend - "1" int note = 36; //nuta bazowa (C1)- odpow.ok.65Hz int note2 = 36; //zmienna potrzebna do transpozycji int ab = 0; //tworzenie matrycy nut po transpozycji int bc = 2; //zmienna potrzebna do odświerzania matrycy nut po transpozycji int xx = 0; //zmienna potrzebna do ustalenia pierwszego klawisza (C1) int xy = 0; //zmienna potrzebna do ustalenia klawisza 4tego i 5tego(D,E) int yz = 0; //zmienna potrzebna do ustalenia nuty int zz = 0; //zmienna potrzebna do ustalenia oktawy(C,D) int ok = 1; //zakres zmiany oktawy void loop() { // Pitch Bend pitchbendPot.update(); int mappedPBPot = map(pitchbendPot.getValue(), 0, 1023, 0, 16383); //przekształcenie zakresu 1023 na if (pitchbendPot.hasChanged()) { //16383 (od 0 lub więcej w zależnosci MIDImessage(0xE0, (0 & 0x7F), (mappedPBPot >> 7) & 0x7F) ; //od ustaw. potencjometru - środek: 8192 } delay(20); Label2: if (zz >= -ok && zz < ok) { if (digitalRead(sw1) == LOW && xx == 3) { //naciśnięcie przycisku sw + C1 raz .. +12 note2 = note2 + 12; ab = 0; bc = 3; xx = 0; note = note2; zz = zz + 1; } } if (zz > -ok && zz <= ok) { if (digitalRead(sw1) == LOW && xx == 1) { //naciśnięcie przycisku sw + D1 raz .. -12 note2 = note2 - 12; ab = 0; bc = 1; xx = 0; note = note2; zz = zz - 1; } } if (yz >= -6 && yz < 6) { if (digitalRead(sw1) == LOW && xx == 2) { //naciśnięcie przycisku sw + C#1 raz .. +1 note2 = note2 + 1; ab = 0; bc = 4; xx = 0; yz = yz + 1; ; note = note2; } } if (yz > -6 && yz <= 6) { if (digitalRead(sw1) == LOW && xx == 4) { //naciśnięcie przycisku sw + D#1 raz .. -1 note2 = note2 - 1; ab = 0; bc = 5; xx = 0; yz = yz - 1; note = note2; } } if (bc == 1 || bc == 3) { // LCD - zmiana oktawy "+12/-12" if (zz < 0) { lcd.setCursor(9, 1); lcd.print(zz); } if (zz > 0) { lcd.setCursor (9, 1); lcd.print ("+"); lcd.setCursor(10, 1); lcd.print(zz); } } if (zz == 0) { lcd.setCursor(9, 1); // LCD - pierwszy klawisz "C1" w notacji MIDI lcd.print("C1"); } if (bc == 4 || bc == 5) { // LCD - zmiana nuty "+1/-1" if (yz < 0) { lcd.setCursor(14, 1); lcd.print(yz); } if (yz >= 0) { lcd.setCursor (14, 1); lcd.print (" "); lcd.setCursor(15, 1); lcd.print(yz); } } lcd.setCursor(9, 0); // sygnalizator aktywnego PitchBend na LCD if (digitalRead(zwora) == HIGH) { lcd.print("+PB "); } else { lcd.print("-d v"); } if (ab == 66) { //tworzenie matrycy nut po transpozycji goto Label; } for (int colCtr = 0; colCtr < NUM_COLS; ++colCtr) { for (int rowCtr = 0; rowCtr < NUM_ROWS; ++rowCtr) { keyPressed[rowCtr][colCtr] = false; keyToMidiMap[rowCtr][colCtr] = note; note++; ab = ab + 1; } } while (digitalRead(sw1) == LOW && xx == 0) {} Label: lcd.setCursor(3, 1); // midi channel lcd.print(ON_CMD - 143); if (ON_CMD - 143 < 10) { lcd.setCursor(4, 1); lcd.print(" "); } if (ON_CMD < 0x9F && OFF_CMD < 0x8F) { //sprawdzenie czy kanał jest wiekszy od 16 if (digitalRead(sw1) == LOW && xy == 1) { //naciśnięcie przycisku sw1 - zwiększanie kanału o 1 xy = 0; ON_CMD = ON_CMD + 1; OFF_CMD = OFF_CMD + 1; PB = PB + 1; channel = channel + 1; } } if (ON_CMD > 0x90 && OFF_CMD > 0x80) { //sprawdzenie czy kanał jest mniejszy od 1 if (digitalRead(sw1) == LOW && xy == 2) { //naciśnięcie przycisku sw1 - zmniejszanie kanału o 1 xy = 0; ON_CMD = ON_CMD - 1; OFF_CMD = OFF_CMD - 1; PB = PB - 1; channel = channel - 1; } } for (int colCtr = 0; colCtr < NUM_COLS; ++colCtr) { //scan next column scanColumn(colCtr); //get row values at this column int rowValue[NUM_ROWS]; rowValue[0] = digitalRead(row1Pin); rowValue[1] = digitalRead(row2Pin); rowValue[2] = digitalRead(row3Pin); rowValue[3] = digitalRead(row4Pin); rowValue[4] = digitalRead(row5Pin); rowValue[5] = digitalRead(row6Pin); // process keys pressed for (int rowCtr = 0; rowCtr < NUM_ROWS; ++rowCtr) { if (rowValue[rowCtr] != 0 && !keyPressed[rowCtr][colCtr]) { keyPressed[rowCtr][colCtr] = true; if (digitalRead(sw1) == HIGH) { noteOn(rowCtr, colCtr); } if (rowCtr == 0 && colCtr == 0 && digitalRead(sw1) == LOW) { // naciśnięcie klawisza "C1" (-12) xx = 1; goto Label2; } if (rowCtr == 1 && colCtr == 0 && digitalRead(sw1) == LOW) { // nacisnięcie klawisza "C#1" (+1) xx = 2; goto Label2; } if (rowCtr == 2 && colCtr == 0 && digitalRead(sw1) == LOW) { // nacisnięcie klawisza "D1" (+12) xx = 3; goto Label2; } if (rowCtr == 3 && colCtr == 0 && digitalRead(sw1) == LOW) { // nacisnięcie klawisza "D#1" (-1) xx = 4; goto Label2; } else if (rowCtr == 4 && colCtr == 0 && digitalRead(sw1) == LOW) { // nacisnięcie klawisza "E" (CH: +1) xy = 1; goto Label; } else if (rowCtr == 5 && colCtr == 0 && digitalRead(sw1) == LOW) { // nacisnięcie klawisza "F" (CH: -1) xy = 2; goto Label; } } } // process keys released for (int rowCtr = 0; rowCtr < NUM_ROWS; ++rowCtr) { if (rowValue[rowCtr] == 0 && keyPressed[rowCtr][colCtr]) { keyPressed[rowCtr][colCtr] = false; noteOff(rowCtr, colCtr); } } } // Modulation if (digitalRead(zwora) == HIGH) { modulationPot.update(); int mappedMPot = map(modulationPot.getValue(), 0, 1023, 0, 127); if (modulationPot.hasChanged()) { MIDI.sendControlChange(1, mappedMPot, channel); } } delay(20); } void scanColumn(int colNum) { digitalWrite(latchPin, LOW); if (0 <= colNum && colNum <= 7) { shiftOut(dataPin, clockPin, MSBFIRST, B00000000); //right sr shiftOut(dataPin, clockPin, MSBFIRST, bits[colNum]); //left sr } else { shiftOut(dataPin, clockPin, MSBFIRST, bits[colNum - 8]); //right sr shiftOut(dataPin, clockPin, MSBFIRST, B00000000); //left sr } digitalWrite(latchPin, HIGH); } void noteOn(int row, int col) { Serial.write(ON_CMD); Serial.write(keyToMidiMap[row][col]); Serial.write(NOTE_VELOCITY); lcd.setCursor(4, 0); // sygnalizator naciskania klawisza na LCD - ("gwiazdka") lcd.print("*"); } void noteOff(int row, int col) { Serial.write(OFF_CMD); Serial.write(keyToMidiMap[row][col]); Serial.write(NOTE_VELOCITY); lcd.setCursor(4, 0); // sygnalizator puszczenia klawisza na LCD lcd.print(" "); } // wysyłanie Pitch Bend void MIDImessage(int type, int bajtLSB, int bajtMSB) { if (digitalRead(zwora) == HIGH) { Serial.write(PB); // Send command byte Serial.write(bajtLSB); // Send data byte #1 Serial.write(bajtMSB); // Send data byte #2 } }