diff --git a/platformio.ini b/platformio.ini index f9fac45..b14907e 100644 --- a/platformio.ini +++ b/platformio.ini @@ -6,15 +6,12 @@ platform = espressif32 board = esp32-s3-devkitc-1 framework = arduino -; USB settings for MIDI build_flags = -DARDUINO_USB_MODE=1 -DARDUINO_USB_CDC_ON_BOOT=1 - -DUSE_TINYUSB + -DCFG_TUSB_MIDI=1 -; Serial monitoring monitor_speed = 115200 -; Partition scheme with more space board_build.partitions = default_8MB.csv board_build.arduino.memory_type = qio_opi diff --git a/src/midi_transport.cpp b/src/midi_transport.cpp index 0a516d6..93841b6 100644 --- a/src/midi_transport.cpp +++ b/src/midi_transport.cpp @@ -1,10 +1,6 @@ #include "midi_transport.h" #include -#include -#include - -// TinyUSB MIDI interface -static USBMIDI MIDI; +#include "tusb.h" UsbMidiTransport::UsbMidiTransport() : initialized(false) { } @@ -13,8 +9,7 @@ UsbMidiTransport::~UsbMidiTransport() { } bool UsbMidiTransport::begin() { - USB.begin(); - MIDI.begin(MIDI_CHANNEL_OMNI); + tusb_init(); initialized = true; Serial.println("[MIDI] USB MIDI transport initialized"); return true; @@ -22,53 +17,29 @@ bool UsbMidiTransport::begin() { void UsbMidiTransport::update() { if (!initialized) return; - - // Check for incoming MIDI - if (MIDI.read()) { - MidiEvent event; - midi_message_t msg = MIDI.getMessage(); - - event.channel = msg.channel; - event.data1 = msg.data1; - event.data2 = msg.data2; - event.timestamp = millis(); - - // Map Arduino MIDI types to our types - switch (msg.type) { - case midi::NoteOn: - event.type = (msg.data2 > 0) ? MidiEvent::NOTE_ON : MidiEvent::NOTE_OFF; - break; - case midi::NoteOff: - event.type = MidiEvent::NOTE_OFF; - break; - case midi::ControlChange: - event.type = MidiEvent::CONTROL_CHANGE; - break; - case midi::ProgramChange: - event.type = MidiEvent::PROGRAM_CHANGE; - break; - case midi::PitchBend: - event.type = MidiEvent::PITCH_BEND; - break; - default: - return; // Unknown type, skip - } - - // Diagnostic logging - const char* type_str = "UNK"; - switch (event.type) { - case MidiEvent::NOTE_ON: type_str = "NOTE_ON"; break; - case MidiEvent::NOTE_OFF: type_str = "NOTE_OFF"; break; - case MidiEvent::CONTROL_CHANGE: type_str = "CC"; break; - case MidiEvent::PROGRAM_CHANGE: type_str = "PC"; break; - case MidiEvent::PITCH_BEND: type_str = "PB"; break; - default: break; - } - Serial.printf("[MIDI IN] Ch:%d %s:%d:%d\n", event.channel, type_str, event.data1, event.data2); - - // Call callback - if (receive_callback) { - receive_callback(event); + + tud_task(); + + while (tud_midi_available()) { + uint8_t packet[4]; + if (tud_midi_packet_read(packet)) { + MidiEvent event; + parse_midi_packet(packet, 4, event); + + const char* type_str = "UNK"; + switch (event.type) { + case MidiEvent::NOTE_ON: type_str = "NOTE_ON"; break; + case MidiEvent::NOTE_OFF: type_str = "NOTE_OFF"; break; + case MidiEvent::CONTROL_CHANGE: type_str = "CC"; break; + case MidiEvent::PROGRAM_CHANGE: type_str = "PC"; break; + case MidiEvent::PITCH_BEND: type_str = "PB"; break; + default: break; + } + Serial.printf("[MIDI IN] Ch:%d %s:%d:%d\n", event.channel, type_str, event.data1, event.data2); + + if (receive_callback) { + receive_callback(event); + } } } } @@ -79,19 +50,51 @@ void UsbMidiTransport::on_midi_receive(std::function cal void UsbMidiTransport::send_note_on(uint8_t channel, uint8_t note, uint8_t velocity) { if (!initialized) return; - MIDI.sendNoteOn(note, velocity, channel); + uint8_t packet[4] = {0x09, (uint8_t)(0x90 | (channel - 1)), note, velocity}; + tud_midi_packet_write(packet); } void UsbMidiTransport::send_note_off(uint8_t channel, uint8_t note, uint8_t velocity) { if (!initialized) return; - MIDI.sendNoteOff(note, velocity, channel); + uint8_t packet[4] = {0x08, (uint8_t)(0x80 | (channel - 1)), note, velocity}; + tud_midi_packet_write(packet); } void UsbMidiTransport::send_cc(uint8_t channel, uint8_t cc, uint8_t value) { if (!initialized) return; - MIDI.sendControlChange(cc, value, channel); + uint8_t packet[4] = {0x0B, (uint8_t)(0xB0 | (channel - 1)), cc, value}; + tud_midi_packet_write(packet); } void UsbMidiTransport::parse_midi_packet(const uint8_t* buffer, uint32_t size, MidiEvent& event) { - // Not used with Arduino MIDI library - kept for reference + if (size < 4) return; + + uint8_t cin = buffer[0] & 0x0F; + uint8_t status = buffer[1]; + uint8_t type = status & 0xF0; + uint8_t channel = (status & 0x0F) + 1; + + event.channel = channel; + event.data1 = buffer[2]; + event.data2 = buffer[3]; + + switch (cin) { + case 0x8: event.type = MidiEvent::NOTE_OFF; break; + case 0x9: + event.type = (event.data2 > 0) ? MidiEvent::NOTE_ON : MidiEvent::NOTE_OFF; + break; + case 0xB: event.type = MidiEvent::CONTROL_CHANGE; break; + case 0xC: event.type = MidiEvent::PROGRAM_CHANGE; break; + case 0xE: event.type = MidiEvent::PITCH_BEND; break; + default: + switch (type) { + case 0x80: event.type = MidiEvent::NOTE_OFF; break; + case 0x90: event.type = (event.data2 > 0) ? MidiEvent::NOTE_ON : MidiEvent::NOTE_OFF; break; + case 0xB0: event.type = MidiEvent::CONTROL_CHANGE; break; + case 0xC0: event.type = MidiEvent::PROGRAM_CHANGE; break; + case 0xE0: event.type = MidiEvent::PITCH_BEND; break; + default: event.type = MidiEvent::NOTE_ON; break; + } + break; + } }