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:
@@ -33,8 +33,6 @@ private:
|
||||
static const uint8_t NUM_LEDS = 10;
|
||||
LedState led_states[NUM_LEDS];
|
||||
bool initialized;
|
||||
uint32_t activity_off_time = 0;
|
||||
uint8_t saved_r = 0, saved_g = 0, saved_b = 0;
|
||||
|
||||
public:
|
||||
DefaultLedStub();
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
|
||||
class MidiClock {
|
||||
public:
|
||||
static void tick();
|
||||
static void start();
|
||||
static void stop();
|
||||
static float get_phase();
|
||||
static float get_pulse();
|
||||
static bool is_running();
|
||||
|
||||
private:
|
||||
static uint32_t last_tick_time;
|
||||
static uint32_t tick_count;
|
||||
static float tick_interval_ms;
|
||||
static bool running;
|
||||
static const uint8_t TICKS_PER_BEAT = 24;
|
||||
};
|
||||
+33
-15
@@ -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();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
#include "midi_clock.h"
|
||||
#include <Arduino.h>
|
||||
#include <math.h>
|
||||
|
||||
uint32_t MidiClock::last_tick_time = 0;
|
||||
uint32_t MidiClock::tick_count = 0;
|
||||
float MidiClock::tick_interval_ms = 0;
|
||||
bool MidiClock::running = false;
|
||||
|
||||
void MidiClock::tick() {
|
||||
uint32_t now = millis();
|
||||
if (last_tick_time != 0) {
|
||||
float interval = now - last_tick_time;
|
||||
if (tick_interval_ms == 0) {
|
||||
tick_interval_ms = interval;
|
||||
} else {
|
||||
tick_interval_ms = tick_interval_ms * 0.9f + interval * 0.1f;
|
||||
}
|
||||
}
|
||||
last_tick_time = now;
|
||||
tick_count++;
|
||||
running = true;
|
||||
}
|
||||
|
||||
void MidiClock::start() {
|
||||
tick_count = 0;
|
||||
last_tick_time = 0;
|
||||
tick_interval_ms = 0;
|
||||
running = true;
|
||||
}
|
||||
|
||||
void MidiClock::stop() {
|
||||
running = false;
|
||||
}
|
||||
|
||||
float MidiClock::get_phase() {
|
||||
if (!running || tick_interval_ms == 0) return 0;
|
||||
uint32_t now = millis();
|
||||
float time_since_tick = now - last_tick_time;
|
||||
float sub_phase = time_since_tick / tick_interval_ms;
|
||||
if (sub_phase > 1.0f) sub_phase = 1.0f;
|
||||
return ((tick_count % TICKS_PER_BEAT) + sub_phase) / (float)TICKS_PER_BEAT;
|
||||
}
|
||||
|
||||
float MidiClock::get_pulse() {
|
||||
return sinf(M_PI * get_phase());
|
||||
}
|
||||
|
||||
bool MidiClock::is_running() {
|
||||
return running;
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "midi_transport.h"
|
||||
#include "midi_clock.h"
|
||||
#include <Arduino.h>
|
||||
#include "Adafruit_TinyUSB.h"
|
||||
|
||||
@@ -51,6 +52,20 @@ void UsbMidiTransport::update() {
|
||||
while (usb_midi.available()) {
|
||||
uint8_t packet[4];
|
||||
if (usb_midi.readPacket(packet)) {
|
||||
uint8_t cin = packet[0] & 0x0F;
|
||||
|
||||
if (cin == 0x0F) {
|
||||
uint8_t rt = packet[1];
|
||||
if (rt == 0xF8) {
|
||||
MidiClock::tick();
|
||||
} else if (rt == 0xFA || rt == 0xFB) {
|
||||
MidiClock::start();
|
||||
} else if (rt == 0xFC) {
|
||||
MidiClock::stop();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
MidiEvent event;
|
||||
parse_midi_packet(packet, 4, event);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user