/ 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