about summary refs log tree commit diff
path: root/HexBoard_V1.1.ino
diff options
context:
space:
mode:
Diffstat (limited to 'HexBoard_V1.1.ino')
-rw-r--r--HexBoard_V1.1.ino266
1 files changed, 266 insertions, 0 deletions
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