Firmware for HexBoard MIDI controller
-rw-r--r--HexBoard_V1.ino248
1 files changed, 165 insertions, 83 deletions
diff --git a/HexBoard_V1.ino b/HexBoard_V1.ino
index f9254a4..e3ad59f 100644
--- a/HexBoard_V1.ino
+++ b/HexBoard_V1.ino
@@ -2,20 +2,109 @@
// 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);
- FastLED.setBrightness(100);
+ /*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:
@@ -35,7 +124,7 @@ void init_leds()
// 140 139 138 137 136 135 134 133 132 131
//DIAGNOSTICS
-int diagnostics = 1;
+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
@@ -57,55 +146,58 @@ const int PTB_UP = 134;
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(BT_TOG, 78, 80, 82, 84, 86, 88, 90, 92, 94),
+ROW_FLIP(BT_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(LGH_MD, 66, 68, 70, 72, 74, 76, 78, 80, 82),
+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(LAY_MD, 54, 56, 58, 60, 62, 64, 66, 68, 70),
+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_UP, 42, 44, 46, 48, 50, 52, 54, 56, 58),
+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(OCT_DN, 30, 32, 34, 36, 38, 40, 42, 44, 46),
+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_UP, 18, 20, 22, 24, 26, 28, 30, 32, 34),
-ROW_FLIP( 11, 13, 15, 17, 19, 21, 23, 25, 27, 29),
-ROW_FLIP(PTB_DN, 6, 8, 10, 12, 14, 16, 18, 20, 22),
-ROW_FLIP( UNUSED, 1, 3, 5, 7, 9, 11, 13, 15, 17) // Oops, wasted key!
+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(BT_TOG, 20, 27, 34, 41, 48, 55, 62, 69, 76),
-ROW_FLIP( 17, 24, 31, 38, 45, 52, 59, 66, 73, 80),
-ROW_FLIP(LGH_MD, 21, 28, 35, 42, 49, 56, 63, 70, 77),
-ROW_FLIP( 18, 25, 32, 39, 46, 53, 60, 67, 74, 81),
-ROW_FLIP(LAY_MD, 22, 29, 36, 43, 50, 57, 64, 71, 78),
-ROW_FLIP( 19, 26, 33, 40, 47, 54, 61, 68, 75, 82),
-ROW_FLIP(OCT_UP, 23, 30, 37, 44, 51, 58, 65, 72, 79),
-ROW_FLIP( 20, 27, 34, 41, 48, 55, 62, 69, 76, 83),
-ROW_FLIP(OCT_DN, 24, 31, 38, 45, 52, 59, 66, 73, 80),
-ROW_FLIP( 21, 28, 35, 42, 49, 56, 63, 70, 77, 84),
-ROW_FLIP(PTB_UP, 25, 32, 39, 46, 53, 60, 67, 74, 81),
-ROW_FLIP( 22, 29, 36, 43, 50, 57, 64, 71, 78, 85),
-ROW_FLIP(PTB_DN, 26, 33, 40, 47, 54, 61, 68, 75, 82),
-ROW_FLIP( 23, 30, 37, 44, 51, 58, 65, 72, 79, 86)
+ROW_FLIP(BT_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(BT_TOG, 20, 21, 22, 23, 24, 25, 26, 27, 28),
-ROW_FLIP( 23, 24, 25, 26, 27, 28, 29, 30, 31, 32),
-ROW_FLIP(LGH_MD, 27, 28, 29, 30, 31, 32, 33, 34, 35),
-ROW_FLIP( 30, 31, 32, 33, 34, 35, 36, 37, 38, 39),
-ROW_FLIP(LAY_MD, 34, 35, 36, 37, 38, 39, 40, 41, 42),
-ROW_FLIP( 37, 38, 39, 40, 41, 42, 43, 44, 45, 46),
-ROW_FLIP(OCT_UP, 41, 42, 43, 44, 45, 46, 47, 48, 49),
-ROW_FLIP( 44, 45, 46, 47, 48, 49, 50, 51, 52, 53),
-ROW_FLIP(OCT_DN, 48, 49, 50, 51, 52, 53, 54, 55, 56),
-ROW_FLIP( 51, 52, 53, 54, 55, 56, 57, 58, 59, 60),
-ROW_FLIP(PTB_UP, 55, 56, 57, 58, 59, 60, 61, 62, 63),
-ROW_FLIP( 58, 59, 60, 61, 62, 63, 64, 65, 66, 67),
-ROW_FLIP(PTB_DN, 62, 63, 64, 65, 66, 67, 68, 69, 70),
-ROW_FLIP( 65, 66, 67, 68, 69, 70, 71, 72, 73, 74)
+ROW_FLIP(BT_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;
@@ -128,14 +220,11 @@ unsigned long activeButtonsTime[elementCount]; // Array
// MIDI channel assignment
byte midiChannel = 0; // Current MIDI channel (changed via user input)
-// MIDI program variables
-byte midiProgram[16]; // MIDI program selection per channel (0-15)
-
// Octave modifier
int octave = 0;// Apply a MIDI note number offset (changed via user input in steps of 12)
// Velocity levels
-byte velocity = 95; // Non-zero default velocity for testing; this will update via analog pot
+byte velocity = 95; // Default velocity
// END SETUP SECTION
// ------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -151,6 +240,9 @@ void setup()
pinMode(rows[pinNumber], INPUT); // Set the pinMode to INPUT (0V / LOW).
}
Serial.begin(115200);
+ if (bleModuleEnabled == true){
+ init_bluetooth();
+ }
init_leds();
setOctLED();
setLayoutLEDs();
@@ -173,6 +265,9 @@ void loop()
// Act on those buttons
playNotes();
+ // Held Buttons
+ heldButtons();
+
// Do the LEDS
FastLED.show();
}
@@ -245,7 +340,8 @@ void playNotes()
if (activeButtons[i] == 1) // If the button is active (newpress)
{
if (currentLayout[i] < 128) {
- leds[i] = CRGB::White;
+ //leds[i] = CRGB::White;
+ leds[i] = CHSV((currentLayout[i] % 12) * 21, 255, 255);
noteOn(midiChannel, (currentLayout[i] + octave) % 128 , velocity);
} else {
commandPress(currentLayout[i]);
@@ -254,6 +350,7 @@ void playNotes()
// 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]);
@@ -263,20 +360,36 @@ void playNotes()
}
}
+void heldButtons()
+{
+ for (int i = 0; i < elementCount; i++) {
+ if (activeButtons[i]) {
+ //if (
+ }
+ }
+}
+
// MIDI PACKET FUNCTIONS
// Send MIDI Note On
-// 1st byte = Event type (0x09 = note on, 0x08 = note off).
-// 2nd byte = Event type bitwise ORed with MIDI channel.
-// 3rd byte = MIDI note number.
-// 4th byte = Velocity (7-bit range 0-127)
void noteOn(byte channel, byte pitch, byte velocity)
{
- usbMIDI.sendNoteOn(pitch, velocity, channel);
+ if (isConnected == true){
+ blemidi.send(0x90, pitch, velocity);
+ }
+ else {
+ usbMIDI.sendNoteOn(pitch, velocity, channel);
+ }
}
-void loopNoteOn(byte channel, byte pitch, byte velocity)
+// 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)
@@ -339,7 +452,7 @@ void setLayoutLEDs()
}
}
void setLayoutLED(int i) {
- leds[i] = CHSV((currentLayout[i] % 12) * 21, 255, 200);
+ leds[i] = CHSV((currentLayout[i] % 12) * 21, 255, 120);
// black keys darker
switch(currentLayout[i] % 12) {
case 1:
@@ -351,20 +464,6 @@ void setLayoutLED(int i) {
}
}
-// Send MIDI Note Off
-// 1st byte = Event type (0x09 = note on, 0x08 = note off).
-// 2nd byte = Event type bitwise ORed with MIDI channel.
-// 3rd byte = MIDI note number.
-// 4th byte = Velocity (7-bit range 0-127)
-void noteOff(byte channel, byte pitch, byte velocity)
-{
- usbMIDI.sendNoteOff(pitch, velocity, channel);
-}
-void loopNoteOff(byte channel, byte pitch, byte velocity)
-{
-
-}
-
// Control Change
// 1st byte = Event type (0x0B = Control Change).
// 2nd byte = Event type bitwise ORed with MIDI channel.
@@ -374,19 +473,6 @@ void controlChange(byte channel, byte control, byte value)
{
}
-void loopControlChange(byte channel, byte control, byte value)
-{
-
-}
-
-// Program Change
-// 1st byte = Event type (0x0C = Program Change).
-// 2nd byte = Event type bitwise ORed with MIDI channel.
-// 3rd byte = Program value (7-bit range 0-127).
-void programChange(byte channel, byte value)
-{
-
-}
// Pitch Bend
// (14 bit value 0-16363, neutral position = 8192)
@@ -398,10 +484,6 @@ void pitchBendChange(byte channel, byte lowValue, byte highValue)
{
}
-void loopPitchBendChange(byte channel, byte lowValue, byte highValue)
-{
-
-}
// END FUNCTIONS SECTION
// ------------------------------------------------------------------------------------------------------------------------------------------------------------