blob: d8a42d646325b6d6940cb51a9c6bac2ba1b55f80 [file]
****
MIDI
****
Roles: device and host. TinyUSB has separate drivers for USB-MIDI 1.0 event
packets and USB-MIDI 2.0 Universal MIDI Packets (UMP). Enable the driver that
matches the data model used by the application.
MIDI 1.0 device
===============
Enable ``CFG_TUD_MIDI``, define ``CFG_TUD_MIDI_RX_BUFSIZE`` and
``CFG_TUD_MIDI_TX_BUFSIZE``, and add ``TUD_MIDI_DESCRIPTOR``.
.. list-table::
:header-rows: 1
:widths: 38 18 44
* - Option
- Default
- What it controls
* - ``CFG_TUD_MIDI_RX_BUFSIZE`` / ``CFG_TUD_MIDI_TX_BUFSIZE``
- Required when enabled
- Software FIFO bytes per interface. Define both, normally at least as
large as the matching endpoint buffer.
* - ``CFG_TUD_MIDI_RX_EPSIZE`` / ``CFG_TUD_MIDI_TX_EPSIZE``
- Device bulk maximum
- Endpoint transfer buffer bytes. Keep them at least the descriptor
packet size, the ``_epsize`` argument of ``TUD_MIDI_DESCRIPTOR``.
Use ``tud_midi_stream_read()``/``tud_midi_stream_write()`` for MIDI byte
streams on the first interface (the write takes a cable number). Use
``tud_midi_n_*`` to select an
interface, ``tud_midi_n_demux_stream_read()`` to separate received cables, and
the ``*_packet_*`` APIs when the application already works with 4-byte
USB-MIDI event packets. Drain received data in ``tud_midi_rx_cb()``.
.. list-table::
:header-rows: 1
:widths: 42 58
* - API or callback
- What it does
* - ``tud_midi_n_available()`` /
``tud_midi_n_stream_read()``
- Report the RX FIFO byte count plus the bytes left in a partially
consumed packet, and read MIDI bytes for one interface. Both ignore
``cable_num``: the read merges every cable.
* - ``tud_midi_n_demux_stream_read()``
- Reads bytes from one cable at a time, returns the byte count and writes
the cable number to ``*p_cable_num``. Do not mix it with the legacy
stream reader on the same interface.
* - ``tud_midi_n_stream_write()``
- Packetizes a MIDI byte stream and returns the number of source bytes
accepted.
* - ``tud_midi_n_packet_read_n()`` /
``tud_midi_n_packet_write_n()``
- Reads or writes complete 4-byte USB-MIDI event packets and returns a
packet count.
* - ``tud_midi_rx_cb()``
- Announces received data. Drain the FIFO so later OUT transfers have
room.
See :doc:`../../examples/device/midi_test`.
MIDI 1.0 host
=============
Set ``CFG_TUH_MIDI`` to the number of simultaneous MIDI streaming interfaces.
The following options size each instance:
.. list-table::
:header-rows: 1
:widths: 38 18 44
* - Option
- Default
- What it controls
* - ``CFG_TUH_MIDI_RX_BUFSIZE`` / ``CFG_TUH_MIDI_TX_BUFSIZE``
- Host bulk maximum
- Software FIFO capacity for received and queued event packets.
* - ``CFG_TUH_MIDI_EP_BUFSIZE``
- Host bulk maximum
- Endpoint transfer buffer size.
* - ``CFG_TUH_MIDI_STREAM_API``
- ``1``
- Enables byte-stream packetization/depacketization. Disable it to save
code size when the application uses only raw 4-byte event packets.
``tuh_midi_descriptor_cb()`` reports descriptor information before the
interface is ready; begin I/O in ``tuh_midi_mount_cb()``. Receive data in
``tuh_midi_rx_cb()`` with ``tuh_midi_stream_read()`` or
``tuh_midi_packet_read_n()``. ``tuh_midi_stream_read()`` stops at a cable
change, so call it in a loop until it returns zero; bytes left in the FIFO can
block later bulk IN transfers. Writes remain buffered until an endpoint packet
is ready or ``tuh_midi_write_flush()`` is called.
The RX and TX cable counts can differ. Query them with
``tuh_midi_get_rx_cable_count()`` and ``tuh_midi_get_tx_cable_count()`` before
selecting a cable. See :doc:`../../examples/host/midi_rx`.
``tuh_midi_read_available()`` reports raw FIFO bytes, while
``tuh_midi_stream_read()`` returns decoded MIDI stream bytes and a cable
number. ``tuh_midi_packet_read_n()`` keeps the USB event-packet format.
``tuh_midi_write_flush()`` starts a short buffered transfer and returns the
number of bytes submitted. Mount/unmount callbacks define the lifetime of the
``idx``; RX/TX callbacks announce new input and newly available TX space.
MIDI 2.0 device
===============
Enable ``CFG_TUD_MIDI2`` and add ``TUD_MIDI2_DESCRIPTOR``. The descriptor
contains alternate setting 0 for USB-MIDI 1.0 fallback and alternate setting 1
for UMP, as required by the MIDI 2.0 class specification.
.. code-block:: c
#define CFG_TUD_MIDI2 1
#define CFG_TUD_MIDI2_RX_BUFSIZE 256
#define CFG_TUD_MIDI2_TX_BUFSIZE 256
.. list-table::
:header-rows: 1
:widths: 38 18 44
* - Option
- Default
- What it controls
* - ``CFG_TUD_MIDI2_RX_EPSIZE`` / ``CFG_TUD_MIDI2_TX_EPSIZE``
- Device bulk maximum
- Endpoint transfer buffer bytes. Keep them at least the descriptor
packet size, the ``_epsize`` argument of ``TUD_MIDI2_DESCRIPTOR``.
* - ``CFG_TUD_MIDI2_RX_BUFSIZE`` / ``CFG_TUD_MIDI2_TX_BUFSIZE``
- Matching endpoint size
- UMP FIFO bytes per interface.
* - ``CFG_TUD_MIDI2_NUM_GROUPS``
- ``1``
- Number of UMP groups exposed by the default Group Terminal Block.
* - ``CFG_TUD_MIDI2_EP_NAME`` / ``CFG_TUD_MIDI2_PRODUCT_ID``
- TinyUSB strings
- Default endpoint name and product identifier returned by UMP discovery.
Override ``tud_midi2_ep_name_cb()`` / ``tud_midi2_product_id_cb()`` for
per-interface values.
* - ``CFG_TUD_MIDI2_FB_CI_VERSION`` / ``CFG_TUD_MIDI2_FB_SYSEX8_STREAMS``
- ``0``
- MIDI-CI version and SysEx8 stream count reported in Function Block Info.
* - ``CFG_TUD_MIDI2_BLOCK_STRIDX``
- ``0``
- Optional string-descriptor index (``iBlockItem``) for the default Group
Terminal Block; zero means no string.
* - ``CFG_TUD_MIDI2_GTB_PROTOCOL``
- ``MIDI2_GTB_PROTOCOL_MIDI2``
- Default ``bMIDIProtocol`` for the built-in Group Terminal Block and
``TUD_MIDI2_GTB_BLOCK`` entries; ``TUD_MIDI2_GTB_BLOCK_PROTOCOL``
entries set their own.
On alternate setting 1, read and write arrays of 32-bit words with
``tud_midi2_ump_read()`` and ``tud_midi2_ump_write()``. On alternate setting
0, use ``tud_midi2_packet_read()`` and ``tud_midi2_packet_write()`` for 4-byte
USB-MIDI 1.0 event packets. Query ``tud_midi2_alt_setting()``,
``tud_midi2_negotiated()`` and ``tud_midi2_protocol()`` when choosing the
format to send; ``tud_midi2_mounted()`` reports whether the endpoints are open.
``tud_midi2_set_itf_cb()`` announces the active alternate setting so the
application can switch its parser and producer.
``tud_midi2_ump_read()`` returns only whole UMP messages: it stops before a
message that does not fit in ``max_words`` or has not fully arrived, and
returns zero on alternate setting 0. Pass at least 4 words, the largest UMP
message, or a long message at the head of the FIFO is never read. Drain the
RX FIFO completely in the callback:
.. code-block:: c
void tud_midi2_rx_cb(uint8_t itf) {
uint32_t count;
if (tud_midi2_n_alt_setting(itf) == 1) {
uint32_t words[16];
while ((count = tud_midi2_n_ump_read(itf, words, 16)) != 0) {
process_ump(words, count); // Track message size from each MT field.
}
} else {
uint8_t packets[16 * 4];
while ((count = tud_midi2_n_packet_read(itf, packets, 16)) != 0) {
process_midi1(packets, count);
}
}
}
The driver handles standard UMP Stream discovery and protocol negotiation.
At interface open and on selecting alternate setting 1, the protocol is
initialized from the first Group Terminal Block: MIDI 1.0 for its MIDI1 values,
otherwise MIDI 2.0. Stream negotiation may change it later.
Override ``tud_midi2_gtb_desc_cb()`` to describe a custom Group Terminal Block
topology, ``tud_midi2_fb_name_cb()`` for Function Block names and
``tud_midi2_device_identity_cb()`` to send a Device Identity Notification. Use
``tud_midi2_stream_msg_cb()`` only when the application must override a built-in
Stream response.
``tud_midi2_n_available()``, ``tud_midi2_n_ump_read()`` and
``tud_midi2_n_ump_write()`` return 32-bit word counts. The packet APIs return
counts of 4-byte MIDI 1.0 event packets.
See :doc:`../../examples/device/midi2_device` for alternate-setting and
protocol fallback.
MIDI 2.0 host
=============
Set ``CFG_TUH_MIDI2`` to the required interface count. The host driver detects
both alternate settings, selects the highest available protocol, and completes
``SET_INTERFACE`` before reporting the mount.
``CFG_TUH_MIDI2_RX_BUFSIZE`` and ``CFG_TUH_MIDI2_TX_BUFSIZE`` default to the
host bulk maximum and allocate FIFO storage per instance. Increase them when
the application can be delayed for several USB transfers; keep UMP data
32-bit aligned in application buffers.
Callback order is important:
.. code-block:: text
protocol/alternate selection -> descriptor callback -> mount callback
-> RX/TX callbacks -> unmount callback
``tuh_midi2_descriptor_cb()`` is informational; the interface is not yet ready.
Start I/O only after ``tuh_midi2_mount_cb()``. In ``tuh_midi2_rx_cb()``, call
``tuh_midi2_ump_read()`` in a loop until it returns zero. Queue output with
``tuh_midi2_ump_write()`` and use ``tuh_midi2_write_flush()`` when latency
matters.
Use ``tuh_midi2_mounted()``, ``tuh_midi2_get_protocol_version()``,
``tuh_midi2_get_alt_setting_active()`` and ``tuh_midi2_get_cable_count()`` to
inspect the selected transport. The :doc:`../../examples/host/midi2_host`
example parses the UMP Message Type field to determine whether each message
occupies 1, 2, 3, or 4 words.
``tuh_midi2_ump_write()`` returns the number of words accepted and
``tuh_midi2_write_flush()`` returns the number of bytes submitted. Preserve
unaccepted words and retry after ``tuh_midi2_tx_cb()``. Treat the data supplied
to ``tuh_midi2_descriptor_cb()`` as informational only; the interface becomes
usable at ``tuh_midi2_mount_cb()`` and invalid at ``tuh_midi2_umount_cb()``.
Specification used: *USB Device Class Definition for MIDI Devices*, Release
2.0. It defines the MIDI 1.0-compatible alternate setting, the native UMP
alternate setting, Group Terminal Blocks, and discovery behavior.