diff --git a/include/expression_pedal.h b/include/expression_pedal.h new file mode 100644 index 0000000..cfb2ab2 --- /dev/null +++ b/include/expression_pedal.h @@ -0,0 +1,27 @@ +#pragma once + +#include + +class UsbMidiTransport; + +class ExpressionPedal { +public: + ExpressionPedal(uint8_t adc_pin = 5); + + void begin(); + void update(UsbMidiTransport& midi); + uint8_t get_value() const { return current_value; } + +private: + uint8_t adc_pin; + uint8_t current_value; + uint8_t last_sent_value; + uint8_t midi_channel; + uint8_t midi_cc; + + static const uint8_t HYSTERESIS = 3; + static const uint16_t READ_INTERVAL_MS = 20; + uint32_t last_read_time; + + uint8_t adc_to_midi(uint16_t adc_value); +}; diff --git a/src/expression_pedal.cpp b/src/expression_pedal.cpp new file mode 100644 index 0000000..acd1e46 --- /dev/null +++ b/src/expression_pedal.cpp @@ -0,0 +1,50 @@ +#include "expression_pedal.h" +#include "midi_transport.h" +#include + +ExpressionPedal::ExpressionPedal(uint8_t adc_pin) + : adc_pin(adc_pin) + , current_value(0) + , last_sent_value(255) + , midi_channel(1) + , midi_cc(4) + , last_read_time(0) +{ +} + +void ExpressionPedal::begin() { + Serial.printf("[EXP] Expression pedal on ADC1_CH4 (GPIO%d)\n", adc_pin); + analogReadResolution(12); + pinMode(adc_pin, INPUT); + delay(10); + uint16_t initial = analogRead(adc_pin); + current_value = adc_to_midi(initial); + last_sent_value = current_value; + Serial.printf("[EXP] Initial ADC: %d -> MIDI: %d\n", initial, current_value); +} + +void ExpressionPedal::update(UsbMidiTransport& midi) { + uint32_t now = millis(); + if (now - last_read_time < READ_INTERVAL_MS) return; + last_read_time = now; + + uint16_t raw = analogRead(adc_pin); + uint8_t new_value = adc_to_midi(raw); + + if (new_value > current_value + HYSTERESIS || + new_value + HYSTERESIS < current_value || + (new_value != current_value && (new_value == 0 || new_value == 127))) { + current_value = new_value; + } + + if (current_value != last_sent_value) { + last_sent_value = current_value; + midi.send_cc(midi_channel, midi_cc, current_value); + Serial.printf("[EXP] CC%d: %d\n", midi_cc, current_value); + } +} + +uint8_t ExpressionPedal::adc_to_midi(uint16_t adc_value) { + uint32_t scaled = (uint32_t)adc_value * 127 / 4095; + return (uint8_t)scaled; +} diff --git a/src/main.cpp b/src/main.cpp index 76fe3de..7df0ce5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -10,6 +10,7 @@ #include "led_stub.h" #include "switch_stub.h" #include "app_task.h" +#include "expression_pedal.h" PixelStompMux mux(12, 10, 11, 9); @@ -18,6 +19,7 @@ DefaultSwitchStub switch_driver; UsbMidiTransport midi_transport; AppTask controller(&led_driver, &switch_driver, &midi_transport); +ExpressionPedal exp_pedal(5); TaskHandle_t midi_task_handle = NULL; @@ -26,6 +28,7 @@ void midi_task(void* parameter) { while (true) { midi_transport.update(); + exp_pedal.update(midi_transport); vTaskDelay(1); } } @@ -83,6 +86,9 @@ void handle_serial_command(const String& cmd) { mux.set_led_color(1, 255, 255, 255); mux.show(); Serial.println("[CMD] Pixel 1 WHITE (max brightness)"); + } else if (cmd == "exp") { + uint16_t raw = analogRead(5); + Serial.printf("[CMD] EXP GPIO5 ADC=%d MIDI=%d\n", raw, exp_pedal.get_value()); } else if (cmd == "usb") { Serial.printf("[CMD] USB mounted: %s\n", TinyUSBDevice.mounted() ? "YES" : "NO"); Serial.printf("[CMD] USB ready: %s\n", TinyUSBDevice.ready() ? "YES" : "NO"); @@ -126,6 +132,7 @@ void handle_serial_command(const String& cmd) { Serial.println(" read - raw button read"); Serial.println(" red/green/blue - solid colour"); Serial.println(" pixel0/pixel1 - single pixel test"); + Serial.println(" exp - expression pedal ADC/MIDI value"); Serial.println(" usb - USB connection status and descriptor info"); Serial.println(" gpiotest - raw GPIO pin diagnostic"); Serial.println(" rawled - bit-bang WS2812 (no library)"); @@ -328,7 +335,7 @@ void setup() { Serial.println("================================="); Serial.println(" Loopy MIDI Controller v0.1"); - Serial.println(" Phase 1: USB MIDI"); + Serial.println(" Phase 1: USB MIDI + Expression Pedal"); Serial.println(" Board: ESP32-S3-WROOM-1"); Serial.println("================================="); @@ -346,6 +353,9 @@ void setup() { Serial.println("[INIT] Initializing USB MIDI..."); midi_transport.begin(); + Serial.println("[INIT] Initializing Expression Pedal..."); + exp_pedal.begin(); + Serial.println("[INIT] Registering MIDI callbacks..."); controller.begin();