Add MIDI clock-driven LED pulsing

- New MidiClock module: tracks 24 PPQN clock ticks, computes beat phase
  and smooth sine pulse from incoming MIDI Clock (0xF8)
- midi_transport: detect CIN=0xF real-time packets, route 0xF8 to
  MidiClock::tick(), 0xFA/FB to start(), 0xFC to stop()
- led_stub update(): every 20ms, modulates active LED brightness
  using pulse curve (50%-100%), pixel 6 always throbs when clock
  is running even if no loops active
- Aligned set_led_state() all paths to use pad_base_colors
- Removed dead activity flash code
This commit is contained in:
ash
2026-07-02 07:15:53 +00:00
parent 06479f0ca2
commit 5dc10eea87
5 changed files with 118 additions and 17 deletions
+33 -15
View File
@@ -1,5 +1,6 @@
#include "led_stub.h"
#include "pixel_stomp_mux.h"
#include "midi_clock.h"
#include <Arduino.h>
static PixelStompMux* mux_ptr = nullptr;
@@ -251,11 +252,7 @@ void DefaultLedStub::set_led_state(uint8_t note, uint8_t channel, uint8_t veloci
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);
apply_pad_color(i, velocity);
mux_ptr->show();
Serial.printf("[LED] Updated LED %d: note=%d ch=%d vel=%d\n", i, note, channel, velocity);
return;
@@ -269,11 +266,7 @@ void DefaultLedStub::set_led_state(uint8_t note, uint8_t channel, uint8_t veloci
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);
apply_pad_color(i, velocity);
mux_ptr->show();
Serial.printf("[LED] Activated LED %d: note=%d ch=%d vel=%d\n", i, note, channel, velocity);
return;
@@ -311,11 +304,36 @@ void DefaultLedStub::update() {
if (!initialized || !mux_ptr) return;
uint32_t now = millis();
static uint32_t last_pulse_update = 0;
// Turn off activity flash
if (activity_off_time > 0 && now >= activity_off_time) {
mux_ptr->set_led_color(0, saved_r, saved_g, saved_b);
mux_ptr->show();
activity_off_time = 0;
if (now - last_pulse_update < 20) return;
last_pulse_update = now;
bool clock_running = MidiClock::is_running();
float pulse = 1.0f;
if (clock_running) {
pulse = MidiClock::get_pulse();
}
for (int i = 0; i < NUM_LEDS; i++) {
if (led_states[i].active) {
float brightness = clock_running ? (0.5f + 0.5f * pulse) : 1.0f;
uint32_t base = pad_base_colors[i];
uint8_t r = (uint8_t)(((base >> 16) & 0xFF) * brightness);
uint8_t g = (uint8_t)(((base >> 8) & 0xFF) * brightness);
uint8_t b = (uint8_t)((base & 0xFF) * brightness);
mux_ptr->set_led_color(i, r, g, b);
} else if (clock_running && i == 6) {
float brightness = 0.3f + 0.7f * pulse;
uint32_t base = pad_base_colors[6];
uint8_t r = (uint8_t)(((base >> 16) & 0xFF) * brightness);
uint8_t g = (uint8_t)(((base >> 8) & 0xFF) * brightness);
uint8_t b = (uint8_t)((base & 0xFF) * brightness);
mux_ptr->set_led_color(6, r, g, b);
} else {
apply_pad_color(i, 0);
}
}
mux_ptr->show();
}