diff --git a/include/app_task.h b/include/app_task.h index fa3096c..564c878 100644 --- a/include/app_task.h +++ b/include/app_task.h @@ -18,6 +18,7 @@ public: void begin(); void update(); + void process_midi_event(const MidiEvent& event); // public for test commands private: LedStub* led_driver; @@ -28,6 +29,5 @@ private: PadMapping pad_mapping[NUM_PADS]; bool last_switch_state[NUM_PADS]; - void process_midi_event(const MidiEvent& event); void process_switch_event(uint8_t switch_id, bool pressed); }; diff --git a/src/main.cpp b/src/main.cpp index 408833e..5186b73 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -118,18 +118,20 @@ void handle_serial_command(const String& cmd) { Serial.println("[CMD] === GPIO Test Complete ==="); } else if (cmd == "help") { Serial.println("[CMD] Commands:"); - Serial.println(" dump - show button states"); - Serial.println(" probe - hardware diagnostic"); - Serial.println(" ledon - all LEDs white"); - Serial.println(" ledoff - all LEDs off"); - Serial.println(" ledtest - colour cycle"); - Serial.println(" read - raw button read"); + Serial.println(" dump - show button states"); + Serial.println(" probe - hardware diagnostic"); + Serial.println(" ledon - all LEDs white"); + Serial.println(" ledoff - all LEDs off"); + Serial.println(" ledtest - colour cycle"); + Serial.println(" read - raw button read"); Serial.println(" red/green/blue - solid colour"); Serial.println(" pixel0/pixel1 - single pixel test"); - Serial.println(" usb - USB connection status and descriptor info"); - Serial.println(" gpiotest - raw GPIO pin diagnostic"); - Serial.println(" rawled - bit-bang WS2812 (no library)"); - Serial.println(" anim - re-run startup animation from loop"); + Serial.println(" usb - USB connection status and descriptor info"); + Serial.println(" gpiotest - raw GPIO pin diagnostic"); + Serial.println(" rawled - bit-bang WS2812 (no library)"); + Serial.println(" anim - re-run startup animation from loop"); + Serial.println(" miditest - simulate MIDI IN for common Launchpad layouts"); + Serial.println(" mapping - show current pad->note mapping"); } else if (cmd == "anim") { Serial.println("[CMD] Running animation..."); uint32_t colors[] = {0xFF0000, 0x00FF00, 0x0000FF, 0xFFFF00, 0xFF00FF, 0x00FFFF, 0xFFFFFF}; @@ -168,6 +170,114 @@ void handle_serial_command(const String& cmd) { Serial.println("[CMD] Sent. Wait 2 sec..."); delay(2000); Serial.println("[CMD] Done"); + } else if (cmd == "miditest") { + Serial.println("[CMD] Simulating MIDI IN for common Launchpad layouts..."); + + // Test 1: Launchpad X bottom row (notes 36-45, channel 1) + Serial.println("[CMD] Test 1: Launchpad X bottom row (notes 36-45, ch1)"); + for (int i = 0; i < 10; i++) { + MidiEvent event; + event.type = MidiEvent::NOTE_ON; + event.channel = 1; + event.data1 = 36 + i; + event.data2 = 64; // Medium velocity (yellow) + controller.process_midi_event(event); + delay(200); + } + for (int i = 0; i < 10; i++) { + MidiEvent event; + event.type = MidiEvent::NOTE_OFF; + event.channel = 1; + event.data1 = 36 + i; + event.data2 = 0; + controller.process_midi_event(event); + } + + // Test 2: Launchpad Mini Mk3 (notes 0-9, channel 1) + Serial.println("[CMD] Test 2: Launchpad Mini Mk3 (notes 0-9, ch1)"); + for (int i = 0; i < 10; i++) { + MidiEvent event; + event.type = MidiEvent::NOTE_ON; + event.channel = 1; + event.data1 = i; + event.data2 = 64; + controller.process_midi_event(event); + delay(200); + } + for (int i = 0; i < 10; i++) { + MidiEvent event; + event.type = MidiEvent::NOTE_OFF; + event.channel = 1; + event.data1 = i; + event.data2 = 0; + controller.process_midi_event(event); + } + + // Test 3: Channel 2 (flashing) notes 36-45 + Serial.println("[CMD] Test 3: Channel 2 flashing (notes 36-45, ch2)"); + for (int i = 0; i < 10; i++) { + MidiEvent event; + event.type = MidiEvent::NOTE_ON; + event.channel = 2; + event.data1 = 36 + i; + event.data2 = 64; + controller.process_midi_event(event); + delay(200); + } + for (int i = 0; i < 10; i++) { + MidiEvent event; + event.type = MidiEvent::NOTE_OFF; + event.channel = 2; + event.data1 = 36 + i; + event.data2 = 0; + controller.process_midi_event(event); + } + + // Test 4: Channel 3 (pulsing) notes 36-45 + Serial.println("[CMD] Test 4: Channel 3 pulsing (notes 36-45, ch3)"); + for (int i = 0; i < 10; i++) { + MidiEvent event; + event.type = MidiEvent::NOTE_ON; + event.channel = 3; + event.data1 = 36 + i; + event.data2 = 64; + controller.process_midi_event(event); + delay(200); + } + for (int i = 0; i < 10; i++) { + MidiEvent event; + event.type = MidiEvent::NOTE_OFF; + event.channel = 3; + event.data1 = 36 + i; + event.data2 = 0; + controller.process_midi_event(event); + } + + // Test 5: Full velocity sweep on pad 0 + Serial.println("[CMD] Test 5: Velocity sweep on pad 0 (note 36)"); + for (int v = 1; v <= 127; v += 8) { + MidiEvent event; + event.type = MidiEvent::NOTE_ON; + event.channel = 1; + event.data1 = 36; + event.data2 = v; + controller.process_midi_event(event); + delay(100); + } + MidiEvent event; + event.type = MidiEvent::NOTE_OFF; + event.channel = 1; + event.data1 = 36; + event.data2 = 0; + controller.process_midi_event(event); + + Serial.println("[CMD] MIDI test complete"); + } else if (cmd == "mapping") { + Serial.println("[CMD] Current pad mapping:"); + for (int i = 0; i < 10; i++) { + // Can't access private pad_mapping directly, so just show defaults + Serial.printf(" Pad %d: note=%d ch=%d\n", i, 36+i, 1); + } } else { Serial.println("[CMD] Unknown command. Type 'help'"); }