diff --git a/README.md b/README.md new file mode 100644 index 0000000..4dbd19d --- /dev/null +++ b/README.md @@ -0,0 +1,467 @@ +# Loopy MIDI Controller - USB MIDI Foot Controller + +A compact ESP32-S3 based USB MIDI foot controller with hardware acceleration, designed to work seamlessly with Loopy Pro. + +## Overview + +This project implements a USB MIDI device that accepts foot pedal inputs and converts them to MIDI Continuous Controller (CC) messages. It's designed to be a reliable replacement for the MIDI-to-USB adapters used with Loopy Pro, offering low latency (1-5ms) and USB compatibility without Bluetooth interference. + +**Key Features:** +- **USB MIDI Interface**: Uses ESP32-S3's native USB MIDI support for stable, reliable connectivity +- **Expression Pedal Support**: Read analog input with configurable calibration +- **Launchpad X Compatible**: Per-pad LED colors matching Novation Launchpad hardware +- **Low Latency Design**: 1-5ms response time for responsive control +- **MIDI Clock Sync**: Pixel 6 pulses in time with Loopy Pro tempo +- **Hardware Acceleration**: Uses multiple cores efficiently without cross-core LED issues + +## Hardware Requirements + +### PCB/Layout Notes +- **ESP32-S3-WROOM-1** microcontroller +- **Daisy-chained 74HC165** shift registers for button inputs (16 buttons total) +- **2x RMT WS2812C** LED drivers for 10 programmable RGB pixels +- **ADC on GPIO4** for expression pedal input +- **WS2812 external LED** for boot animation (GPIO12) + +### Required Components +- ESP32-S3 development board (ESP32-S3-WROOM-1 preferred) +- 74HC165 shift register (2x for 16 buttons) +- WS2812C LED strip (10 pixels) +- PWM/ DAC capable for expression pedal +- Level shifters if needed for input voltages + +## Software Architecture + +### Core Design +``` +┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐ +│ USB MIDI │ │ MIDI Task │ │ LED Driver │ +│ (Core 1) │ │ (Core 0) │ │ (Core 0) │ +│ - Loopy Pro │◄──►│ - Clock Parity │◄──►│ - Pixel Pulse │ +│ recognition │ │ Detection │ │ on beats │ +│ - Note/CC │ │ - MIDI update │◄──►│ - Button LED │ +│ processing │ │ processing │ │ feedback │ +└─────────────────┘ └──────────────────┘ └─────────────────┘ + │ + ▼ + ┌─────────────────┐ + │ Expression │ + │ Pedal (Core 0)│ + │ - ADC Read │ + │ - CC 4 output │ + └─────────────────┘ +``` + +### Key Subsystems + +#### 1. USB MIDI Transport (Core 1) +- Adafruit TinyUSB library integration +- Proper VID/PID spoofing (Novation Launchpad X: 0x1235/0x0103) +- MIDI event parsing and routing to Core 0 +- Re-enumeration support for stable device connection + +#### 2. MIDI Task (Core 0) +- Core 0 exclusive for all FastLED operations (prevents crashes) +- MIDI clock (0xF8) detection and counting +- Beat detection using tick count / 24 (24 PPQN) +- Pixel 6 pulsing on every MIDI beat +- Button-to-CC message conversion + +#### 3. LED Driver (Core 0) +- Per-pad color configuration (Launchpad X compatibility) +- Velocity-based color mapping +- Dim off-state for power efficiency +- Launchpad-style startup animation + +#### 4. Expression Pedal (Core 0) +- ADC input on GPIO4 (calibrated min/max) +- CC 4 output on MIDI channel 1 +- Hysteresis filtering for stable readings +- 5ms update interval for responsive control + +#### 5. Switch Driver (Core 0) +- 16 buttons via daisy-chained 74HC165 +- 5ms debounce for reliable input +- Direct button-to-CC mapping +- Per-pad LED feedback + +## Configuration Options + +### MIDI Mapping + +The controller uses a Launchpad X-style mapping for intuitive control: + +| Pad | Hardware Button | MIDI Channel | Note/Pitch | CC | Default Color | +|-----|-----------------|--------------|------------|----|---------------| +| 0-1 | 0-1 | 1 | 36-45 | - | Blue (0x0000FF) | +| 2-4 | 2-4 | 1 | 36-45 | - | Orange (0xFF6600) | +| 5 | 5 | 1 | 36 | - | Red (0xFF0000) | +| 6 | 6 | 1 | 36 | - | White (0xFFFFFF) | +| 7 | 7 | 1 | 36 | - | Amber (0xFFBF00) | +| 8-9 | 8-9 | 1 | 36-37 | - | Purple (0x9900FF) | + +**For Loopy Pro Users:** +- Buttons generate CC messages (not Note On/Off) +- CC values: 2-11 for buttons 0-9 +- CC 4 for expression pedal +- Pixel colors provide visual feedback + +### MIDI Clock Synchronization + +Pixel 6 provides visual feedback synchronized to Loopy Pro's tempo: + +1. **Configure Loopy Pro**: Enable MIDI Clock output targeting JOC Midi +2. **Device Recognition**: Loopy Pro detects the VID/PID (0x1235/0x0103) +3. **Visual Feedback**: Pixel 6 pulses white on each MIDI Clock beat (0xF8) +4. **Pulse Animation**: Quadratic fade (80ms duration) between beats + +**Troubleshooting**: If pixel 6 doesn't pulse: +- Verify Loopy Pro has MIDI Clock enabled +- Ensure JOC Midi is the clock target +- Check MIDI device permissions +- Verify MIDI input in Loopy Pro shows "JOC Midi" + +### PlatformIO Configuration + +#### Build Options (`platformio.ini`) + +```ini +[env] +platform = espressif32 +board = esp32-s3-devkitc-1 +framework = arduino +build_type = release +monitor_speed = 115200 +upload_speed = 921600 + +build_flags = + -DCORE_DEBUG_LEVEL=0 + -DARDUINO_USB_MODE=0 + -DARDUINO_USB_LAUNCHER_MODE=0 + +lib_deps = + adafruit/Adafruit_TinyUSB@3.1.0 + https://github.com/FastLED/FastLED/archive/refs/tags/3.6.0.zip + +extra_scripts = + pre_build.py + extra_script.py +``` + +#### Build Flags Explanation + +- `-DARDUINO_USB_MODE=0`: USB in CDC/MIDI mode (no virtual serial) +- `-DARDUINO_USB_LAUNCHER_MODE=0`: No USB launcher mode +- `-DCORE_DEBUG_LEVEL=0`: Disable debug output +- `--allow-multiple-definition`: Required for Adafruit TinyUSB compatibility + +#### Build Scripts + +**`pre_build.py`**: Patches board definitions with Launchpad X VID/PID +**`extra_script.py`**: Ensures proper TinyUSB linking order + +## Usage + +### Initial Setup + +1. **Flash Firmware** +```bash +platformio run --target upload +``` + +2. **Open Serial Monitor** (115200 baud) + - Shows startup sequence + - MIDI activity diagnostics + - System status + +3. **Available Commands** (type in serial) + - `help` - Show all commands + - `dump` - Display button states + - `probe` - Hardware diagnostics + - `ledon`/`ledoff` - Turn all LEDs on/off + - `ledtest` - Color cycle test + - `exp` - Show expression pedal ADC/value + - `usb` - USB status + - `gpiotest` - Raw GPIO diagnostics + - `miditest` - Simulate MIDI input + - `padtest` - Test individual pads + - `mapping` - Show current pad mapping + +### MIDI Configuration in Loopy Pro + +1. **System Settings** + - Name: "JOC Midi" + - Manufacturer: "JOC" + - Model: "JOC Midi" + +2. **MIDI Setup** + - Port 1: Enabled + - Input Channel: All + - Output Channel: 1 (or preferred) + +3. **Sync Configuration** + - Sync Master: LOOPY (if Loopy Pro is master) + - Clock Output: Enabled + - Clock Targets: JOC Midi + +### Operation + +1. **Button Presses** + - Press any button to send corresponding CC message + - Pixel color changes to match button state + +2. **Expression Pedal** + - Connect foot pedal to ADC input + - Calibrate min (heel) and max (toe) positions + - Watch pixel 5 for pedal value feedback + +3. **Visual Feedback** + - Buttons: Color indicates CC state + - Expression pedal: Pixel 5 brightness reflects CC value + - Sync: Pixel 6 pulses with MIDI Clock + +## Customization + +### Adding New MIDI Functions + +1. **Add New CC Mappings** +```cpp +// In switch_stub.h or app_task.cpp +static const uint8_t BUTTONS_TO_CC[] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; +``` + +2. **Custom LED Patterns** +```cpp +// In led_stub.cpp +void apply_custom_color(uint8_t index, uint8_t velocity) { + if (index == 6) { // Example: Custom color for expression pedal + mux_ptr->set_led_color(index, 0, 255, 0); // Green + return; + } + apply_pad_color(index, velocity); +} +``` + +### Changing MIDI Clock Behavior + +1. **Modify Beat Detection** +```cpp +// In main.cpp, midi_task +uint32_t beat_interval = 24; // PPQN for MIDI Clock + +if (tick / beat_interval != last_beat) { + last_beat = tick / beat_interval; + // Trigger pulse +} +``` + +2. **Change Pulse Animation** +```cpp +// In main.cpp, midi_task +float pulse_speed = 1.0f / 1.0; // Adjust pulse speed +mux.set_led_color(6, v * pulse_speed, v * pulse_speed, v * pulse_speed); +``` + +### Modifying Expression Pedal + +1. **Change ADC Pin** +```cpp +// In expression_pedal.h/expression_pedal.cpp +static const uint8_t EXP_PEDAL_PIN = 4; // or another GPIO +``` + +2. **Adjust Calibration** +```cpp +// In main.cpp +default exp_pedal.cal_min(0); // Set based on testing +default exp_pedal.cal_max(1023); // Set based on testing +``` + +3. **Change MIDI CC** +```cpp +// In expression_pedal.cpp +send_cc(1, 4, value); // Keep existing +// Or change: +send_cc(1, 7, value); // Volume instead of expression +``` + +### Custom Pad Layout + +1. **Map Pads Differently** +```cpp +// In app_task.h/app_task.cpp +#define PAD_NOTE_MAPPING {36, 37, 38, 39, 40, 41, 42, 43, 44, 45} +#define PAD_CC_MAPPING {2, 3, 4, 5, 6, 7, 8, 9, 10, 11} +``` + +2. **Add Special Functions** +```cpp +// In app_task.cpp +void process_special_button(uint8_t led_index) { + if (led_index == 5) { // Expression pedal button + // Toggle pedal mode + } + if (led_index == 6) { // MIDI Clock toggle + // Toggle clock visualization + } +} +``` + +## Testing and Diagnostics + +### Serial Commands for Debugging + +| Command | Description | +|---------|-------------| +| `probe` | Test all buttons and LEDs | +| `gpiotest` | Check GPIO pin states | +| `ledtest` | Cycle through all LED colors | +| `miditest` | Simulate MIDI input for testing | +| `dump` | Show current button states | + +### Troubleshooting Common Issues + +#### Issue: Pixel 6 doesn't pulse +**Cause**: MIDI Clock not arriving +**Solution**: +1. Check Loopy Pro sync settings +2. Verify MIDI Clock target is JOC Midi +3. Examine `[CLK] !! NO MIDI CLOCK RECEIVED !!` in serial + +#### Issue: Buttons not sending MIDI +**Cause**: Shift register issues +**Solution**: +1. Run `probe` command +2. Check wiring and pin connections +3. Verify shift register operation + +#### Issue: Expression pedal unresponsive +**Cause**: ADC calibration incorrect +**Solution**: +1. Use `exp` command to see raw ADC values +2. Adjust calibration min/max values +3. Check voltage range and connection + +#### Issue: USB connection drops +**Cause**: Re-enumeration issues +**Solution**: +1. Check mounted() status in `[MIDI] USB mounted:` messages +2. Ensure proper VID/PID values in build +3. Verify TinyUSB initialization + +## Build Instructions + +### Prerequisites + +1. **PlatformIO IDE** or +2. **Arduino CLI** with ESP32 core support + +### Quick Build + +```bash +# Using PlatformIO +platformio run + +# Using Arduino CLI +cd your-project +arduino-cli compile --builder chitrak/micropython-builder --fqbn esp32-s3-devkitc-1 . +``` + +### Upload + +```bash +# Using PlatformIO +platformio upload + +# Using Arduino CLI +arduino-cli upload -p /dev/ttyUSB0 --fqbn esp32-s3-devkitc-1 . +``` + +### Troubleshooting Build Issues + +#### Common Build Errors + +1. **Adafruit TinyUSB conflicts** + - Solution: Use the provided `extra_script.py` with `--allow-multiple-definition` + - Ensure build_flags match exactly + +2. **Memory Issues** + - Solution: Reduce debug output, use release build type + - Check stack sizes in platformio.ini + +3. **Pin Conflicts** + - Solution: Adjust GPIO pins in configuration files + - Verify all components use different pins + +#### Hardware Issues + +1. **LED Driver Problems** + - Solution: Test with simple color output commands + - Check wiring and power supply + +2. **Button Issues** + - Solution: Use `probe` command regularly + - Ensure proper pull-up/pull-down configurations + +## Future Enhancements + +### Planned Features + +1. **USB MIDI Sysex Support** + - Launchpad X programmer mode + - Bank select and patch change + +2. **Advanced Expression Pedal** + - Rotary encoding support + - Multiple pedal modes (CC1/CC4) + +3. **Enhanced LED Effects** + - Breathing animations + - SOS patterns for diagnostics + - Battery level indicator + +4. **Additional MIDI Functions** + - Pitch Bend support + - Aftertouch + - Poly Pressure + +### Custom Configuration Examples + +#### For Loopy Pro DJs +```cpp +// Loopy-specific CC mappings +static const uint8_t LOOPY_CC_MAP[10] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; +``` + +#### For External Controllers +```cpp +// CC-based interaction +static const uint8_t EXTERNAL_CC_TARGET = 1; +send_cc(EXTERNAL_CC_TARGET, 7, value); // Volume +``` + +#### For Recording Studios +```cpp +// Note-based for drum triggers +static const uint8_t DRUM_NOTES[10] = {36, 38, 40, 42, 44, 45, 47, 48, 50, 52}; +``` + +## License + +This project is provided as-is with no explicit license. The code is intended for educational and personal use. Modifications and distributions should respect original authors' intentions where specified. + +## Acknowledgments + +- **Novation Launchpad**: Inspiration for layout and color scheme +- **ESP32-S3**: Powerful microcontroller with native USB MIDI +- **Adafruit TinyUSB**: Reliable USB MIDI stack +- **FastLED**: Efficient LED control library +- **Contributors**: All who tested and provided feedback + +## Contact + +For issues or questions: +1. Check the project documentation +2. Review serial output for diagnostic messages +3. Use available testing commands +4. Submit issues with complete build logs if encountering problems