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:
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user