Add visual MIDI type indicators

- SysEx: ALL LEDs flash white 200ms
- Note: LED 0 flashes red 100ms
- CC: LED 1 flashes green 100ms
- Helps diagnose what MIDI arrives without serial
This commit is contained in:
2026-06-25 22:39:37 +00:00
parent c02121cd09
commit c20f1dec2c
3 changed files with 59 additions and 4 deletions
+4
View File
@@ -12,6 +12,8 @@ public:
virtual void set_led_brightness(uint8_t brightness) = 0;
virtual void flash_activity() {}
virtual void flash_sysex() {}
virtual void flash_all(uint8_t r, uint8_t g, uint8_t b, uint16_t duration) {}
virtual void flash_one(uint8_t index, uint8_t r, uint8_t g, uint8_t b, uint16_t duration) {}
virtual void update() {}
virtual uint8_t note_to_index(uint8_t note) {
@@ -49,6 +51,8 @@ public:
void set_led_brightness(uint8_t brightness) override;
void flash_activity() override;
void flash_sysex() override;
void flash_all(uint8_t r, uint8_t g, uint8_t b, uint16_t duration) override;
void flash_one(uint8_t index, uint8_t r, uint8_t g, uint8_t b, uint16_t duration) override;
void update() override;
void set_mux(PixelStompMux* mux);
+8 -4
View File
@@ -46,16 +46,20 @@ void AppTask::process_midi_event(const MidiEvent& event) {
Serial.printf("[APP] MIDI IN: Type=%d Ch=%d Data1=%d Data2=%d\n",
event.type, event.channel, event.data1, event.data2);
// Flash LED 0 white briefly on ANY MIDI input - visual activity indicator
// (visible without serial when connected to iPad)
led_driver->flash_activity();
// Visual MIDI type indicator (works without serial on iPad)
if (event.type == MidiEvent::SYSEX) {
led_driver->flash_all(255, 255, 255, 200); // SysEx = ALL white
} else if (event.type == MidiEvent::NOTE_ON || event.type == MidiEvent::NOTE_OFF) {
led_driver->flash_one(0, 255, 0, 0, 100); // Note = LED 0 red
} else if (event.type == MidiEvent::CONTROL_CHANGE) {
led_driver->flash_one(1, 0, 255, 0, 100); // CC = LED 1 green
}
if (event.type == MidiEvent::SYSEX) {
// Cin is encoded in channel for SYSEX packets
uint8_t cin = event.channel;
uint8_t packet[3] = {event.data1, event.data2, 0};
process_sysex_packet(packet, cin);
led_driver->flash_sysex();
return;
}
+47
View File
@@ -345,3 +345,50 @@ void DefaultLedStub::update() {
if (heartbeat_phase > 200) heartbeat_phase = 0;
}
}
void DefaultLedStub::flash_all(uint8_t r, uint8_t g, uint8_t b, uint16_t duration) {
if (!initialized || !mux_ptr) return;
// Save all LED states
for (int i = 0; i < NUM_LEDS; i++) {
if (led_states[i].active) {
uint32_t color = launchpad_palette[led_states[i].velocity];
sysex_saved_r[i] = (color >> 16) & 0xFF;
sysex_saved_g[i] = (color >> 8) & 0xFF;
sysex_saved_b[i] = color & 0xFF;
} else {
sysex_saved_r[i] = 0;
sysex_saved_g[i] = 0;
sysex_saved_b[i] = 0;
}
}
for (int i = 0; i < NUM_LEDS; i++) {
mux_ptr->set_led_color(i, r, g, b);
}
mux_ptr->show();
activity_off_time = millis() + duration;
sysex_flash_active = true;
}
void DefaultLedStub::flash_one(uint8_t index, uint8_t r, uint8_t g, uint8_t b, uint16_t duration) {
if (!initialized || !mux_ptr) return;
if (index >= NUM_LEDS) return;
// Save only this LED's state
if (led_states[index].active) {
uint32_t color = launchpad_palette[led_states[index].velocity];
saved_r = (color >> 16) & 0xFF;
saved_g = (color >> 8) & 0xFF;
saved_b = color & 0xFF;
} else {
saved_r = 0;
saved_g = 0;
saved_b = 0;
}
mux_ptr->set_led_color(index, r, g, b);
mux_ptr->show();
activity_off_time = millis() + duration;
sysex_flash_active = false;
}