From fee8ab5b94ab79e66e9a7f9aeb2082597d8e15cf Mon Sep 17 00:00:00 2001 From: Ashley Strahle Date: Wed, 24 Jun 2026 06:43:16 +0000 Subject: [PATCH] Focus on Launchpad X mode: NOTE 36-45 ch1-3, send NOTE_ON/OFF for buttons --- src/app_task.cpp | 98 ++++++++++++++++++++---------------------------- 1 file changed, 41 insertions(+), 57 deletions(-) diff --git a/src/app_task.cpp b/src/app_task.cpp index 76ab7e6..c7c7096 100644 --- a/src/app_task.cpp +++ b/src/app_task.cpp @@ -23,7 +23,7 @@ void AppTask::begin() { process_midi_event(event); }); - Serial.println("[APP] Controller ready"); + Serial.println("[APP] Controller ready - Launchpad X mode (notes 36-45, ch1)"); } void AppTask::update() { @@ -40,35 +40,6 @@ void AppTask::update() { last_switch_state[i] = false; } } - - // Test mode: hold pad 0 + pad 9 for 2s to cycle palette - static uint32_t test_hold_start = 0; - static bool test_mode_active = false; - bool p0 = switch_driver->is_pressed(0); - bool p9 = switch_driver->is_pressed(9); - - if (p0 && p9) { - if (test_hold_start == 0) test_hold_start = millis(); - else if (!test_mode_active && millis() - test_hold_start > 2000) { - test_mode_active = true; - run_palette_test(); - } - } else { - test_hold_start = 0; - test_mode_active = false; - } -} - -void AppTask::run_palette_test() { - Serial.println("[APP] PALETTE TEST: cycling through all 127 colors on pad 0"); - Serial.println("[APP] Hold pad 0 + pad 9 for 2s to re-run"); - - for (uint8_t v = 1; v <= 127; v++) { - led_driver->set_led_state(36, 1, v); - vTaskDelay(pdMS_TO_TICKS(80)); - } - led_driver->set_led_state(36, 1, 0); - Serial.println("[APP] Palette test complete"); } void AppTask::process_midi_event(const MidiEvent& event) { @@ -80,32 +51,41 @@ void AppTask::process_midi_event(const MidiEvent& event) { uint8_t midi_note = event.data1; uint8_t midi_velocity = event.data2; - // NOTE_ON/NOTE_OFF on channels 1-3 (Launchpad standard) + // Launchpad X: NOTE_ON/NOTE_OFF on channels 1-3 + // ch1 = static, ch2 = flashing, ch3 = pulsing + // Notes 36-45 (C2-A2) map to pads 0-9 + // Velocity 1-127 = color palette index if (event.type == MidiEvent::NOTE_ON || event.type == MidiEvent::NOTE_OFF) { - for (uint8_t i = 0; i < NUM_PADS; i++) { - if (pad_mapping[i].midi_channel == midi_channel && - pad_mapping[i].midi_note == midi_note) { - led_index = pad_mapping[i].led_index; - break; + // Only handle channels 1-3 (Launchpad channels) + if (midi_channel >= 1 && midi_channel <= 3) { + for (uint8_t i = 0; i < NUM_PADS; i++) { + if (pad_mapping[i].midi_channel == midi_channel && + pad_mapping[i].midi_note == midi_note) { + led_index = pad_mapping[i].led_index; + break; + } + } + + if (led_index < NUM_PADS) { + uint8_t color_vel = (event.type == MidiEvent::NOTE_ON) ? midi_velocity : 0; + + led_driver->set_led_state( + pad_mapping[led_index].midi_note, + pad_mapping[led_index].midi_channel, + color_vel + ); + + Serial.printf("[APP] NOTE -> LED: Ch%d Note%d Vel%d -> LED%d\n", + midi_channel, midi_note, color_vel, led_index); + } else { + Serial.printf("[APP] NOTE Ch%d Note%d Vel%d - no mapping\n", + midi_channel, midi_note, midi_velocity); } - } - - if (led_index < NUM_PADS) { - uint8_t color_vel = (event.type == MidiEvent::NOTE_ON) ? midi_velocity : 0; - // For flashing/pulsing channels, just use velocity as color - led_driver->set_led_state( - pad_mapping[led_index].midi_note, - pad_mapping[led_index].midi_channel, - color_vel - ); - Serial.printf("[APP] NOTE -> LED: Ch%d Note%d Vel%d -> LED%d\n", - midi_channel, midi_note, color_vel, led_index); } else { - Serial.printf("[APP] NOTE Ch%d Note%d Vel%d - no mapping\n", - midi_channel, midi_note, midi_velocity); + Serial.printf("[APP] NOTE Ch%d ignored (not Launchpad channel 1-3)\n", midi_channel); } } - // CONTROL_CHANGE on any channel (generic MIDI / Loopy Pro) + // CONTROL_CHANGE fallback for generic MIDI / Loopy Pro generic mode else if (event.type == MidiEvent::CONTROL_CHANGE) { uint8_t cc_num = event.data1; uint8_t cc_val = event.data2; @@ -120,7 +100,6 @@ void AppTask::process_midi_event(const MidiEvent& event) { } if (led_index < NUM_PADS) { - // Use CC value directly as color velocity led_driver->set_led_state( pad_mapping[led_index].midi_note, pad_mapping[led_index].midi_channel, @@ -139,13 +118,18 @@ void AppTask::process_switch_event(uint8_t switch_id, bool pressed) { for (uint8_t i = 0; i < NUM_PADS; i++) { if (pad_mapping[i].physical_switch == switch_id) { uint8_t channel = pad_mapping[i].midi_channel; - uint8_t cc_num = 2 + switch_id; - uint8_t cc_val = pressed ? 127 : 0; + // Loopy Pro Launchpad mode expects NOTE_ON/NOTE_OFF on notes 36-45 + uint8_t note = pad_mapping[i].midi_note; + uint8_t velocity = pressed ? 127 : 0; - midi_transport->send_cc(channel, cc_num, cc_val); + if (pressed) { + midi_transport->send_note_on(channel, note, velocity); + } else { + midi_transport->send_note_off(channel, note, velocity); + } - Serial.printf("[APP] Switch %d -> Ch%d CC%d Val%d (%s)\n", - switch_id, channel, cc_num, cc_val, + Serial.printf("[APP] Switch %d -> Ch%d Note%d Vel%d (%s)\n", + switch_id, channel, note, velocity, pressed ? "PRESS" : "RELEASE"); break; }