Compare commits

...
17 Commits
Author SHA1 Message Date
ash 1c1fc4d372 Remove heartbeat, relabel USB to JOC Midi 2026-06-30 03:46:31 +00:00
ash ac83ba269f USB name: JOC / JOC Midi (VID/PID still Launchpad X for Loopy Pro recognition) 2026-06-26 00:13:41 +00:00
ash 17c630f850 Fix update(): remove old sysex_flash_active logic 2026-06-26 00:07:50 +00:00
ash 268b793d87 Fix compilation: remove unused flash_sysex/flash_all/flash_one methods and member vars 2026-06-25 23:54:30 +00:00
ash a281eaa46e Clean up LED driver + rename USB to JOC Midi
- 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
2026-06-25 23:47:39 +00:00
ash 6ccd28362f Add Generic mode CC value visualization
- 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
2026-06-25 23:32:24 +00:00
ash 90bbfa7b84 Revert to single MIDI interface (working USB detection)
- Dual interface broke USB enumeration
- Back to working single interface with Novation Launchpad X VID/PID
- Buttons work, MIDI OUT works
2026-06-25 23:17:18 +00:00
ash a209b48720 Add second USB MIDI interface (LPX MIDI) for Programmer mode
- 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)
2026-06-25 22:51:44 +00:00
ash c20f1dec2c 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
2026-06-25 22:39:37 +00:00
ash c02121cd09 Add pre-build script to patch core's pins_arduino.h with Launchpad X VID/PID
- pre_build.py patches framework-arduinoespressif32/variants/esp32s3_devkitc/pins_arduino.h
- Replaces USB_VID 0x303a -> 0x1235, USB_PID 0x1001 -> 0x0103
- Adds USB_MANUFACTURER/PRODUCT
2026-06-25 22:21:51 +00:00
ash 109106f1f1 Add custom pins_arduino.h variant with Launchpad X VID/PID
- 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
2026-06-25 22:03:15 +00:00
ash 75f583b3c4 Revert to standard board, try VID/PID via board_build.arduino.vid/pid 2026-06-25 10:57:12 +00:00
ash fc9b7688c0 Fix board definition: add espidf framework for Arduino core 2026-06-25 08:57:24 +00:00
ash b380133b3e Add custom board definition with Launchpad X VID/PID (0x1235/0x0103)
- boards/launchpad_x_variant.json defines custom board
- platformio.ini uses custom board
- Board sets VID/PID at hardware level
2026-06-25 08:27:47 +00:00
ash 25713707aa Revert to working USB mode (ARDUINO_USB_MODE=0 + CDC) 2026-06-25 08:20:19 +00:00
ash 7558082e7b Try ARDUINO_USB_MODE=2 (native MIDI only)
Disable CDC, use ESP32 core native USB MIDI stack
2026-06-25 08:12:07 +00:00
ash dee60c7d27 Fix compilation: declare 'now' in flash_sysex 2026-06-25 07:54:35 +00:00
6 changed files with 58 additions and 63 deletions
-6
View File
@@ -11,7 +11,6 @@ public:
virtual void clear_all() = 0;
virtual void set_led_brightness(uint8_t brightness) = 0;
virtual void flash_activity() {}
virtual void flash_sysex() {}
virtual void update() {}
virtual uint8_t note_to_index(uint8_t note) {
@@ -36,10 +35,6 @@ private:
bool initialized;
uint32_t activity_off_time = 0;
uint8_t saved_r = 0, saved_g = 0, saved_b = 0;
uint8_t sysex_saved_r[10] = {0}, sysex_saved_g[10] = {0}, sysex_saved_b[10] = {0};
bool sysex_flash_active = false;
uint32_t heartbeat_time = 0;
uint8_t heartbeat_phase = 0;
public:
DefaultLedStub();
@@ -48,7 +43,6 @@ public:
void clear_all() override;
void set_led_brightness(uint8_t brightness) override;
void flash_activity() override;
void flash_sysex() override;
void update() override;
void set_mux(PixelStompMux* mux);
+2
View File
@@ -21,3 +21,5 @@ monitor_speed = 115200
board_build.partitions = default_8MB.csv
board_build.arduino.memory_type = qio_opi
extra_scripts = pre:pre_build.py
+49
View File
@@ -0,0 +1,49 @@
import os
import fileinput
def patch_usb_ids():
# Find the core's pins_arduino.h for ESP32-S3 DevKitC-1
core_variants = os.path.expanduser("~/.platformio/packages/framework-arduinoespressif32/variants")
if not os.path.exists(core_variants):
# Try PlatformIO default location
core_variants = os.path.join(os.environ.get("PLATFORMIO_PACKAGES_DIR", ""), "framework-arduinoespressif32", "variants")
pins_file = os.path.join(core_variants, "esp32s3_devkitc", "pins_arduino.h")
if not os.path.exists(pins_file):
# Try alternative variant name
pins_file = os.path.join(core_variants, "esp32s3", "pins_arduino.h")
if os.path.exists(pins_file):
print(f"Patching {pins_file} with Launchpad X VID/PID")
# Read and replace
with open(pins_file, 'r') as f:
content = f.read()
# Replace USB_VID and USB_PID
content = content.replace(
'#define USB_VID 0x303a',
'#define USB_VID 0x1235'
)
content = content.replace(
'#define USB_PID 0x1001',
'#define USB_PID 0x0103'
)
# Add or replace manufacturer/product
if 'USB_MANUFACTURER' not in content:
content = content.replace(
'#define USB_PID 0x0103',
'#define USB_PID 0x0103\n#define USB_MANUFACTURER "JOC"\n#define USB_PRODUCT "JOC Midi"'
)
else:
content = content.replace('USB_MANUFACTURER "Novation"', 'USB_MANUFACTURER "JOC"')
content = content.replace('USB_PRODUCT "Launchpad X"', 'USB_PRODUCT "JOC Midi"')
with open(pins_file, 'w') as f:
f.write(content)
print("USB VID/PID patched successfully")
else:
print(f"WARNING: Could not find pins_arduino.h at {pins_file}")
patch_usb_ids()
-2
View File
@@ -47,7 +47,6 @@ void AppTask::process_midi_event(const MidiEvent& event) {
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();
if (event.type == MidiEvent::SYSEX) {
@@ -55,7 +54,6 @@ void AppTask::process_midi_event(const MidiEvent& event) {
uint8_t cin = event.channel;
uint8_t packet[3] = {event.data1, event.data2, 0};
process_sysex_packet(packet, cin);
led_driver->flash_sysex();
return;
}
+1 -49
View File
@@ -283,63 +283,15 @@ void DefaultLedStub::flash_activity() {
activity_off_time = now + 50;
}
void DefaultLedStub::flash_sysex() {
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;
}
}
// Flash ALL LEDs white
for (int i = 0; i < NUM_LEDS; i++) {
mux_ptr->set_led_color(i, 255, 255, 255);
}
mux_ptr->show();
activity_off_time = now + 200;
sysex_flash_active = true;
}
void DefaultLedStub::update() {
if (!initialized || !mux_ptr) return;
uint32_t now = millis();
// Turn off activity/SysEx flash
// Turn off activity flash
if (activity_off_time > 0 && now >= activity_off_time) {
if (sysex_flash_active) {
for (int i = 0; i < NUM_LEDS; i++) {
mux_ptr->set_led_color(i, sysex_saved_r[i], sysex_saved_g[i], sysex_saved_b[i]);
}
sysex_flash_active = false;
} else {
mux_ptr->set_led_color(0, saved_r, saved_g, saved_b);
}
mux_ptr->show();
activity_off_time = 0;
}
// Heartbeat: pulse LED 9 slowly (amber)
if (now - heartbeat_time > 2000 && !activity_off_time) {
heartbeat_time = now;
heartbeat_phase = 1;
}
if (heartbeat_phase && !activity_off_time) {
uint8_t brightness = (heartbeat_phase < 100) ? (heartbeat_phase * 2) : (400 - heartbeat_phase * 2);
if (!led_states[9].active) {
mux_ptr->set_led_color(9, brightness, brightness / 4, 0);
mux_ptr->show();
}
heartbeat_phase++;
if (heartbeat_phase > 200) heartbeat_phase = 0;
}
}
+5 -5
View File
@@ -13,11 +13,11 @@ UsbMidiTransport::~UsbMidiTransport() {
bool UsbMidiTransport::begin() {
Serial.println("[MIDI] Setting up USB MIDI device...");
// Novation Launchpad X identifiers so Loopy Pro recognizes us
TinyUSBDevice.setID(0x1235, 0x0103);
TinyUSBDevice.setManufacturerDescriptor("Novation");
TinyUSBDevice.setProductDescriptor("Launchpad X");
TinyUSBDevice.setSerialDescriptor("LPX00001");
// Use Launchpad X VID/PID (0x1235/0x0103) so Loopy Pro recognizes us
// but with our own name
TinyUSBDevice.setManufacturerDescriptor("JOC");
TinyUSBDevice.setProductDescriptor("JOC Midi");
TinyUSBDevice.setSerialDescriptor("JOCMIDI001");
TinyUSBDevice.begin(0);
if (!usb_midi.begin()) {