You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
175 lines
5.6 KiB
175 lines
5.6 KiB
4 months ago
|
/*
|
||
|
* SPDX-FileCopyrightText: 2019 Ha Thach (tinyusb.org)
|
||
|
*
|
||
|
* SPDX-License-Identifier: MIT
|
||
|
*
|
||
|
* SPDX-FileContributor: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||
|
*/
|
||
|
|
||
|
#include <stdlib.h>
|
||
|
#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);
|
||
|
}
|