Replace MIDI clock with internal BPM timer for pixel 6 pulse
Revert: - Remove midi_clock.h/cpp (was causing cross-core crash) - Remove real-time MIDI message parsing from midi_transport.cpp New approach: - Pixel 6 (and all active LEDs) pulse to internal BPM timer - Default 120 BPM (500ms beat interval) - 'bpm <n>' serial command to change tempo (20-300) - Only calls FastLED.show() when actively pulsing (avoids USB/WS2812 interference) - 33ms update rate (30fps) - Inactive LEDs left untouched (no unnecessary show() calls)
This commit is contained in:
@@ -33,6 +33,7 @@ private:
|
|||||||
static const uint8_t NUM_LEDS = 10;
|
static const uint8_t NUM_LEDS = 10;
|
||||||
LedState led_states[NUM_LEDS];
|
LedState led_states[NUM_LEDS];
|
||||||
bool initialized;
|
bool initialized;
|
||||||
|
uint32_t beat_interval_ms = 500;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DefaultLedStub();
|
DefaultLedStub();
|
||||||
@@ -44,4 +45,5 @@ public:
|
|||||||
void update() override;
|
void update() override;
|
||||||
|
|
||||||
void set_mux(PixelStompMux* mux);
|
void set_mux(PixelStompMux* mux);
|
||||||
|
void set_bpm(uint16_t bpm);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
#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;
|
|
||||||
};
|
|
||||||
+17
-11
@@ -1,7 +1,7 @@
|
|||||||
#include "led_stub.h"
|
#include "led_stub.h"
|
||||||
#include "pixel_stomp_mux.h"
|
#include "pixel_stomp_mux.h"
|
||||||
#include "midi_clock.h"
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
static PixelStompMux* mux_ptr = nullptr;
|
static PixelStompMux* mux_ptr = nullptr;
|
||||||
|
|
||||||
@@ -300,40 +300,46 @@ void DefaultLedStub::flash_activity() {
|
|||||||
// LED feedback is handled directly by set_led_state().
|
// LED feedback is handled directly by set_led_state().
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DefaultLedStub::set_bpm(uint16_t bpm) {
|
||||||
|
if (bpm == 0) bpm = 120;
|
||||||
|
beat_interval_ms = 60000 / bpm;
|
||||||
|
Serial.printf("[LED] Pulse BPM set to %d (%dms)\n", bpm, beat_interval_ms);
|
||||||
|
}
|
||||||
|
|
||||||
void DefaultLedStub::update() {
|
void DefaultLedStub::update() {
|
||||||
if (!initialized || !mux_ptr) return;
|
if (!initialized || !mux_ptr) return;
|
||||||
|
|
||||||
uint32_t now = millis();
|
uint32_t now = millis();
|
||||||
static uint32_t last_pulse_update = 0;
|
static uint32_t last_pulse_update = 0;
|
||||||
|
|
||||||
if (now - last_pulse_update < 20) return;
|
if (now - last_pulse_update < 33) return;
|
||||||
last_pulse_update = now;
|
last_pulse_update = now;
|
||||||
|
|
||||||
bool clock_running = MidiClock::is_running();
|
float phase = (now % beat_interval_ms) / (float)beat_interval_ms;
|
||||||
float pulse = 1.0f;
|
float pulse = sinf(M_PI * phase);
|
||||||
if (clock_running) {
|
|
||||||
pulse = MidiClock::get_pulse();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
bool active = false;
|
||||||
for (int i = 0; i < NUM_LEDS; i++) {
|
for (int i = 0; i < NUM_LEDS; i++) {
|
||||||
if (led_states[i].active) {
|
if (led_states[i].active) {
|
||||||
float brightness = clock_running ? (0.5f + 0.5f * pulse) : 1.0f;
|
active = true;
|
||||||
|
float brightness = 0.5f + 0.5f * pulse;
|
||||||
uint32_t base = pad_base_colors[i];
|
uint32_t base = pad_base_colors[i];
|
||||||
uint8_t r = (uint8_t)(((base >> 16) & 0xFF) * brightness);
|
uint8_t r = (uint8_t)(((base >> 16) & 0xFF) * brightness);
|
||||||
uint8_t g = (uint8_t)(((base >> 8) & 0xFF) * brightness);
|
uint8_t g = (uint8_t)(((base >> 8) & 0xFF) * brightness);
|
||||||
uint8_t b = (uint8_t)((base & 0xFF) * brightness);
|
uint8_t b = (uint8_t)((base & 0xFF) * brightness);
|
||||||
mux_ptr->set_led_color(i, r, g, b);
|
mux_ptr->set_led_color(i, r, g, b);
|
||||||
} else if (clock_running && i == 6) {
|
} else if (i == 6) {
|
||||||
|
active = true;
|
||||||
float brightness = 0.3f + 0.7f * pulse;
|
float brightness = 0.3f + 0.7f * pulse;
|
||||||
uint32_t base = pad_base_colors[6];
|
uint32_t base = pad_base_colors[6];
|
||||||
uint8_t r = (uint8_t)(((base >> 16) & 0xFF) * brightness);
|
uint8_t r = (uint8_t)(((base >> 16) & 0xFF) * brightness);
|
||||||
uint8_t g = (uint8_t)(((base >> 8) & 0xFF) * brightness);
|
uint8_t g = (uint8_t)(((base >> 8) & 0xFF) * brightness);
|
||||||
uint8_t b = (uint8_t)((base & 0xFF) * brightness);
|
uint8_t b = (uint8_t)((base & 0xFF) * brightness);
|
||||||
mux_ptr->set_led_color(6, r, g, b);
|
mux_ptr->set_led_color(6, r, g, b);
|
||||||
} else {
|
|
||||||
apply_pad_color(i, 0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (active) {
|
||||||
mux_ptr->show();
|
mux_ptr->show();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,6 +89,13 @@ void handle_serial_command(const String& cmd) {
|
|||||||
} else if (cmd == "exp") {
|
} else if (cmd == "exp") {
|
||||||
Serial.printf("[CMD] EXP ADC=%d MIDI=%d\n",
|
Serial.printf("[CMD] EXP ADC=%d MIDI=%d\n",
|
||||||
exp_pedal.get_raw(), exp_pedal.get_value());
|
exp_pedal.get_raw(), exp_pedal.get_value());
|
||||||
|
} else if (cmd.startsWith("bpm ")) {
|
||||||
|
uint16_t bpm = cmd.substring(4).toInt();
|
||||||
|
if (bpm >= 20 && bpm <= 300) {
|
||||||
|
led_driver.set_bpm(bpm);
|
||||||
|
} else {
|
||||||
|
Serial.println("[CMD] BPM must be 20-300");
|
||||||
|
}
|
||||||
} else if (cmd == "usb") {
|
} else if (cmd == "usb") {
|
||||||
Serial.printf("[CMD] USB mounted: %s\n", TinyUSBDevice.mounted() ? "YES" : "NO");
|
Serial.printf("[CMD] USB mounted: %s\n", TinyUSBDevice.mounted() ? "YES" : "NO");
|
||||||
Serial.printf("[CMD] USB ready: %s\n", TinyUSBDevice.ready() ? "YES" : "NO");
|
Serial.printf("[CMD] USB ready: %s\n", TinyUSBDevice.ready() ? "YES" : "NO");
|
||||||
@@ -133,6 +140,7 @@ void handle_serial_command(const String& cmd) {
|
|||||||
Serial.println(" red/green/blue - solid colour");
|
Serial.println(" red/green/blue - solid colour");
|
||||||
Serial.println(" pixel0/pixel1 - single pixel test");
|
Serial.println(" pixel0/pixel1 - single pixel test");
|
||||||
Serial.println(" exp - expression pedal ADC/MIDI value");
|
Serial.println(" exp - expression pedal ADC/MIDI value");
|
||||||
|
Serial.println(" bpm <n> - set LED pulse tempo (20-300, default 120)");
|
||||||
Serial.println(" usb - USB connection status and descriptor info");
|
Serial.println(" usb - USB connection status and descriptor info");
|
||||||
Serial.println(" gpiotest - raw GPIO pin diagnostic");
|
Serial.println(" gpiotest - raw GPIO pin diagnostic");
|
||||||
Serial.println(" rawled - bit-bang WS2812 (no library)");
|
Serial.println(" rawled - bit-bang WS2812 (no library)");
|
||||||
@@ -356,6 +364,9 @@ void setup() {
|
|||||||
Serial.println("[INIT] Initializing Expression Pedal...");
|
Serial.println("[INIT] Initializing Expression Pedal...");
|
||||||
exp_pedal.begin();
|
exp_pedal.begin();
|
||||||
|
|
||||||
|
Serial.println("[INIT] Setting LED pulse tempo...");
|
||||||
|
led_driver.set_bpm(120);
|
||||||
|
|
||||||
Serial.println("[INIT] Registering MIDI callbacks...");
|
Serial.println("[INIT] Registering MIDI callbacks...");
|
||||||
controller.begin();
|
controller.begin();
|
||||||
|
|
||||||
|
|||||||
@@ -1,51 +0,0 @@
|
|||||||
#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,5 +1,4 @@
|
|||||||
#include "midi_transport.h"
|
#include "midi_transport.h"
|
||||||
#include "midi_clock.h"
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include "Adafruit_TinyUSB.h"
|
#include "Adafruit_TinyUSB.h"
|
||||||
|
|
||||||
@@ -52,20 +51,6 @@ void UsbMidiTransport::update() {
|
|||||||
while (usb_midi.available()) {
|
while (usb_midi.available()) {
|
||||||
uint8_t packet[4];
|
uint8_t packet[4];
|
||||||
if (usb_midi.readPacket(packet)) {
|
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;
|
MidiEvent event;
|
||||||
parse_midi_packet(packet, 4, event);
|
parse_midi_packet(packet, 4, event);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user