- Detect 0xF8 in midi_transport.cpp (runs on Core 0)
- Every 24th tick = beat, flash pixel 6 white
- Instant-on, quadratic fade over 80ms, restore to dim
- All FastLED calls stay on Core 0, no cross-core conflict
Pulsing code was causing crashes (FastLED.show() RMT conflict with USB).
Removed:
- update() is now empty no-op (was calling mux_ptr->show() every 33ms)
- Removed set_bpm(), beat_interval_ms, bpm serial command
Kept:
- Per-pad LED colors with dim off state (working fine)
- All button/MIDI/expression pedal functionality
- Pulse shape: instant-on at beat, quick fade to 0 by phase 0.25
(was smooth sine wave - didn't show exact timing)
- Active LEDs no longer overridden by update() - they keep their
set_led_state() color, restoring button press responsiveness
- Pixel 6 only pulses when not active (acts as visual metronome)
When active as a loop trigger, stays at full brightness
- 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
- Pad 0-1: Blue, 2-4: Orange, 5: Red, 6: White, 7: Amber, 8-9: White
- Off state (velocity=0): dim at ~8% brightness instead of black
- On state: full brightness of assigned color
- clear_all() sets dim colors instead of off
Latency sources fixed:
- debounce 50ms -> 5ms (switch_stub.cpp:15)
- Removed [MIDI OUT] Serial.printf from send_cc() (midi_transport.cpp:93-98)
- Removed [APP] Switch pressed/released prints from update() (app_task.cpp:39,43)
- Removed [APP] Switch -> CC print from process_switch_event() (app_task.cpp:140-143)
- loop() delay 10ms -> 1ms (main.cpp:390)
Serial output at 115200 baud was taking 2-5ms per printf call
in the critical button-to-MIDI path, adding 7-15ms+ total latency
per button press. All removed from hot path.
- Print raw ADC + mapped MIDI value on every change
- Remove cal min/cal max serial commands (broken with multi-word)
- Keep cal_min=0, cal_max=4095 defaults
- User moves pedal full range and reports min/max raw values
- Remove fixed 0-4095 mapping, use cal_min/cal_max instead
- Auto-calibrate minimum at boot (assumes pedal at heel)
- 'cal min' sets current position as heel (0)
- 'cal max' sets current position as toe (127)
- Map cal_min->0, cal_max->127 with clamping
- Update 'exp' command to show raw ADC + cal values
- Removed flash_sysex/flash_all/flash_one (conflicted with heartbeat)
- Simplified flash_activity: LED 0 white 50ms, restores properly
- Heartbeat only on LED 9 when no activity
- USB renamed: Manufacturer=JOC, Product=JOC Midi
- LED 1 green = CC received
- LED 2 color shows CC value range:
- Red (0-31) = recording?
- Amber (32-63) = queued?
- Green (64-95) = playing?
- Blue (96-127) = other?
- Helps map Loopy Pro Generic mode values to Launchpad palette
- Interface 1 (DAW): Button presses -> Loopy Pro
- Interface 2 (MIDI): SysEx + LED control <- Loopy Pro
- Both interfaces polled in update()
- Sends on DAW interface (like real Launchpad X)
- variants/esp32s3/pins_arduino.h overrides USB_VID/USB_PID
- Included via -I in build_flags before core variant
- This should force USB descriptors at hardware level
- flash_activity: only LED 0, restores properly
- flash_sysex: saves ALL LED states, restores all properly
- heartbeat: only LED 9, only when no activity flash active
- Added sysex_saved arrays to track all LED states
- Set USB VID/PID via ESP32 core build flags (may work better than TinyUSB API)
- Heartbeat on LED 9 (amber pulse every 2s) confirms device is alive
- SysEx flashes ALL LEDs white for 200ms
- Regular MIDI flashes LED 0 white for 50ms
Change USB device descriptor to VID 0x1235 PID 0x0103
so Loopy Pro recognizes the device as a Launchpad X
and sends LED control MIDI in Launchpad mode.