about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJared DeCook <jared@shapingthesilence.com>2022-11-19 17:51:34 -0500
committerZach DeCook <zachdecook@librem.one>2022-11-19 17:51:34 -0500
commit37cb602acfc6e28dbd163071ecc77d1d362ab1f8 (patch)
tree11b110182340fe2097b1a5eb888ed17a7f452354
parent51cd1b7953145134b387ecf6b3606b4257c2b9a7 (diff)
downloadHexBoard-37cb602acfc6e28dbd163071ecc77d1d362ab1f8.tar.gz
v1.1 WIP
-rw-r--r--Buttons.ino77
-rw-r--r--HexBoard_V1.1.ino266
-rw-r--r--HexBoard_V1.ino504
-rw-r--r--LEDs.ino38
-rw-r--r--MIDI.ino15
5 files changed, 396 insertions, 504 deletions
diff --git a/Buttons.ino b/Buttons.ino
new file mode 100644
index 0000000..ecc209f
--- /dev/null
+++ b/Buttons.ino
@@ -0,0 +1,77 @@
+void readDigitalButtons() {
+  if (diagnostics == 1) {
+    Serial.println();
+  }
+  // Button Deck
+  for (int rowIndex = 0; rowIndex < rowCount; rowIndex++)  // Iterate through each of the row pins on the multiplexing chip.
+  {
+    digitalWrite(m1p, rowIndex & 1);
+    digitalWrite(m2p, (rowIndex & 2) >> 1);
+    digitalWrite(m4p, (rowIndex & 4) >> 2);
+    digitalWrite(m8p, (rowIndex & 8) >> 3);
+    for (byte columnIndex = 0; columnIndex < columnCount; columnIndex++)  // Now iterate through each of the column pins that are connected to the current row pin.
+    {
+      byte columnPin = columns[columnIndex];                              // Hold the currently selected column pin in a variable.
+      pinMode(columnPin, INPUT_PULLUP);                                   // Set that row pin to INPUT_PULLUP mode (+3.3V / HIGH).
+      byte buttonNumber = columnIndex + (rowIndex * columnCount);         // Assign this location in the matrix a unique number.
+      delayMicroseconds(10);                                              // Delay to give the pin modes time to change state (false readings are caused otherwise).
+      previousActiveButtons[buttonNumber] = activeButtons[buttonNumber];  // Track the "previous" variable for comparison.
+      byte buttonState = digitalRead(columnPin);                          // (don't)Invert reading due to INPUT_PULLUP, and store the currently selected pin state.
+      if (buttonState == LOW) {
+        if (diagnostics == 1) {
+          Serial.print("1");
+        } else if (diagnostics == 2) {
+          Serial.println(buttonNumber);
+        }
+        if (!previousActiveButtons[buttonNumber]) {
+          // newpress time
+          activeButtonsTime[buttonNumber] = millis();
+        }
+        // TODO: Implement debounce?
+        activeButtons[buttonNumber] = 1;
+      } else {
+        // Otherwise, the button is inactive, write a 0.
+        if (diagnostics == 1) {
+          Serial.print("0");
+        }
+        activeButtons[buttonNumber] = 0;
+      }
+      // Set the selected column pin back to INPUT mode (0V / LOW).
+      pinMode(columnPin, INPUT);
+    }
+  }
+}
+
+void playNotes() {
+  for (int i = 0; i < elementCount; i++)  // For all buttons in the deck
+  {
+    if (activeButtons[i] != previousActiveButtons[i])  // If a change is detected
+    {
+      if (activeButtons[i] == 1)  // If the button is active (newpress)
+      {
+        if (currentLayout[i] < 128) {
+          strip.setPixelColor(i, strip.ColorHSV((currentLayout[i] % 12) * 5006, 255, 255));
+          noteOn(midiChannel, (currentLayout[i] + octave) % 128, midiVelocity);
+        } else {
+          commandPress(currentLayout[i]);
+        }
+      } else {
+        // If the button is inactive (released)
+        if (currentLayout[i] < 128) {
+          setLayoutLED(i);
+          noteOff(midiChannel, (currentLayout[i] + octave) % 128, 0);
+        } else {
+          commandRelease(currentLayout[i]);
+        }
+      }
+    }
+  }
+}
+
+void heldButtons() {
+  for (int i = 0; i < elementCount; i++) {
+    if (activeButtons[i]) {
+      //if (
+    }
+  }
+}
\ No newline at end of file
diff --git a/HexBoard_V1.1.ino b/HexBoard_V1.1.ino
new file mode 100644
index 0000000..6c5b3fd
--- /dev/null
+++ b/HexBoard_V1.1.ino
@@ -0,0 +1,266 @@
+// Hardware Information:
+// Generic RP2040 running at 133MHz with 16MB of flash
+
+// Brilliant resource for dealing with hexagonal coordinates. https://www.redblobgames.com/grids/hexagons/
+// Might be useful for animations and stuff like that.
+
+#include <Arduino.h>
+#include <Adafruit_TinyUSB.h>
+#include <MIDI.h>
+#include <Adafruit_NeoPixel.h>
+
+// USB MIDI object
+Adafruit_USBD_MIDI usb_midi;
+
+// Create a new instance of the Arduino MIDI Library,
+// and attach usb_midi as the transport.
+MIDI_CREATE_INSTANCE(Adafruit_USBD_MIDI, usb_midi, MIDI);
+
+#define LED_PIN 22
+#define LED_COUNT 140
+
+Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_RGB + NEO_KHZ800);
+
+//
+// Button matrix and LED locations
+// Portrait orientation top view:
+//            9   8   7   6   5   4   3   2   1
+//         20  19  18  17  16  15  14  13  12  11
+//           29  28  27  26  25  24  23  22  21
+//         40  39  38  37  36  35  34  33  32  31
+//           49  48  47  46  45  44  43  42  41
+//         60  59  58  57  56  55  54  53  52  51
+//   10      69  68  67  66  65  64  63  62  61
+// 30      80  79  78  77  76  75  74  73  72  71
+//   50      89  88  87  86  85  84  83  82  81
+// 70     100 99  98  97  96  95  94  93  92  91
+//   90     109 108 107 106 105 104 103 102 101
+//110     120 119 118 117 116 115 114 113 112 111
+//  130     129 128 127 126 125 124 123 122 121
+//        140 139 138 137 136 135 134 133 132 131
+
+// DIAGNOSTICS
+// 1 = Full button test (1 and 0)
+// 2 = Button test (button number)
+// 3 = MIDI output test
+int diagnostics = 0;
+
+// Define digital button matrix pins
+const byte columns[] = { 14, 15, 13, 12, 11, 10, 9, 8, 7, 6 };  // Column pins in order from right to left
+const int m1p = 4;                                              // Multiplexing chip control pins
+const int m2p = 5;
+const int m4p = 2;
+const int m8p = 3;
+// 16 & 17 reserved for lights.
+const byte columnCount = sizeof(columns);          // The number of columns in the matrix
+const byte rowCount = 14;                          // The number of rows in the matrix
+const byte elementCount = columnCount * rowCount;  // The number of elements in the matrix
+
+// Since MIDI only uses 7 bits, we can give greater values special meanings.
+// (see commandPress)
+const int OCT_DN = 128;
+const int OCT_UP = 129;
+const int BT_TOG = 130;
+const int LAY_MD = 131;
+const int LGH_MD = 132;
+const int PTB_DN = 133;
+const int PTB_UP = 134;
+const int BK_TOG = 135;
+const int UNUSED = 255;
+
+#define ROW_FLIP(x, ix, viii, vii, vi, v, iv, iii, ii, i) i, ii, iii, iv, v, vi, vii, viii, ix, x
+//hacky macro because I (Jared) messed up the board layout - I'll do better next time! xD
+
+// MIDI note value tables
+const byte wickiHaydenLayout[elementCount] = {
+  ROW_FLIP(BK_TOG, 90, 92, 94, 96, 98, 100, 102, 104, 106),
+  ROW_FLIP(83, 85, 87, 89, 91, 93, 95, 97, 99, 101),
+  ROW_FLIP(LGH_MD, 78, 80, 82, 84, 86, 88, 90, 92, 94),
+  ROW_FLIP(71, 73, 75, 77, 79, 81, 83, 85, 87, 89),
+  ROW_FLIP(LAY_MD, 66, 68, 70, 72, 74, 76, 78, 80, 82),
+  ROW_FLIP(59, 61, 63, 65, 67, 69, 71, 73, 75, 77),
+  ROW_FLIP(OCT_UP, 54, 56, 58, 60, 62, 64, 66, 68, 70),
+  ROW_FLIP(47, 49, 51, 53, 55, 57, 59, 61, 63, 65),
+  ROW_FLIP(OCT_DN, 42, 44, 46, 48, 50, 52, 54, 56, 58),
+  ROW_FLIP(35, 37, 39, 41, 43, 45, 47, 49, 51, 53),
+  ROW_FLIP(PTB_UP, 30, 32, 34, 36, 38, 40, 42, 44, 46),
+  ROW_FLIP(23, 25, 27, 29, 31, 33, 35, 37, 39, 41),
+  ROW_FLIP(PTB_DN, 18, 20, 22, 24, 26, 28, 30, 32, 34),
+  ROW_FLIP(11, 13, 15, 17, 19, 21, 23, 25, 27, 29)
+};
+const byte harmonicTableLayout[elementCount] = {
+  ROW_FLIP(BK_TOG, 83, 76, 69, 62, 55, 48, 41, 34, 27),
+  ROW_FLIP(86, 79, 72, 65, 58, 51, 44, 37, 30, 23),
+  ROW_FLIP(LGH_MD, 82, 75, 68, 61, 54, 47, 40, 33, 26),
+  ROW_FLIP(85, 78, 71, 64, 57, 50, 43, 36, 29, 22),
+  ROW_FLIP(LAY_MD, 81, 74, 67, 60, 53, 46, 39, 32, 25),
+  ROW_FLIP(84, 77, 70, 63, 56, 49, 42, 35, 28, 21),
+  ROW_FLIP(OCT_UP, 80, 73, 66, 59, 52, 45, 38, 31, 24),
+  ROW_FLIP(83, 76, 69, 62, 55, 48, 41, 34, 27, 20),
+  ROW_FLIP(OCT_DN, 79, 72, 65, 58, 51, 44, 37, 30, 23),
+  ROW_FLIP(82, 75, 68, 61, 54, 47, 40, 33, 26, 19),
+  ROW_FLIP(PTB_UP, 78, 71, 64, 57, 50, 43, 36, 29, 22),
+  ROW_FLIP(81, 74, 67, 60, 53, 46, 39, 32, 25, 18),
+  ROW_FLIP(PTB_DN, 77, 70, 63, 56, 49, 42, 35, 28, 21),
+  ROW_FLIP(80, 73, 66, 59, 52, 45, 38, 31, 24, 17)
+};
+const byte gerhardLayout[elementCount] = {
+  ROW_FLIP(BK_TOG, 74, 73, 72, 71, 70, 69, 68, 67, 66),
+  ROW_FLIP(71, 70, 69, 68, 67, 66, 65, 64, 63, 62),
+  ROW_FLIP(LGH_MD, 67, 66, 65, 64, 63, 62, 61, 60, 59),
+  ROW_FLIP(64, 63, 62, 61, 60, 59, 58, 57, 56, 55),
+  ROW_FLIP(LAY_MD, 60, 59, 58, 57, 56, 55, 54, 53, 52),
+  ROW_FLIP(57, 56, 55, 54, 53, 52, 51, 50, 49, 48),
+  ROW_FLIP(OCT_UP, 53, 52, 51, 50, 49, 48, 47, 46, 45),
+  ROW_FLIP(50, 49, 48, 47, 46, 45, 44, 43, 42, 41),
+  ROW_FLIP(OCT_DN, 46, 45, 44, 43, 42, 41, 40, 39, 38),
+  ROW_FLIP(43, 42, 41, 40, 39, 38, 37, 36, 35, 34),
+  ROW_FLIP(PTB_UP, 39, 38, 37, 36, 35, 34, 33, 32, 31),
+  ROW_FLIP(36, 35, 34, 33, 32, 31, 30, 29, 28, 27),
+  ROW_FLIP(PTB_DN, 32, 31, 30, 29, 28, 27, 26, 25, 24),
+  ROW_FLIP(29, 28, 27, 26, 25, 24, 23, 22, 21, 20)
+};
+// LEDs for OCT_UP/OCT_DN status.
+const byte octUpSW = 70 - 1;
+const byte octDnSW = 90 - 1;
+const byte layMdSW = 50 - 1;
+
+const byte *currentLayout = wickiHaydenLayout;
+
+// Global time variables
+unsigned long currentTime;  // Program loop consistent variable for time in milliseconds since power on
+const byte debounceTime = 2;  // Global digital button debounce time in milliseconds
+
+// Variables for holding digital button states and activation times
+byte activeButtons[elementCount];               // Array to hold current note button states
+byte previousActiveButtons[elementCount];       // Array to hold previous note button states for comparison
+unsigned long activeButtonsTime[elementCount];  // Array to track last note button activation time for debounce
+
+
+// MIDI channel assignment
+byte midiChannel = 1;  // Current MIDI channel (changed via user input)
+
+// Octave modifier
+int octave = 0;  // Apply a MIDI note number offset (changed via user input in steps of 12)
+
+bool blackKeys = true;  // whether the black keys should be dimmer
+
+// Velocity levels
+byte midiVelocity = 95;  // Default velocity
+// END SETUP SECTION
+// ------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+void setup() {
+#if defined(ARDUINO_ARCH_MBED) && defined(ARDUINO_ARCH_RP2040)
+  // Manual begin() is required on core without built-in support for TinyUSB such as mbed rp2040
+  TinyUSB_Device_Init(0);
+#endif
+
+  //usb_midi.setStringDescriptor("HexBoard MIDI");
+
+  // Initialize MIDI, and listen to all MIDI channels
+  // This will also call usb_midi's begin()
+  MIDI.begin(MIDI_CHANNEL_OMNI);
+
+  // Set serial to make uploads work without bootsel button
+  Serial.begin(115200);
+
+  // Set pinModes for the digital button matrix.
+  for (int pinNumber = 0; pinNumber < columnCount; pinNumber++)  // For each column pin...
+  {
+    pinMode(columns[pinNumber], INPUT_PULLUP);  // set the pinMode to INPUT_PULLUP (+3.3V / HIGH).
+  }
+  pinMode(m1p, OUTPUT);  // Setting the row multiplexer pins to output.
+  pinMode(m2p, OUTPUT);
+  pinMode(m4p, OUTPUT);
+  pinMode(m8p, OUTPUT);
+  Serial.begin(115200);
+  strip.begin();             // INITIALIZE NeoPixel strip object (REQUIRED)
+  strip.show();              // Turn OFF all pixels ASAP
+  strip.setBrightness(128);  // Set BRIGHTNESS (max = 255)
+  setOctLED();
+  setLayoutLEDs();
+  strip.setPixelColor(layMdSW, 255, 0, 0);
+
+  // wait until device mounted
+  while (!TinyUSBDevice.mounted()) delay(1);
+
+  // Print diagnostic troubleshooting information to serial monitor
+  diagnosticTest();
+}
+
+// ------------------------------------------------------------------------------------------------------------------------------------------------------------
+// START LOOP SECTION
+void loop() {
+  // Store the current time in a uniform variable for this program loop
+  currentTime = millis();
+
+  // Read and store the digital button states of the scanning matrix
+  readDigitalButtons();
+
+  // Act on those buttons
+  playNotes();
+
+  // Held Buttons
+  heldButtons();
+
+  // Do the LEDS
+  strip.show();
+
+  // Read any new MIDI messages
+  MIDI.read();
+}
+// END LOOP SECTION
+// ------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+
+// ------------------------------------------------------------------------------------------------------------------------------------------------------------
+// START FUNCTIONS SECTION
+
+void diagnosticTest() {
+  if (diagnostics > 0) {
+    Serial.println("Zach was here");
+  }
+}
+
+void commandPress(byte command) {
+  // Keep octave between ~-12~ 0 and 24
+  if (command == OCT_DN) {
+    if (octave >= 12) {
+      octave -= 12;
+      setOctLED();
+      strip.setPixelColor(octDnSW, 120, 120, 120);
+    }
+  } else if (command == OCT_UP) {
+    if (octave <= 12) {
+      octave += 12;
+      setOctLED();
+      strip.setPixelColor(octUpSW, 120, 120, 120);
+    }
+  } else if (command == LAY_MD) {
+    if (currentLayout == wickiHaydenLayout) {
+      currentLayout = harmonicTableLayout;
+    } else if (currentLayout == harmonicTableLayout) {
+      currentLayout = gerhardLayout;
+    } else {
+      currentLayout = wickiHaydenLayout;
+    }
+    setLayoutLEDs();
+  } else if (command == BK_TOG) {
+    blackKeys = !blackKeys;
+    setLayoutLEDs();
+  }
+}
+void commandRelease(byte command) {
+  if (command == OCT_DN) {
+    setOctLED();
+  } else if (command == OCT_UP) {
+    setOctLED();
+  }
+}
+
+// END FUNCTIONS SECTION
+// ------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+// END OF PROGRAM
+// ------------------------------------------------------------------------------------------------------------------------------------------------------------
\ No newline at end of file
diff --git a/HexBoard_V1.ino b/HexBoard_V1.ino
deleted file mode 100644
index d0a8a84..0000000
--- a/HexBoard_V1.ino
+++ /dev/null
@@ -1,504 +0,0 @@
-// Hardware Information:
-// Teensy LC set to 48MHz with USB type MIDI
-#include <FastLED.h>
-
-#include "Adafruit_BLE.h"
-#include "Adafruit_BluefruitLE_UART.h"
-#include "Adafruit_BLEMIDI.h"
-#include "BluefruitConfig.h"
-
-#define FACTORYRESET_ENABLE         0
-#define MINIMUM_FIRMWARE_VERSION    "0.7.0"
-
-#define LEDS_PIN 17
-#define NUM_LEDS 140
-
-Adafruit_BluefruitLE_UART ble(Serial1, -1);
-
-Adafruit_BLEMIDI blemidi(ble);
-
-bool bleModuleEnabled = false;
-
-bool isConnected = false;
-
-// Bluetooth error messages
-void error(const __FlashStringHelper*err) {
-  Serial.println(err);
-  while (1);
-}
-//Bluetooth callbacks
-void connected(void)
-{
-  isConnected = true;
-  Serial.println("CONNECTED!");
-  //Zach make bluetooth light go solid once connected
-}
-void disconnected(void)
-{
-  Serial.println("disconnected");
-  isConnected = false;
-  //Zach make bluetooth light start blinking again once disconnected
-}
-
-CRGB leds[NUM_LEDS];
-
-void init_leds()
-{
-  FastLED.addLeds<WS2811, LEDS_PIN, RGB>(leds, NUM_LEDS);
-  /*Max Brightness. Recommended 100 or lower for usb power to stay under 2 amps. Increase up to 255 at your own risk.
-  Board can handle full power (theoretically 8.4 amps at max brightness) while only getting warm, but external power
-  is required to meet this. Use capable power supply on EXT PWR headers.*/
-  FastLED.setBrightness(200);
-  FastLED.setMaxPowerInVoltsAndMilliamps(5,1000);
-  for (int i=0; i < NUM_LEDS; i++) {
-    leds[i] = CRGB::Black;
-  }
-}
-
-bool bluetooth = false;
-void init_bluetooth()
-{
-/* Initialise the module */
-  Serial.print(F("Initialising the Bluefruit LE module: "));
-
-  if ( !ble.begin(VERBOSE_MODE) )
-  {
-    error(F("Couldn't find Bluefruit, make sure it's in CoMmanD mode & check wiring?"));
-  }
-  Serial.println( F("OK!") );
-
-  if ( FACTORYRESET_ENABLE )
-  {
-    /* Perform a factory reset to make sure everything is in a known state */
-    Serial.println(F("Performing a factory reset: "));
-    if ( ! ble.factoryReset() ) {
-      error(F("Couldn't factory reset"));
-    }
-  }
-
-  //ble.sendCommandCheckOK(F("AT+uartflow=off"));
-  ble.echo(false);
-
-  Serial.println("Requesting Bluefruit info:");
-  /* Print Bluefruit information */
-  ble.info();
-
-  /* Set BLE callbacks */
-  ble.setConnectCallback(connected);
-  ble.setDisconnectCallback(disconnected);
-
-  Serial.println(F("Enable MIDI: "));
-  if ( ! blemidi.begin(true) )
-  {
-    error(F("Could not enable Bluetooth MIDI"));
-  }
-
-  ble.verbose(false);
-  Serial.print(F("Waiting for a connection..."));
-  
-  bluetooth = true;
-  //Zach add bluetooth button blinking here until connection made
-}
-void shutdown_bluetooth()
-{
-  ble.end();
-  bluetooth = false;
-}
-
-//
-// Button matrix and LED locations
-// Portrait orientation top view:
-//            9   8   7   6   5   4   3   2   1
-//         20  19  18  17  16  15  14  13  12  11
-//           29  28  27  26  25  24  23  22  21
-//         40  39  38  37  36  35  34  33  32  31
-//           49  48  47  46  45  44  43  42  41
-//         60  59  58  57  56  55  54  53  52  51
-//   10      69  68  67  66  65  64  63  62  61
-// 30      80  79  78  77  76  75  74  73  72  71
-//   50      89  88  87  86  85  84  83  82  81
-// 70     100 99  98  97  96  95  94  93  92  91
-//   90     109 108 107 106 105 104 103 102 101
-//110     120 119 118 117 116 115 114 113 112 111
-//  130     129 128 127 126 125 124 123 122 121
-//        140 139 138 137 136 135 134 133 132 131
-
-//DIAGNOSTICS
-int diagnostics = 0;
-
-// Define digital button matrix pins
-const byte columns[] = { 25, 24,  9,  8,  7,  6,  5,  4,  3,  2};                // Column pins in order from right to left
-const byte rows[]    = {10, 11, 12, 13, 14, 15, 16, 18, 19, 20, 21, 22, 23, 26}; // Row pins in order from top to bottom
-// 16 & 17 reserved for lights.
-const byte columnCount      = sizeof(columns);                          // The number of columns in the matrix
-const byte rowCount         = sizeof(rows);                             // The number of rows in the matrix
-const byte elementCount     = columnCount * rowCount;// The number of elements in the matrix
-
-// Since MIDI only uses 7 bits, we can give greater values special meanings.
-// (see commandPress)
-const int OCT_DN = 128;
-const int OCT_UP = 129;
-const int BT_TOG = 130;
-const int LAY_MD = 131;
-const int LGH_MD = 132;
-const int PTB_DN = 133;
-const int PTB_UP = 134;
-const int BK_TOG = 135;
-const int UNUSED = 255;
-
-#define ROW_FLIP(x, ix, viii, vii, vi, v, iv, iii, ii, i) i, ii, iii, iv, v, vi, vii, viii, ix, x
-//hacky macro because we typed them in wrong???
-//#define NO_FLIP(x, ix, viii, vii, vi, v, iv, iii, ii, i) i, x, ix, viii, vii, vi, v, iv, iii, ii
-
-
-// MIDI note value tables
-const byte wickiHaydenLayout[elementCount] = {
-ROW_FLIP(BK_TOG, 90,  92,  94,  96,  98, 100, 102, 104, 106),
-ROW_FLIP(     83,  85,  87,  89,  91,  93,  95,  97,  99, 101),
-ROW_FLIP(LGH_MD, 78,  80,  82,  84,  86,  88,  90,  92,  94),
-ROW_FLIP(     71,  73,  75,  77,  79,  81,  83,  85,  87,  89),
-ROW_FLIP(LAY_MD, 66,  68,  70,  72,  74,  76,  78,  80,  82),
-ROW_FLIP(     59,  61,  63,  65,  67,  69,  71,  73,  75,  77),
-ROW_FLIP(OCT_UP, 54,  56,  58,  60,  62,  64,  66,  68,  70),
-ROW_FLIP(     47,  49,  51,  53,  55,  57,  59,  61,  63,  65),
-ROW_FLIP(OCT_DN, 42,  44,  46,  48,  50,  52,  54,  56,  58),
-ROW_FLIP(     35,  37,  39,  41,  43,  45,  47,  49,  51,  53),
-ROW_FLIP(PTB_UP, 30,  32,  34,  36,  38,  40,  42,  44,  46),
-ROW_FLIP(     23,  25,  27,  29,  31,  33,  35,  37,  39,  41),
-ROW_FLIP(PTB_DN, 18,  20,  22,  24,  26,  28,  30,  32,  34),
-ROW_FLIP(     11,  13,  15,  17,  19,  21,  23,  25,  27,  29)
-};
-const byte harmonicTableLayout[elementCount] = {
-ROW_FLIP(BK_TOG, 83,  76,  69,  62,  55,  48,  41,  34,  27),
-ROW_FLIP(     86,  79,  72,  65,  58,  51,  44,  37,  30,  23),
-ROW_FLIP(LGH_MD, 82,  75,  68,  61,  54,  47,  40,  33,  26),
-ROW_FLIP(     85,  78,  71,  64,  57,  50,  43,  36,  29,  22),
-ROW_FLIP(LAY_MD, 81,  74,  67,  60,  53,  46,  39,  32,  25),
-ROW_FLIP(     84,  77,  70,  63,  56,  49,  42,  35,  28,  21),
-ROW_FLIP(OCT_UP, 80,  73,  66,  59,  52,  45,  38,  31,  24),
-ROW_FLIP(     83,  76,  69,  62,  55,  48,  41,  34,  27,  20),
-ROW_FLIP(OCT_DN, 79,  72,  65,  58,  51,  44,  37,  30,  23),
-ROW_FLIP(     82,  75,  68,  61,  54,  47,  40,  33,  26,  19),
-ROW_FLIP(PTB_UP, 78,  71,  64,  57,  50,  43,  36,  29,  22),
-ROW_FLIP(     81,  74,  67,  60,  53,  46,  39,  32,  25,  18),
-ROW_FLIP(PTB_DN, 77,  70,  63,  56,  49,  42,  35,  28,  21),
-ROW_FLIP(     80,  73,  66,  59,  52,  45,  38,  31,  24,  17)
-};
-const byte gerhardLayout[elementCount] = {
-ROW_FLIP(BK_TOG, 74,  73,  72,  71,  70,  69,  68,  67,  66),
-ROW_FLIP(     71,  70,  69,  68,  67,  66,  65,  64,  63,  62),
-ROW_FLIP(LGH_MD, 67,  66,  65,  64,  63,  62,  61,  60,  59),
-ROW_FLIP(     64,  63,  62,  61,  60,  59,  58,  57,  56,  55),
-ROW_FLIP(LAY_MD, 60,  59,  58,  57,  56,  55,  54,  53,  52),
-ROW_FLIP(     57,  56,  55,  54,  53,  52,  51,  50,  49,  48),
-ROW_FLIP(OCT_UP, 53,  52,  51,  50,  49,  48,  47,  46,  45),
-ROW_FLIP(     50,  49,  48,  47,  46,  45,  44,  43,  42,  41),
-ROW_FLIP(OCT_DN, 46,  45,  44,  43,  42,  41,  40,  39,  38),
-ROW_FLIP(     43,  42,  41,  40,  39,  38,  37,  36,  35,  34),
-ROW_FLIP(PTB_UP, 39,  38,  37,  36,  35,  34,  33,  32,  31),
-ROW_FLIP(     36,  35,  34,  33,  32,  31,  30,  29,  28,  27),
-ROW_FLIP(PTB_DN, 32,  31,  30,  29,  28,  27,  26,  25,  24),
-ROW_FLIP(     29,  28,  27,  26,  25,  24,  23,  22,  21,  20)
-};
-// LEDs for OCT_UP/OCT_DN status.
-const byte octUpSW = 70 - 1;
-const byte octDnSW = 90 - 1;
-const byte layMdSW = 50 - 1;
-
-const byte *currentLayout = wickiHaydenLayout;
-
-// Global time variables
-unsigned long   currentTime; // Program loop consistent variable for time in milliseconds since power on
-unsigned long timeBothPressed;
-const byte      debounceTime = 2; // Global digital button debounce time in milliseconds
-
-// Variables for holding digital button states and activation times
-byte            activeButtons[elementCount];                            // Array to hold current note button states
-byte            previousActiveButtons[elementCount];                    // Array to hold previous note button states for comparison
-unsigned long   activeButtonsTime[elementCount];                        // Array to track last note button activation time for debounce
-
-
-// MIDI channel assignment
-byte midiChannel = 0;                                                   // Current MIDI channel (changed via user input)
-
-// Octave modifier
-int octave = 0;// Apply a MIDI note number offset (changed via user input in steps of 12)
-
-bool blackKeys = true; // whether the black keys should be dimmer
-
-// Velocity levels
-byte velocity = 95;                                                     // Default velocity
-// END SETUP SECTION
-// ------------------------------------------------------------------------------------------------------------------------------------------------------------
-
-void setup()
-{ 
-  // Set pinModes for the digital button matrix.
-  for (int pinNumber = 0; pinNumber < columnCount; pinNumber++)                   // For each column pin...
-  {
-    pinMode(columns[pinNumber], INPUT_PULLUP);                                  // set the pinMode to INPUT_PULLUP (+3.3V / HIGH).
-  }
-  for (int pinNumber = 0; pinNumber < rowCount; pinNumber++)                      // For each row pin...
-  {
-    pinMode(rows[pinNumber], INPUT);                                            // Set the pinMode to INPUT (0V / LOW).
-  }
-  Serial.begin(115200);
-  if (bleModuleEnabled == true){
-    init_bluetooth();
-  }
-  init_leds();
-  setOctLED();
-  setLayoutLEDs();
-  leds[layMdSW] = CRGB::Red;
-
-  // Print diagnostic troubleshooting information to serial monitor
-  diagnosticTest();
-}
-
-// ------------------------------------------------------------------------------------------------------------------------------------------------------------
-// START LOOP SECTION
-void loop()
-{
-  // Store the current time in a uniform variable for this program loop
-  currentTime = millis();
-
-  // Read and store the digital button states of the scanning matrix
-  readDigitalButtons();
-
-  // Act on those buttons
-  playNotes();
-
-  // Held Buttons
-  heldButtons();
-
-  // Do the LEDS
-  FastLED.show();
-}
-// END LOOP SECTION
-// ------------------------------------------------------------------------------------------------------------------------------------------------------------
-
-
-// ------------------------------------------------------------------------------------------------------------------------------------------------------------
-// START FUNCTIONS SECTION
-
-void diagnosticTest()
-{
-  if (diagnostics > 0) {
-    Serial.println("Zach was here");
-  }
-}
-
-void readDigitalButtons()
-{
-  if (diagnostics == 1){
-    Serial.println();
-  }
-  // Button Deck
-  for (byte rowIndex = 0; rowIndex < rowCount; rowIndex++) // Iterate through each of the row pins.
-  {
-    byte rowPin = rows[rowIndex]; // Hold the currently selected row pin in a variable.
-    pinMode(rowPin, OUTPUT); // Set that row pin to OUTPUT mode and...
-    digitalWrite(rowPin, LOW); // set the pin state to LOW turning it into a temporary ground.
-    for  (byte columnIndex = 0; columnIndex < columnCount; columnIndex++)// Now iterate through each of the column pins that are connected to the current row pin.
-    {
-      byte columnPin = columns[columnIndex]; // Hold the currently selected column pin in a variable.
-      pinMode(columnPin, INPUT_PULLUP); // Set that row pin to INPUT_PULLUP mode (+3.3V / HIGH).
-      byte buttonNumber = columnIndex + (rowIndex * columnCount); // Assign this location in the matrix a unique number.
-      delayMicroseconds(50); // Delay to give the pin modes time to change state (false readings are caused otherwise).
-      previousActiveButtons[buttonNumber] = activeButtons[buttonNumber]; // Track the "previous" variable for comparison.
-      byte buttonState = digitalRead(columnPin); // (don't)Invert reading due to INPUT_PULLUP, and store the currently selected pin state.
-      if (buttonState == LOW ) {
-        if (diagnostics == 1){
-          Serial.print("1");
-        } else if (diagnostics == 2) {
-          Serial.println(buttonNumber);
-        }
-        if (!previousActiveButtons[buttonNumber]) {
-          // newpress time
-          activeButtonsTime[buttonNumber] = millis();
-        }
-        // TODO: Implement debounce?
-        activeButtons[buttonNumber] = 1;
-      } else {
-        // Otherwise, the button is inactive, write a 0.
-        if (diagnostics == 1){
-          Serial.print("0");
-        }
-        activeButtons[buttonNumber] = 0;
-      }
-      // Set the selected column pin back to INPUT mode (0V / LOW).
-      pinMode(columnPin, INPUT);
-    }
-    // Set the selected row pin back to INPUT mode (0V / LOW).
-    pinMode(rowPin, INPUT);
-  }
-}
-
-void playNotes()
-{
-  for (int i = 0; i < elementCount; i++) // For all buttons in the deck
-  {
-    if (activeButtons[i] != previousActiveButtons[i]) // If a change is detected
-    {
-      if (activeButtons[i] == 1) // If the button is active (newpress)
-      {
-        if (currentLayout[i] < 128) {
-          //leds[i] = CRGB::White;
-          leds[i] = CHSV((currentLayout[i] % 12) * 21, 255, 255);
-          noteOn(midiChannel, (currentLayout[i] + octave) % 128 , velocity);
-        } else {
-          commandPress(currentLayout[i]);
-        }
-      } else {
-      // If the button is inactive (released)
-        if (currentLayout[i] < 128) {
-          setLayoutLED(i);
-          //leds[i] ;
-          noteOff(midiChannel, (currentLayout[i] + octave) % 128, 0);
-        } else {
-          commandRelease(currentLayout[i]);
-        }
-      }
-    }
-  }
-}
-
-void heldButtons()
-{
-  for (int i = 0; i < elementCount; i++) {
-    if (activeButtons[i]) {
-      //if (
-    }
-  }
-}
-
-// MIDI PACKET FUNCTIONS
-
-// Send MIDI Note On
-void noteOn(byte channel, byte pitch, byte velocity)
-{
-  if (isConnected == true){
-    blemidi.send(0x90, pitch, velocity);
-  }
-  else {
-    usbMIDI.sendNoteOn(pitch, velocity, channel);
-  }
-}
-// Send MIDI Note Off
-void noteOff(byte channel, byte pitch, byte velocity)
-{
-  if (isConnected == true){
-    blemidi.send(0x80, pitch, velocity);
-  }
-  else {
-    usbMIDI.sendNoteOff(pitch, velocity, channel);
-  }
-}
-
-void commandPress(byte command)
-{
-  // Keep octave between ~-12~ 0 and 24
-  if(command == OCT_DN) {
-    if (octave >= 12) {
-      octave -= 12;
-      setOctLED(); leds[octDnSW] = CRGB::White;
-    }
-  } else if (command == OCT_UP) {
-    if (octave <= 12) {
-      octave += 12;
-      setOctLED(); leds[octUpSW] = CRGB::White;
-    }
-  } else if (command == LAY_MD) {
-    if (currentLayout == wickiHaydenLayout) {
-      currentLayout = harmonicTableLayout;
-    } else if (currentLayout == harmonicTableLayout) {
-      currentLayout = gerhardLayout;
-    } else {
-      currentLayout = wickiHaydenLayout;
-    }
-    setLayoutLEDs();
-  } else if (command == BK_TOG) {
-    blackKeys = !blackKeys;
-    setLayoutLEDs();
-  }
-}
-void commandRelease(byte command)
-{
-  if (command == OCT_DN) {
-    setOctLED();
-  } else if (command == OCT_UP) {
-    setOctLED();
-  }
-}
-
-
-void setOctLED()
-{
-  /*if (octave <= -12) {
-    leds[octUpSW].setRGB(0xA0, 0, 0x20);
-    leds[octDnSW] = CRGB::Black; // No lower to go.
-  } else */if (octave <= 0) {
-    leds[octUpSW] = CRGB::Purple;
-    leds[octDnSW] = CRGB::Black; // No lower to go.
-  } else if (octave <= 12) {
-    leds[octUpSW] = CRGB::Blue;
-    leds[octDnSW].setRGB(0xA0, 0, 0x20);
-  } else if (octave <= 24) {
-    leds[octUpSW] = CRGB::Black; // No higher to go.
-    leds[octDnSW] = CRGB::Purple;
-  }
-}
-
-void setLayoutLEDs()
-{
-  for (int i = 0; i < elementCount; i++) {
-    if (currentLayout[i] <= 127) {
-      setLayoutLED(i);
-    }
-  }
-}
-void setLayoutLED(int i) {
-  leds[i] = CHSV((currentLayout[i] % 12) * 21, 255, 120);
-  // black keys darker
-  if(blackKeys){
-    // LEET programmers stuff
-    switch(currentLayout[i] % 12) {
-      // If it is one of the black keys, fall through to case 10.
-      case 1:
-      case 3:
-      case 6:
-      case 8:
-      // bitshift by 2 (efficient division by four)
-      case 10: leds[i] >>= 2; break;
-      // otherwise it was a white key. Do nothing
-      default: break;
-    }
-  }
-}
-
-// Control Change
-// 1st byte = Event type (0x0B = Control Change).
-// 2nd byte = Event type bitwise ORed with MIDI channel.
-// 3rd byte = MIDI CC number (7-bit range 0-127).
-// 4th byte = Control value (7-bit range 0-127).
-void controlChange(byte channel, byte control, byte value)
-{
-
-}
-
-// Pitch Bend
-// (14 bit value 0-16363, neutral position = 8192)
-// 1st byte = Event type (0x0E = Pitch bend change).
-// 2nd byte = Event type bitwise ORed with MIDI channel.
-// 3rd byte = The 7 least significant bits of the value.
-// 4th byte = The 7 most significant bits of the value.
-void pitchBendChange(byte channel, byte lowValue, byte highValue)
-{
-
-}
-
-// END FUNCTIONS SECTION
-// ------------------------------------------------------------------------------------------------------------------------------------------------------------
-
-// END OF PROGRAM
-// ------------------------------------------------------------------------------------------------------------------------------------------------------------
diff --git a/LEDs.ino b/LEDs.ino
new file mode 100644
index 0000000..5b72b65
--- /dev/null
+++ b/LEDs.ino
@@ -0,0 +1,38 @@
+void setOctLED() {
+  if (octave <= 0) {
+    strip.setPixelColor(octUpSW, 120, 0, 120);
+    strip.setPixelColor(octDnSW, 0, 0, 0);  // No lower to go.
+  } else if (octave <= 12) {
+    strip.setPixelColor(octUpSW, 0, 0, 120);
+    strip.setPixelColor(octDnSW, 120, 0, 0);
+  } else if (octave <= 24) {
+    strip.setPixelColor(octUpSW, 0, 0, 0);  //No higher to go.
+    strip.setPixelColor(octDnSW, 120, 0, 120);
+  }
+}
+
+void setLayoutLEDs() {
+  for (int i = 0; i < elementCount; i++) {
+    if (currentLayout[i] <= 127) {
+      setLayoutLED(i);
+    }
+  }
+}
+void setLayoutLED(int i) {
+  strip.setPixelColor(i, strip.ColorHSV((currentLayout[i] % 12) * 5006, 255, 120));
+  // black keys darker
+  if (blackKeys) {
+    // LEET programmers stuff
+    switch (currentLayout[i] % 12) {
+      // If it is one of the black keys, fall through to case 10.
+      case 1:
+      case 3:
+      case 6:
+      case 8:
+      // bitshift by 2 (efficient division by four)
+      case 10: strip.setPixelColor(i, strip.ColorHSV((currentLayout[i] % 12) * 5006, 255, 30)); break;
+      // otherwise it was a white key. Do nothing
+      default: break;
+    }
+  }
+}
\ No newline at end of file
diff --git a/MIDI.ino b/MIDI.ino
new file mode 100644
index 0000000..77c786b
--- /dev/null
+++ b/MIDI.ino
@@ -0,0 +1,15 @@
+// Send MIDI Note On
+void noteOn(byte channel, byte pitch, byte velocity) {
+  MIDI.sendNoteOn(pitch, velocity, channel);
+  if (diagnostics == 3) {
+    Serial.print(pitch);
+    Serial.print(", ");
+    Serial.print(velocity);
+    Serial.print(", ");
+    Serial.println(channel);
+  }
+}
+// Send MIDI Note Off
+void noteOff(byte channel, byte pitch, byte velocity) {
+  MIDI.sendNoteOff(pitch, velocity, channel);
+}
\ No newline at end of file