/ Neotrellis_M4_Live_Launcher / Neotrellis_M4_Live_Launcher.ino
Neotrellis_M4_Live_Launcher.ino
1 // SPDX-FileCopyrightText: 2018 Collin Cunningham for Adafruit Industries 2 // 3 // SPDX-License-Identifier: MIT 4 5 /* Live Launcher - Ableton Live controller for Adafruit Neotrellis M4 6 by Collin Cunningham for Adafruit Industries 7 https://www.adafruit.com/product/3938 8 */ 9 10 #include <Adafruit_NeoTrellisM4.h> 11 12 #define WIDTH 8 13 #define HEIGHT 4 14 #define N_BUTTONS WIDTH*HEIGHT 15 #define NEO_PIN 10 16 #define NUM_KEYS 32 17 #define SERIAL_TIMEOUT 1000 //time before giving up on incoming serial data 18 #define COLOR_DATA_LENGTH 98 //number of total bytes to expect in incoming color data 19 //4 bytes per color * 32 buttons = 128 bytes + 2 header bytes = 130 bytes total 20 #define BUTTON_DATA_LENGTH 5 //clip playing status message for each button 21 #define PULSE_DURATION 350 //length of 'now playing' pulse 22 23 unsigned long readTime; //time we start reading serial buffer 24 unsigned long lastPulseTime; 25 bool pulseOn = false; 26 uint8_t packetbuffer[COLOR_DATA_LENGTH]; //store incoming serial data 27 uint8_t colors[96]; 28 29 Adafruit_NeoTrellisM4 trellis = Adafruit_NeoTrellisM4(); 30 31 const byte ROWS = HEIGHT; // four rows 32 const byte COLS = WIDTH; // eight columns 33 byte trellisKeys[ROWS][COLS] = { //define the symbols on the buttons of the keypads 34 {1, 2, 3, 4, 5, 6, 7, 8}, 35 {9, 10, 11, 12, 13, 14, 15, 16}, 36 {17, 18, 19, 20, 21, 22, 23, 24}, 37 {25, 26, 27, 28, 29, 30, 31, 32} 38 }; 39 byte rowPins[ROWS] = {14, 15, 16, 17}; //connect to the row pinouts of the keypad 40 byte colPins[COLS] = {2, 3, 4, 5, 6, 7, 8, 9}; //connect to the column pinouts of the keypad 41 Adafruit_Keypad customKeypad = Adafruit_Keypad( makeKeymap(trellisKeys), rowPins, colPins, ROWS, COLS); //initialize keypad 42 extern const uint8_t gamma8[]; 43 44 boolean pressed[N_BUTTONS] = {false}; // Pressed state for each button 45 uint8_t playing[N_BUTTONS] = {0}; // Playing state for each button 46 47 void setup() { 48 Serial.begin(57600); 49 // while (!Serial) {} 50 51 trellis.begin(); 52 trellis.setBrightness(255); 53 trellis.fill(0); 54 } 55 56 57 void loop() { 58 unsigned long startTime = millis(); 59 60 if (Serial.available() >= BUTTON_DATA_LENGTH) { 61 parseData(); 62 } 63 64 //send press events to Live via serial 65 trellis.tick(); 66 while (trellis.available()) { 67 keypadEvent e = trellis.read(); 68 uint8_t i = e.bit.KEY; 69 if (e.bit.EVENT == KEY_JUST_PRESSED) { 70 pressed[i] = true; 71 Serial.write(i); 72 } 73 else if (e.bit.EVENT == KEY_JUST_RELEASED) { 74 pressed[i] = false; 75 } 76 } 77 78 if ((startTime - lastPulseTime) >= PULSE_DURATION) { 79 80 //flash any clip which is playing 81 if (pulseOn) { 82 for (uint8_t i = 0; i < N_BUTTONS; i++) { 83 setPixelWithColorsIndex(i, false); 84 } 85 } 86 else { 87 for (uint8_t i = 0; i < N_BUTTONS; i++) { 88 if (playing[i]) { 89 setPixelWithColorsIndex(i, true); 90 } 91 else setPixelWithColorsIndex(i, false); 92 } 93 } 94 pulseOn = !pulseOn; 95 lastPulseTime = millis(); 96 } 97 } 98 99 void parseData() { 100 101 //check for ! start char 102 if (Serial.read() == '!') { 103 uint8_t id = Serial.read(); 104 105 //check for Color data 106 if (id == 'C') { 107 for (int i = 0; i < 96; i++) { 108 colors[i] = Serial.read(); 109 } 110 111 //color button leds 112 for (int i = 0; i < N_BUTTONS; i++) { 113 setPixelWithColorsIndex(i, false); 114 } 115 } 116 117 //check for clip status data 118 else if (id == 'B') { 119 uint8_t x = Serial.read(); 120 uint8_t state = Serial.read(); 121 uint8_t y = Serial.read(); 122 123 if (state == 0) { //if state is 0, all clips in track are stopped 124 for (int i = 0; i < HEIGHT; i++) { 125 uint8_t index = i * WIDTH + x; 126 playing[index] = state; 127 } 128 } 129 130 else { //all other clips in track should stop 131 for (int i = 0; i < HEIGHT; i++) { 132 uint8_t index = i * WIDTH + x; 133 playing[index] = 0; 134 } 135 //save playing state 136 uint8_t index = y * WIDTH + x; 137 playing[index] = state; 138 } 139 } 140 } 141 } 142 143 void setPixelWithColorsIndex(int i, bool dimmed) { 144 145 uint8_t red = colors[i * 3]; 146 uint8_t green = colors[i * 3 + 1]; 147 uint8_t blue = colors[i * 3 + 2]; 148 if (dimmed) { 149 setPixelWithGamma(i, red / 2, green / 2, blue / 2); 150 } 151 else { 152 setPixelWithGamma(i, red, green, blue); 153 } 154 155 } 156 157 void setPixelWithGamma(int pixelNumber, uint8_t red, uint8_t green, uint8_t blue) { 158 159 uint32_t color = trellis.Color( 160 pgm_read_byte(&gamma8[red]), 161 pgm_read_byte(&gamma8[green]), 162 pgm_read_byte(&gamma8[blue])); 163 164 trellis.setPixelColor(pixelNumber, color); 165 } 166 167 const uint8_t PROGMEM gamma8[] = { 168 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 169 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 170 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 171 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 172 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 173 10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16, 174 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 24, 24, 25, 175 25, 26, 27, 27, 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 35, 36, 176 37, 38, 39, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 50, 177 51, 52, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 66, 67, 68, 178 69, 70, 72, 73, 74, 75, 77, 78, 79, 81, 82, 83, 85, 86, 87, 89, 179 90, 92, 93, 95, 96, 98, 99, 101, 102, 104, 105, 107, 109, 110, 112, 114, 180 115, 117, 119, 120, 122, 124, 126, 127, 129, 131, 133, 135, 137, 138, 140, 142, 181 144, 146, 148, 150, 152, 154, 156, 158, 160, 162, 164, 167, 169, 171, 173, 175, 182 177, 180, 182, 184, 186, 189, 191, 193, 196, 198, 200, 203, 205, 208, 210, 213, 183 215, 218, 220, 223, 225, 228, 231, 233, 236, 239, 241, 244, 247, 249, 252, 255 184 }; 185