Skip to content

Commit c7471f8

Browse files
authored
Merge pull request #1800 from jedgarpark/keypad-4x4-clocked
first commit
2 parents 033416b + 9e0fac3 commit c7471f8

2 files changed

Lines changed: 154 additions & 0 deletions

File tree

Keypad_4x4_Clocked/.qtpy.test.only

Whitespace-only changes.
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
// SPDX-FileCopyrightText: 2021 John Park for Adafruit Industries
2+
// SPDX-License-Identifier: MIT
3+
// Keypad 4x4 for NeoKey Ortho Snap-apart PCB & QT Py M0
4+
// Sends MIDI NoteOn/Off and Clock
5+
// --works well in VCV Rack for keeping clock timing via MIDI-CV CLK
6+
7+
#include <Adafruit_TinyUSB.h>
8+
#include "Adafruit_Keypad.h"
9+
#include <Adafruit_NeoPixel.h>
10+
#include <MIDI.h>
11+
12+
// User variables
13+
bool latch_mode = false; // set latch/toggle mode
14+
int BPM = 120; // set BPM
15+
int MIDI_OUT_CH = 1; // pick your midi output channel here
16+
17+
18+
uint32_t interval = 60000 / BPM;
19+
20+
Adafruit_USBD_MIDI usb_midi;
21+
MIDI_CREATE_INSTANCE(Adafruit_USBD_MIDI, usb_midi, MIDI);
22+
23+
const byte ROWS = 4; // rows
24+
const byte COLS = 4; // columns
25+
26+
//define the symbols on the buttons of the keypads -- used for Serial output, debugging
27+
char keys[ROWS][COLS] = {
28+
{'1','2','3','4'},
29+
{'5','6','7','8'},
30+
{'A','B','C','D'},
31+
{'E','F','G','H'}
32+
};
33+
34+
byte rowPins[ROWS] = {A3, A2, A1, A0}; //connect to the row pinouts of the keypad
35+
byte colPins[COLS] = {SCL, A6, A7, A8}; //connect to the column pinouts of the keypad
36+
37+
//define the MIDI notes to send per key
38+
int pads[] = { // two A scales with added G#
39+
76, 77, 79, 80,
40+
69, 71, 72, 74,
41+
64, 65, 67, 68,
42+
57, 59, 60, 62
43+
};
44+
45+
/*int pads[] = { // corresponds to 1010music blackbox pads for sample launching
46+
48, 49, 50, 51,
47+
44, 45, 46, 47,
48+
40, 41, 42, 43,
49+
36, 37, 38, 39
50+
};*/
51+
52+
53+
int current_key = 0; // current key press int
54+
int pixorder[] = { // to convert "snake" order to grid order
55+
0, 1, 2, 3,
56+
7, 6, 5, 4,
57+
8, 9, 10, 11,
58+
15, 14, 13, 12
59+
} ;
60+
61+
//initialize an instance of keypad
62+
Adafruit_Keypad customKeypad = Adafruit_Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS);
63+
64+
#define NEO_PIN SDA
65+
#define NUMPIXELS ROWS*COLS
66+
Adafruit_NeoPixel pixels(NUMPIXELS, NEO_PIN, NEO_GRB + NEO_KHZ800);
67+
68+
uint32_t red = pixels.Color(100, 0, 0);
69+
uint32_t light_blue = pixels.Color(0, 50, 60);
70+
uint32_t black = pixels.Color(0, 0, 0);
71+
72+
uint32_t priorcolor = pixels.Color(0,0,0); // store state of color before sequence changes it
73+
uint32_t currentcolor = pixels.Color(0,0,0);
74+
75+
int current_pixel = 0; // current pixel
76+
77+
unsigned long previousMillis = 0;
78+
79+
void setup() {
80+
//Serial.begin(9600); // use for debugging
81+
MIDI.begin(MIDI_OUT_CH); // begin MIDI before the delay to settle
82+
delay(1000);
83+
customKeypad.begin(); // begin keypad
84+
pixels.begin(); // begin neopixels
85+
86+
for(int i=0; i<NUMPIXELS+1; i++) { // light up each pixel
87+
pixels.setPixelColor(pixorder[i], light_blue);
88+
pixels.setPixelColor(pixorder[i-1], black);
89+
pixels.show(); // Send the updated pixel colors to the hardware.
90+
delay(int(interval/4));
91+
}
92+
}
93+
94+
void loop() {
95+
customKeypad.tick();
96+
unsigned long currentMillis = millis();
97+
98+
while(customKeypad.available()){
99+
keypadEvent e = customKeypad.read(); // scan the keypad for changes
100+
//Serial.print((char)e.bit.KEY);
101+
102+
if(e.bit.EVENT == KEY_JUST_PRESSED){
103+
current_key = (e.bit.ROW * ROWS) + e.bit.COL ;
104+
//Serial.println(" pressed");
105+
//Serial.println(interval);
106+
currentcolor = pixels.getPixelColor(pixorder[current_key]);
107+
if (latch_mode == true){
108+
if (currentcolor==0){
109+
MIDI.sendNoteOn(pads[current_key], 127, MIDI_OUT_CH);
110+
pixels.setPixelColor(pixorder[current_key], light_blue);
111+
}
112+
else{
113+
MIDI.sendNoteOff(pads[current_key], 0, MIDI_OUT_CH);
114+
pixels.setPixelColor(pixorder[current_key], black);
115+
}
116+
}
117+
else{
118+
MIDI.sendNoteOn(pads[current_key], 127, MIDI_OUT_CH);
119+
pixels.setPixelColor(pixorder[current_key], light_blue);
120+
}
121+
pixels.show();
122+
}
123+
124+
else if(e.bit.EVENT == KEY_JUST_RELEASED){
125+
current_key = (e.bit.ROW * ROWS) + e.bit.COL ;
126+
//Serial.println(" released");
127+
if (latch_mode == false){
128+
MIDI.sendNoteOff(pads[current_key], 0, MIDI_OUT_CH);
129+
pixels.setPixelColor(pixorder[current_key], black);
130+
pixels.show();
131+
}
132+
}
133+
// delay(10);
134+
}
135+
//----- Running light
136+
if (currentMillis - previousMillis >= interval) {
137+
MIDI.sendClock();
138+
if (current_pixel==0){ // loop around to last pixel for color reset
139+
pixels.setPixelColor(pixorder[NUMPIXELS-1], priorcolor);
140+
}
141+
else{
142+
pixels.setPixelColor(pixorder[current_pixel-1], priorcolor);
143+
}
144+
priorcolor = pixels.getPixelColor(pixorder[current_pixel]); // grabs the current color of the pixel for later use
145+
146+
pixels.setPixelColor(pixorder[current_pixel], red);
147+
pixels.show();
148+
current_pixel++;
149+
previousMillis = currentMillis;
150+
}
151+
if (current_pixel==NUMPIXELS){
152+
current_pixel=0;
153+
}
154+
}

0 commit comments

Comments
 (0)