From b2d726a953f72073704444cb28fbe6869e204d87 Mon Sep 17 00:00:00 2001 From: Ashley Strahle Date: Wed, 24 Jun 2026 01:25:45 +0000 Subject: [PATCH] Add Launchpad X velocity->color palette and matching startup animation --- src/led_stub.cpp | 139 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 122 insertions(+), 17 deletions(-) diff --git a/src/led_stub.cpp b/src/led_stub.cpp index ef46eff..3895e18 100644 --- a/src/led_stub.cpp +++ b/src/led_stub.cpp @@ -4,6 +4,49 @@ static PixelStompMux* mux_ptr = nullptr; +// Launchpad X color palette (velocity 1-127 mapped to colors) +static const uint32_t launchpad_palette[128] = { + 0x000000, // 0: off + 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, // 1-4: Red + 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, // 5-8: Red + 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, // 9-12: Red + 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, // 13-16: Red + 0xFF6600, 0xFF6600, 0xFF6600, 0xFF6600, // 17-20: Amber + 0xFF6600, 0xFF6600, 0xFF6600, 0xFF6600, // 21-24: Amber + 0xFF6600, 0xFF6600, 0xFF6600, 0xFF6600, // 25-28: Amber + 0xFF6600, 0xFF6600, 0xFF6600, 0xFF6600, // 29-32: Amber + 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, // 33-36: Yellow + 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, // 37-40: Yellow + 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, // 41-44: Yellow + 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, // 45-48: Yellow + 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, // 49-52: Green + 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, // 53-56: Green + 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, // 57-60: Green + 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, // 61-64: Green + 0x00FF66, 0x00FF66, 0x00FF66, 0x00FF66, // 65-68: Mint + 0x00FF66, 0x00FF66, 0x00FF66, 0x00FF66, // 69-72: Mint + 0x00FF66, 0x00FF66, 0x00FF66, 0x00FF66, // 73-76: Mint + 0x00FF66, 0x00FF66, 0x00FF66, 0x00FF66, // 77-80: Mint + 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, // 81-84: Light Blue + 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, // 85-88: Light Blue + 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, // 89-92: Light Blue + 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, // 93-96: Light Blue + 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, // 97-100: Blue + 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, // 101-104: Blue + 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, // 105-108: Blue + 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, // 109-112: Blue + 0x6600FF, 0x6600FF, 0x6600FF, 0x6600FF, // 113-116: Purple + 0x6600FF, 0x6600FF, 0x6600FF, 0x6600FF, // 117-120: Purple + 0x6600FF, 0x6600FF, 0x6600FF, 0x6600FF, // 121-124: Purple + 0x6600FF, 0x6600FF, 0x6600FF, 0x6600FF, // 125-128: Purple +}; + +static uint32_t velocity_to_color(uint8_t velocity) { + if (velocity == 0) return 0x000000; + if (velocity >= 128) return launchpad_palette[127]; + return launchpad_palette[velocity]; +} + DefaultLedStub::DefaultLedStub() : initialized(false) { for (int i = 0; i < NUM_LEDS; i++) { led_states[i].active = false; @@ -19,7 +62,7 @@ void DefaultLedStub::set_mux(PixelStompMux* mux) { } void DefaultLedStub::begin() { - Serial.println("[LED] Using WS2812C via PixelStomp MUX (FastLED I2S)"); + Serial.println("[LED] Using WS2812C via PixelStomp MUX (FastLED)"); initialized = true; if (!mux_ptr) { @@ -27,37 +70,99 @@ void DefaultLedStub::begin() { return; } - Serial.println("[LED] Startup animation..."); + Serial.println("[LED] Launchpad-style startup animation..."); - uint32_t colors[] = { - 0xFF0000, - 0x00FF00, - 0x0000FF, - 0xFFFF00, - 0xFF00FF, - 0x00FFFF, - 0xFFFFFF, - }; - int num_colors = sizeof(colors) / sizeof(colors[0]); + // Launchpad X style: sweep each LED through palette, then all-off + for (int i = 0; i < NUM_LEDS; i++) { + for (int c = 1; c <= 127; c += 8) { + uint32_t color = launchpad_palette[c]; + uint8_t r = (color >> 16) & 0xFF; + uint8_t g = (color >> 8) & 0xFF; + uint8_t b = color & 0xFF; + mux_ptr->set_led_color(i, r, g, b); + mux_ptr->show(); + delay(15); + } + // Turn off this LED before moving to next + mux_ptr->set_led_color(i, 0, 0, 0); + mux_ptr->show(); + } - for (int c = 0; c < num_colors; c++) { - uint32_t color = colors[c]; + // Final: all LEDs pulse through palette once together + for (int c = 1; c <= 127; c += 4) { + uint32_t color = launchpad_palette[c]; uint8_t r = (color >> 16) & 0xFF; uint8_t g = (color >> 8) & 0xFF; uint8_t b = color & 0xFF; - for (int i = 0; i < NUM_LEDS; i++) { mux_ptr->set_led_color(i, r, g, b); } mux_ptr->show(); - Serial.printf("[LED] Colour %d: R=%d G=%d B=%d\n", c, r, g, b); - delay(300); + delay(12); } clear_all(); Serial.println("[LED] Startup complete"); } +void DefaultLedStub::set_led_state(uint8_t note, uint8_t channel, uint8_t velocity) { + if (!initialized || !mux_ptr) return; + + for (int i = 0; i < NUM_LEDS; i++) { + if (led_states[i].active && led_states[i].note == note && led_states[i].channel == channel) { + led_states[i].velocity = velocity; + led_states[i].timestamp = millis(); + uint32_t color = velocity_to_color(velocity); + uint8_t r = (color >> 16) & 0xFF; + uint8_t g = (color >> 8) & 0xFF; + uint8_t b = color & 0xFF; + mux_ptr->set_led_color(i, r, g, b); + mux_ptr->show(); + Serial.printf("[LED] Updated LED %d: note=%d ch=%d vel=%d\n", i, note, channel, velocity); + return; + } + } + + // Find free slot + for (int i = 0; i < NUM_LEDS; i++) { + if (!led_states[i].active) { + led_states[i].active = true; + led_states[i].note = note; + led_states[i].channel = channel; + led_states[i].velocity = velocity; + led_states[i].timestamp = millis(); + uint32_t color = velocity_to_color(velocity); + uint8_t r = (color >> 16) & 0xFF; + uint8_t g = (color >> 8) & 0xFF; + uint8_t b = color & 0xFF; + mux_ptr->set_led_color(i, r, g, b); + mux_ptr->show(); + Serial.printf("[LED] Activated LED %d: note=%d ch=%d vel=%d\n", i, note, channel, velocity); + return; + } + } +} + +void DefaultLedStub::clear_all() { + if (!initialized || !mux_ptr) return; + + for (int i = 0; i < NUM_LEDS; i++) { + led_states[i].active = false; + led_states[i].velocity = 0; + led_states[i].note = 0; + led_states[i].channel = 0; + led_states[i].timestamp = 0; + mux_ptr->set_led_color(i, 0, 0, 0); + } + mux_ptr->show(); +} + +void DefaultLedStub::set_led_brightness(uint8_t brightness) { + if (!initialized || !mux_ptr) return; + mux_ptr->set_led_brightness(brightness); + mux_ptr->show(); +} + void DefaultLedStub::set_led_state(uint8_t note, uint8_t channel, uint8_t velocity) { if (!initialized || !mux_ptr) return;