mirror of
https://github.com/espressif/esp-idf.git
synced 2025-09-30 19:19:21 +00:00
usb: Added MIDI example + fixed TinyUSB MIDI config
Closes https://github.com/espressif/esp-idf/issues/8541
This commit is contained in:
6
examples/peripherals/usb/device/tusb_midi/CMakeLists.txt
Normal file
6
examples/peripherals/usb/device/tusb_midi/CMakeLists.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
# The following five lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(tusb_midi)
|
83
examples/peripherals/usb/device/tusb_midi/README.md
Normal file
83
examples/peripherals/usb/device/tusb_midi/README.md
Normal file
@@ -0,0 +1,83 @@
|
||||
| Supported Targets | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | -------- | -------- |
|
||||
|
||||
# TinyUSB MIDI Device Example
|
||||
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
This example shows how to set up ESP chip to work as a USB MIDI Device.
|
||||
It outputs a MIDI note sequence via the native USB port.
|
||||
|
||||
As a USB stack, a TinyUSB component is used.
|
||||
|
||||
## How to use example
|
||||
|
||||
### Hardware Required
|
||||
|
||||
Any ESP board that have USB-OTG supported.
|
||||
|
||||
#### Pin Assignment
|
||||
|
||||
_Note:_ In case your board doesn't have micro-USB connector connected to USB-OTG peripheral, you may have to DIY a cable and connect **D+** and **D-** to the pins listed below.
|
||||
|
||||
See common pin assignments for USB Device examples from [upper level](../../README.md#common-pin-assignments).
|
||||
|
||||
### Build and Flash
|
||||
|
||||
Build the project and flash it to the board, then run monitor tool to view serial output:
|
||||
|
||||
```bash
|
||||
idf.py -p PORT flash monitor
|
||||
```
|
||||
|
||||
(Replace PORT with the name of the serial port to use.)
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
|
||||
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
## MIDI output
|
||||
|
||||
You can use several programs on your computer to listen to the ESP's MIDI output depending on your operating system, e.g.:
|
||||
|
||||
* Windows: `MIDI-OX`
|
||||
* Linux: `qsynth` with `qjackctl`
|
||||
* macOS: `SimpleSynth`
|
||||
|
||||
## Example Output
|
||||
|
||||
After the flashing you should see the output at idf monitor:
|
||||
|
||||
```
|
||||
I (285) example: USB initialization
|
||||
I (285) tusb_desc:
|
||||
┌─────────────────────────────────┐
|
||||
│ USB Device Descriptor Summary │
|
||||
├───────────────────┬─────────────┤
|
||||
│bDeviceClass │ 0 │
|
||||
├───────────────────┼─────────────┤
|
||||
│bDeviceSubClass │ 0 │
|
||||
├───────────────────┼─────────────┤
|
||||
│bDeviceProtocol │ 0 │
|
||||
├───────────────────┼─────────────┤
|
||||
│bMaxPacketSize0 │ 64 │
|
||||
├───────────────────┼─────────────┤
|
||||
│idVendor │ 0x303a │
|
||||
├───────────────────┼─────────────┤
|
||||
│idProduct │ 0x4008 │
|
||||
├───────────────────┼─────────────┤
|
||||
│bcdDevice │ 0x100 │
|
||||
├───────────────────┼─────────────┤
|
||||
│iManufacturer │ 0x1 │
|
||||
├───────────────────┼─────────────┤
|
||||
│iProduct │ 0x2 │
|
||||
├───────────────────┼─────────────┤
|
||||
│iSerialNumber │ 0x3 │
|
||||
├───────────────────┼─────────────┤
|
||||
│bNumConfigurations │ 0x1 │
|
||||
└───────────────────┴─────────────┘
|
||||
I (455) TinyUSB: TinyUSB Driver installed
|
||||
I (465) example: USB initialization DONE
|
||||
```
|
||||
|
||||
Disconnect UART-to-USB port and connect the native USB port to a computer then the device should show up as a USB MIDI Device while outputting notes.
|
@@ -0,0 +1,3 @@
|
||||
idf_component_register(SRCS "tusb_midi_main.c"
|
||||
INCLUDE_DIRS "."
|
||||
)
|
105
examples/peripherals/usb/device/tusb_midi/main/tusb_midi_main.c
Normal file
105
examples/peripherals/usb/device/tusb_midi/main/tusb_midi_main.c
Normal file
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* SPDX-FileContributor: 2022 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"
|
||||
|
||||
static const char *TAG = "example";
|
||||
|
||||
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) {
|
||||
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.
|
||||
uint8_t note_on[3] = {0x90 | 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] = {0x80 | 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 = NULL,
|
||||
.external_phy = false // In the most cases you need to use a `false` value
|
||||
};
|
||||
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", 2 * 1024, NULL, 5, NULL);
|
||||
}
|
@@ -0,0 +1,2 @@
|
||||
CONFIG_TINYUSB=y
|
||||
CONFIG_TINYUSB_MIDI_ENABLED=y
|
Reference in New Issue
Block a user