Created
June 10, 2024 20:48
-
-
Save possan/3652d589ee70aabdca7d522609f26b6b to your computer and use it in GitHub Desktop.
Trellis launchpad midi colors
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Trellis M4 MIDI Keypad CC | |
// sends 32 notes, pitch bend & a CC from accelerometer tilt over USB MIDI | |
#include <Adafruit_Sensor.h> | |
#include <Adafruit_ADXL343.h> | |
#include <Adafruit_NeoTrellisM4.h> | |
#define MIDI_CHANNEL 0 // default channel # is 0 | |
// Set the value of first note, C is a good choice. Lowest C is 0. | |
// 36 is a good default. 48 is a high range. Set to 24 for a bass machine. | |
#define FIRST_MIDI_NOTE 36 | |
Adafruit_ADXL343 accel = Adafruit_ADXL343(123, &Wire1); | |
int xCC = 1; //choose a CC number to control with x axis tilting of the board. 1 is mod wheel, for example. | |
int last_xbend = 0; | |
int last_ybend = 0; | |
bool any_midi_in = false; | |
Adafruit_NeoTrellisM4 trellis = Adafruit_NeoTrellisM4(); | |
void setup() { | |
Serial.begin(115200); | |
//while (!Serial); | |
Serial.println("MIDI keypad & pitchbend!"); | |
trellis.begin(); | |
trellis.setBrightness(80); | |
// USB MIDI messages sent over the micro B USB port | |
Serial.println("Enabling MIDI on USB"); | |
trellis.enableUSBMIDI(true); | |
trellis.setUSBMIDIchannel(MIDI_CHANNEL); | |
// UART MIDI messages sent over the 4-pin STEMMA connector (3.3V logic) | |
Serial.println("Enabling MIDI on UART"); | |
trellis.enableUARTMIDI(true); | |
trellis.setUARTMIDIchannel(MIDI_CHANNEL); | |
trellis.autoUpdateNeoPixels(true); | |
// //do a little animation to show we're on | |
for (uint16_t i = 0; i < 32; i++) { | |
trellis.setPixelColor(i, Wheel(map(i, 0, 32, 0, 255))); | |
delay(20); | |
} | |
for (uint16_t i = 0; i < 32; i++) { | |
trellis.setPixelColor(i, 0x000000); | |
delay(20); | |
} | |
// trellis. | |
if (!accel.begin()) { | |
Serial.println("No accelerometer found"); | |
while (1) | |
; | |
} | |
} | |
void loop() { | |
// put your main code here, to run repeatedly: | |
trellis.tick(); | |
while (trellis.available()) { | |
keypadEvent e = trellis.read(); | |
int key = e.bit.KEY; | |
Serial.print("Keypad key: "); | |
Serial.println(key); | |
Serial.print("MIDI note: "); | |
Serial.println(FIRST_MIDI_NOTE + key); | |
if (e.bit.EVENT == KEY_JUST_PRESSED) { | |
Serial.println(" pressed\n"); | |
if (!any_midi_in) { | |
trellis.setPixelColor(key, 0xFFFFFF); | |
} | |
trellis.noteOn(FIRST_MIDI_NOTE + key, 64); | |
} else if (e.bit.EVENT == KEY_JUST_RELEASED) { | |
Serial.println(" released\n"); | |
if (!any_midi_in) { | |
trellis.setPixelColor(key, 0x0); | |
} | |
trellis.noteOff(FIRST_MIDI_NOTE + key, 64); | |
} | |
} | |
midiEventPacket_t rx; | |
do { | |
rx = MidiUSB.read(); | |
if (rx.header != 0) { | |
if (rx.header == 9) { | |
// Note on | |
int note = rx.byte2; | |
int vel = rx.byte3; | |
Serial.print("Received note on: "); | |
Serial.print(note, HEX); | |
Serial.print(" velocity:"); | |
Serial.println(vel, HEX); | |
int button = note - FIRST_MIDI_NOTE; | |
if (button >= 0 && button < 32) { | |
int red = ((vel >> 0) & 3) * 63; | |
int green = ((vel >> 4) & 3) * 63; | |
if (vel >= 0 && vel < 64) { | |
trellis.setPixelColor(button, (red << 16) | (green << 8)); | |
} else { | |
trellis.setPixelColor(button, 0x000000); | |
} | |
any_midi_in = true; | |
} | |
} else if (rx.header == 8) { | |
// Note off | |
int note = rx.byte2; | |
int vel = rx.byte3; | |
Serial.print("Ignoring note off: "); | |
Serial.print(note, HEX); | |
Serial.print(" velocity:"); | |
Serial.println(vel, HEX); | |
// int button = note - FIRST_MIDI_NOTE; | |
// if (button >= 0 && button < 32) { | |
// trellis.setPixelColor(button, 0x000000); | |
// any_midi_in = true; | |
// } | |
} else { | |
Serial.print("Received unhandled midi: "); | |
Serial.print(rx.header, HEX); | |
Serial.print("-"); | |
Serial.print(rx.byte1, HEX); | |
Serial.print("-"); | |
Serial.print(rx.byte2, HEX); | |
Serial.print("-"); | |
Serial.println(rx.byte3, HEX); | |
} | |
} | |
} while (rx.header != 0); | |
// Check for accelerometer | |
sensors_event_t event; | |
accel.getEvent(&event); | |
/* Display the results (acceleration is measured in m/s^2) */ | |
//Serial.print("X: "); Serial.print(event.acceleration.x); Serial.print(" "); | |
//Serial.print("Y: "); Serial.print(event.acceleration.y); Serial.print(" "); | |
//Serial.print("Z: "); Serial.print(event.acceleration.z); Serial.print(" ");Serial.println("m/s^2 "); | |
int xbend = 0; | |
int ybend = 0; | |
if (abs(event.acceleration.y) < 2.0) { // 2.0 m/s^2 | |
// don't make any bend unless they've really started moving it | |
ybend = 8192; // 8192 means no bend | |
} else { | |
if (event.acceleration.y > 0) { | |
ybend = ofMap(event.acceleration.y, 2.0, 10.0, 8192, 0, true); // 2 ~ 10 m/s^2 is downward bend | |
} else { | |
ybend = ofMap(event.acceleration.y, -2.0, -10.0, 8192, 16383, true); // -2 ~ -10 m/s^2 is upward bend | |
} | |
} | |
if (ybend != last_ybend) { | |
Serial.print("Y pitchbend: "); | |
Serial.println(ybend); | |
trellis.pitchBend(ybend); | |
last_ybend = ybend; | |
} | |
if (abs(event.acceleration.x) < 2.0) { // 2.0 m/s^2 | |
// don't make any bend unless they've really started moving it | |
xbend = 0; | |
} else { | |
if (event.acceleration.x > 0) { | |
xbend = ofMap(event.acceleration.x, 2.0, 10.0, 0, 127, true); // 2 ~ 10 m/s^2 is upward bend | |
} else { | |
xbend = ofMap(event.acceleration.x, -2.0, -10.0, 0, 127, true); // -2 ~ -10 m/s^2 is downward bend | |
} | |
} | |
if (xbend != last_xbend) { | |
Serial.print("X mod: "); | |
Serial.println(xbend); | |
trellis.controlChange(xCC, xbend); //xCC is set at top of sketch. e.g., CC 1 is Mod Wheel | |
last_xbend = xbend; | |
} | |
trellis.sendMIDI(); // send any pending MIDI messages | |
delay(4); | |
} | |
// void noteOn(byte channel, byte pitch, byte velocity) { | |
// midiEventPacket_t noteOn = {0x09, 0x90 | channel, pitch, velocity}; | |
// MidiUSB.sendMIDI(noteOn); | |
// } | |
// void noteOff(byte channel, byte pitch, byte velocity) { | |
// // midiEventPacket_t noteOff = {0x08, 0x80 | channel, pitch, velocity}; | |
// // MidiUSB.sendMIDI(noteOff); | |
// } | |
// floating point map | |
float ofMap(float value, float inputMin, float inputMax, float outputMin, float outputMax, bool clamp) { | |
float outVal = ((value - inputMin) / (inputMax - inputMin) * (outputMax - outputMin) + outputMin); | |
if (clamp) { | |
if (outputMax < outputMin) { | |
if (outVal < outputMax) outVal = outputMax; | |
else if (outVal > outputMin) outVal = outputMin; | |
} else { | |
if (outVal > outputMax) outVal = outputMax; | |
else if (outVal < outputMin) outVal = outputMin; | |
} | |
} | |
return outVal; | |
} | |
// Input a value 0 to 255 to get a color value. | |
// The colours are a transition r - g - b - back to r. | |
uint32_t Wheel(byte WheelPos) { | |
WheelPos = 255 - WheelPos; | |
if (WheelPos < 85) { | |
return trellis.Color(255 - WheelPos * 3, 0, WheelPos * 3); | |
} | |
if (WheelPos < 170) { | |
WheelPos -= 85; | |
return trellis.Color(0, WheelPos * 3, 255 - WheelPos * 3); | |
} | |
WheelPos -= 170; | |
return trellis.Color(WheelPos * 3, 255 - WheelPos * 3, 0); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment