Skip to content

Instantly share code, notes, and snippets.

@possan
Created June 10, 2024 20:48
Show Gist options
  • Save possan/3652d589ee70aabdca7d522609f26b6b to your computer and use it in GitHub Desktop.
Save possan/3652d589ee70aabdca7d522609f26b6b to your computer and use it in GitHub Desktop.
Trellis launchpad midi colors
// 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