/* * SPDX-FileCopyrightText: 2019 Ha Thach (tinyusb.org) * * SPDX-License-Identifier: MIT * * SPDX-FileContributor: 2022-2023 Espressif Systems (Shanghai) CO LTD */ #include #include "esp_log.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "tinyusb.h" #include "esp_timer.h" #include "controls.h" static const char *TAG = "example"; /** Helper defines **/ // Interface counter enum interface_count { #if CFG_TUD_MIDI ITF_NUM_MIDI = 0, ITF_NUM_MIDI_STREAMING, #endif ITF_COUNT }; // USB Endpoint numbers enum usb_endpoints { // Available USB Endpoints: 5 IN/OUT EPs and 1 IN EP EP_EMPTY = 0, #if CFG_TUD_MIDI EPNUM_MIDI, #endif }; /** TinyUSB descriptors **/ #define TUSB_DESCRIPTOR_TOTAL_LEN (TUD_CONFIG_DESC_LEN + CFG_TUD_MIDI * TUD_MIDI_DESC_LEN) // Basic MIDI Messages #define NOTE_OFF 0x80 #define NOTE_ON 0x90 #define SET_CONTROL 0xB0 /** * @brief String descriptor */ static const char* s_str_desc[5] = { // array of pointer to string descriptors (char[]){0x09, 0x04}, // 0: is supported language is English (0x0409) "TinyUSB", // 1: Manufacturer "TinyUSB Device", // 2: Product "123456", // 3: Serials, should use chip ID "Example MIDI device", // 4: MIDI }; /** * @brief Configuration descriptor * * This is a simple configuration descriptor that defines 1 configuration and a MIDI interface */ static const uint8_t s_midi_cfg_desc[] = { // Configuration number, interface count, string index, total length, attribute, power in mA TUD_CONFIG_DESCRIPTOR(1, ITF_COUNT, 0, TUSB_DESCRIPTOR_TOTAL_LEN, 0, 100), // Interface number, string index, EP Out & EP In address, EP size TUD_MIDI_DESCRIPTOR(ITF_NUM_MIDI, 4, EPNUM_MIDI, (0x80 | EPNUM_MIDI), 64), }; static void midi_task_read_example(void *arg) { // The MIDI interface always creates input and output port/jack descriptors // regardless of these being used or not. Therefore incoming traffic should be read // (possibly just discarded) to avoid the sender blocking in IO uint8_t packet[4]; bool read = false; for (;;) { vTaskDelay(1); while (tud_midi_available()) { read = tud_midi_packet_read(packet); if (read) { if(packet[1] == SET_CONTROL){ setControl(packet[2], packet[3]<<1); ESP_LOGI(TAG, "setControl(packet[2]%i, packet[3]%i<1/%i)", packet[2], packet[3],packet[3]<<1); } ESP_LOGI(TAG, "Read - Time (ms since boot): %lld, Data: %02hhX %02hhX %02hhX %02hhX", esp_timer_get_time(), packet[0], packet[1], packet[2], packet[3]); } } } } static void periodic_midi_write_example_cb(void *arg) { // Example melody stored as an array of note values uint8_t const note_sequence[] = { 74, 78, 81, 86, 90, 93, 98, 102, 57, 61, 66, 69, 73, 78, 81, 85, 88, 92, 97, 100, 97, 92, 88, 85, 81, 78, 74, 69, 66, 62, 57, 62, 66, 69, 74, 78, 81, 86, 90, 93, 97, 102, 97, 93, 90, 85, 81, 78, 73, 68, 64, 61, 56, 61, 64, 68, 74, 78, 81, 86, 90, 93, 98, 102 }; static uint8_t const cable_num = 0; // MIDI jack associated with USB endpoint static uint8_t const channel = 0; // 0 for channel 1 static uint32_t note_pos = 0; // Previous positions in the note sequence. int previous = note_pos - 1; // If we currently are at position 0, set the // previous position to the last note in the sequence. if (previous < 0) { previous = sizeof(note_sequence) - 1; } // Send Note On for current position at full velocity (127) on channel 1. ESP_LOGI(TAG, "Writing MIDI data %d", note_sequence[note_pos]); if (tud_midi_mounted()) { uint8_t note_on[3] = {NOTE_ON | channel, note_sequence[note_pos], 127}; tud_midi_stream_write(cable_num, note_on, 3); // Send Note Off for previous note. uint8_t note_off[3] = {NOTE_OFF | channel, note_sequence[previous], 0}; tud_midi_stream_write(cable_num, note_off, 3); } // Increment position note_pos++; // If we are at the end of the sequence, start over. if (note_pos >= sizeof(note_sequence)) { note_pos = 0; } } void app_main(void) { ESP_LOGI(TAG, "USB initialization"); tinyusb_config_t const tusb_cfg = { .device_descriptor = NULL, // If device_descriptor is NULL, tinyusb_driver_install() will use Kconfig .string_descriptor = s_str_desc, .external_phy = false, .configuration_descriptor = s_midi_cfg_desc, }; // .string_descriptor_count = sizeof(s_str_desc) / sizeof(s_str_desc[0]), ESP_ERROR_CHECK(tinyusb_driver_install(&tusb_cfg)); ESP_LOGI(TAG, "USB initialization DONE"); // // Periodically send MIDI packets // int const tempo = 286; // const esp_timer_create_args_t periodic_midi_args = { // .callback = &periodic_midi_write_example_cb, // /* name is optional, but may help identify the timer when debugging */ // .name = "periodic_midi" // }; // ESP_LOGI(TAG, "MIDI write task init"); // esp_timer_handle_t periodic_midi_timer; // ESP_ERROR_CHECK(esp_timer_create(&periodic_midi_args, &periodic_midi_timer)); // ESP_ERROR_CHECK(esp_timer_start_periodic(periodic_midi_timer, tempo * 1000)); // Read recieved MIDI packets ESP_LOGI(TAG, "MIDI read task init"); xTaskCreate(midi_task_read_example, "midi_task_read_example", 8 * 1024, NULL, 5, NULL); ESP_LOGI(TAG, "read inputs task init"); xTaskCreate(task_read_all, "task_read_all", 8 * 1024, NULL, 21, NULL); }