/*
This is an example of using an ESP32 with a native USB support stack (S2, S3, etc.) as a Serial MIDI to
USB MIDI bridge (AKA "A MIDI Interface").

View this sketch in action on YouTube: https://youtu.be/BXG5i55I9s0

Receiving and decoding USB MIDI 1.0 packets is a more advanced topic than sending MIDI over USB,
please refer to the other examples in this library for a more basic example of sending MIDI over USB.

This example should still be self explanatory, please refer to the USB MIDI 1.0 specification (the spec)
for a more in-depth explanation of the packet format.

For the spec please visit: https://www.midi.org/specifications-old/item/usb-midi-1-0-specification

Note: Because ESP32 works at VCC=3.3v normal schematics for Serial MIDI connections will not suffice,
      Please refer to the Updated MIDI 1.1 Electrical Specification [1] for information on how to hookup
      Serial MIDI for 3.3v devices.

[1] - https://www.midi.org/specifications/midi-transports-specifications/5-pin-din-electrical-specs
*/
#include <Arduino.h>
#if ARDUINO_USB_MODE
#warning This sketch should be used when USB is in OTG mode
void setup() {}
void loop() {}
#else

// define a new USB MIDI device name using a macro
SET_USB_MIDI_DEVICE_NAME("ESP MIDI Device")

#include "USB.h"
#include "USBMIDI.h"
// Creates the MIDI device with specific name defined with the SET_USB_MIDI_DEVICE_NAME() macro
USBMIDI MIDI;

#define MIDI_RX 39
#define MIDI_TX 40

void setup() {
  // USBCDC Serial
  Serial.begin(115200);

  // HW UART Serial
  Serial1.begin(31250, SERIAL_8N1, MIDI_RX, MIDI_TX);

  MIDI.begin();
  USB.begin();
}

void loop() {
  // MIDI Serial 1.0 to USB MIDI 1.0
  if (Serial1.available()) {
    byte data = Serial1.read();
    MIDI.write(data);
  }

  // USB MIDI 1.0 to MIDI Serial 1.0
  midiEventPacket_t midi_packet_in = {0, 0, 0, 0};
  // See Chapter 4: USB-MIDI Event Packets (page 16) of the spec.
  int8_t cin_to_midix_size[16] = {-1, -1, 2, 3, 3, 1, 2, 3, 3, 3, 3, 3, 2, 2, 3, 1};

  if (MIDI.readPacket(&midi_packet_in)) {
    midi_code_index_number_t code_index_num = MIDI_EP_HEADER_CIN_GET(midi_packet_in.header);
    int8_t midix_size = cin_to_midix_size[code_index_num];

    // We skip Misc and Cable Events for simplicity
    if (code_index_num >= 0x2) {
      for (int i = 0; i < midix_size; i++) {
        Serial1.write(((uint8_t *)&midi_packet_in)[i + 1]);
      }
      Serial1.flush();
    }
  }
}
#endif /* ARDUINO_USB_MODE */
