-
Notifications
You must be signed in to change notification settings - Fork 6.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
usb: device_next: add new MIDI 2.0 device class
This adds a new USB device class (based on usb/device_next) that implements revision 2.0 of the MIDIStreaming interface, a sub-class of the USB audio device class. In practice, the MIDI interface is much more simple and has little in common with Audio, so it makes sense to have it as a separate class driver. MIDI inputs and outputs are configured through the device tree, under a node `compatible = "zephyr,usb-midi"`. As per the USB-MIDI2.0 spec, a single usb-midi interface can convey up to 16 Universal MIDI groups, comprising 16 channels each. Data is carried from/to the host via so-called Group Terminals, that are organized in Group Terminal Blocks. They are represented as children of the usb-midi interface in the device tree. From the Zephyr application programmer perspective, MIDI data is exchanged with the host through the device associated with the `zephyr,usb-midi` interface, using the following API: * Send a Universal MIDI Packet to the host: `usb_midi_send(device, pkt)` * Universal MIDI Packets from the host are delivered to the function passed in `usb_midi_set_callback(device, void (device, pkt){...})` Compliant USB-MIDI 2.0 devices are required to expose a USB-MIDI1.0 interface as alt setting 0, and the 2.0 interface on alt setting 1. To avoid the extra complexity of generating backward compatible USB descriptors and translating Universal MIDI Packets from/to the old USB-MIDI1.0 format, this driver generates an empty MIDI1.0 interface (without any input/output); and therefore will only be able to exchange MIDI data when the host has explicitely enabled MIDI2.0 (alt setting 1). This implementation is based on the following documents, which are referred to in the inline comments: * `midi20`: [Universal Serial Bus Device Class Definition for MIDI Devices Release 2.0](https://www.usb.org/sites/default/files/USB%20MIDI%20v2_0.pdf) * `ump112`: [Universal MIDI Packet (UMP) Format and MIDI 2.0 Protocol With MIDI 1.0 Protocol in UMP Format _Document Version 1.1.2_](https://midi.org/universal-midi-packet-ump-and-midi-2-0-protocol-specification) Signed-off-by: Titouan Christophe <[email protected]>
- Loading branch information
Showing
10 changed files
with
1,004 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,3 +11,4 @@ New USB device support APIs | |
usbd_hid_device.rst | ||
uac2_device.rst | ||
usbd_msc_device.rst | ||
usb_midi.rst |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
.. _usb_midi: | ||
|
||
MIDI 2.0 Class device API | ||
######################### | ||
|
||
USB MIDI 2.0 device specific API defined in :zephyr_file:`include/zephyr/usb/class/usb_midi.h`. | ||
|
||
API Reference | ||
************* | ||
|
||
.. doxygengroup:: usb_midi |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
# Copyright (c) 2024 Titouan Christophe | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
description: USB MIDI Class | ||
|
||
compatible: "zephyr,usb-midi" | ||
|
||
properties: | ||
"#address-cells": | ||
type: int | ||
const: 1 | ||
|
||
"#size-cells": | ||
type: int | ||
const: 1 | ||
|
||
child-binding: | ||
description: | | ||
USB MIDI Group terminal block. | ||
This represent a set of contiguous Universal MIDI groups through which the | ||
device exchange Universal MIDI Packets with the host. | ||
properties: | ||
reg: | ||
type: array | ||
required: true | ||
description: | | ||
First MIDI Group number (address) and number of Group Terminals (size) | ||
in this USB-MIDI Group Terminal Block. | ||
The MIDI Groups 1 to 16 corresponds to address 0x0 to 0xf. There are at | ||
most 16 addressable groups (of 16 channels each) per USB-MIDI interface | ||
protocol: | ||
type: string | ||
enum: | ||
- "use-midi-ci" | ||
- "midi1-up-to-64b" | ||
- "midi1-up-to-128b" | ||
- "midi2" | ||
description: | | ||
Default MIDI protocol of the Group Terminals in this Block | ||
terminal-type: | ||
type: string | ||
default: "bidirectional" | ||
enum: | ||
- "bidirectional" | ||
- "input-only" | ||
- "output-only" | ||
description: | | ||
Type (data direction) of Group Terminals in this Block. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
/* | ||
* Copyright (c) 2024 Titouan Christophe | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
#ifndef ZEPHYR_INCLUDE_USB_CLASS_MIDI_H_ | ||
#define ZEPHYR_INCLUDE_USB_CLASS_MIDI_H_ | ||
|
||
/** | ||
* @brief Universal MIDI Packet definitions | ||
* @defgroup usb_midi_ump USB MIDI 2.0 Universal MIDI Packet definitions | ||
* @ingroup usb | ||
* @since 4.1 | ||
* @version 0.1.0 | ||
* @see ump112: "Universal MIDI Packet (UMP) Format and MIDI 2.0 Protocol" | ||
* Document version 1.1.2 | ||
* @{ | ||
* | ||
* @defgroup usb_midi_ump_mt Message types | ||
* @ingroup usb_midi_ump | ||
* @see ump112: 2.1.4 Message Type (MT) Allocation | ||
* @{ | ||
*/ | ||
|
||
#define UMP_MT_UTILITY 0x00 /**< Utility Messages */ | ||
/** System Real Time and System Common Messages (except System Exclusive) */ | ||
#define UMP_MT_SYS_RT_COMMON 0x01 | ||
#define UMP_MT_MIDI1_CHANNEL_VOICE 0x02 /**< MIDI 1.0 Channel Voice Messages */ | ||
#define UMP_MT_DATA 0x03 /**< Data Messages (including System Exclusive) */ | ||
#define UMP_MT_MIDI2_CHANNEL_VOICE 0x04 /**< MIDI 2.0 Channel Voice Messages */ | ||
#define UMP_MT_FLEX_DATA 0x0d /**< Flex Data Messages */ | ||
#define UMP_MT_UMP_STREAM 0x0f /**< UMP Stream Message */ | ||
/** @} */ | ||
|
||
/** | ||
* @brief Message Type field of a Universal MIDI Packet | ||
* @param[in] ump The universal MIDI Packet | ||
*/ | ||
#define UMP_MT(ump) ((ump)[0] >> 28) | ||
|
||
/** | ||
* @brief Size of a Universal MIDI Packet, in 32bit words | ||
* @param[in] ump The universal MIDI Packet | ||
* @see ump112: 2.1.4 Message Type (MT) Allocation | ||
*/ | ||
#define UMP_WORDS(ump) (1 + ((0xfe950d40 >> (2 * UMP_MT(ump))) & 3)) | ||
|
||
/** | ||
* @brief MIDI group field of a Universal MIDI Packet | ||
* @param[in] ump The universal MIDI Packet | ||
*/ | ||
#define UMP_GROUP(ump) (((ump)[0] >> 24) & 0x0f) | ||
|
||
/** | ||
* @brief Status byte of a MIDI channel voice or system message | ||
* @param[in] ump A universal MIDI Packet (containing a MIDI1 event) | ||
*/ | ||
#define UMP_MIDI_STATUS(ump) (((ump)[0] >> 16) & 0xff) | ||
/** | ||
* @brief Command of a MIDI channel voice message | ||
* @param[in] ump A universal MIDI Packet (containing a MIDI event) | ||
* @see usb_midi_cmd | ||
*/ | ||
#define UMP_MIDI_COMMAND(ump) (UMP_MIDI_STATUS(ump) >> 4) | ||
/** | ||
* @brief Channel of a MIDI channel voice message | ||
* @param[in] ump A universal MIDI Packet (containing a MIDI event) | ||
*/ | ||
#define UMP_MIDI_CHANNEL(ump) (UMP_MIDI_STATUS(ump) & 0x0f) | ||
/** | ||
* @brief First parameter of a MIDI1 channel voice or system message | ||
* @param[in] ump A universal MIDI Packet (containing a MIDI1 event) | ||
*/ | ||
#define UMP_MIDI1_P1(ump) (((ump)[0] >> 8) & 0x7f) | ||
/** | ||
* @brief Second parameter of a MIDI1 channel voice or system message | ||
* @param[in] ump A universal MIDI Packet (containing a MIDI1 event) | ||
*/ | ||
#define UMP_MIDI1_P2(ump) ((ump)[0] & 0x7f) | ||
|
||
/** | ||
* @brief Initialize a MIDI1 Universal Midi Packet | ||
* @param group The UMP group | ||
* @param command The MIDI1 command | ||
* @param channel The MIDI1 channel number | ||
* @param p1 The 1st MIDI1 parameter | ||
* @param p2 The 2nd MIDI1 parameter | ||
*/ | ||
#define UMP_MIDI1(group, command, channel, p1, p2) \ | ||
(const uint32_t[]) \ | ||
{ \ | ||
(UMP_MT_MIDI1_CHANNEL_VOICE << 28) | ((group & 0x0f) << 24) | \ | ||
((command & 0x0f) << 20) | ((channel & 0x0f) << 16) | ((p1 & 0x7f) << 8) | \ | ||
(p2 & 0x7f) \ | ||
} | ||
|
||
/** | ||
* @defgroup usb_midi_ump_cmd MIDI commands | ||
* @ingroup usb_midi_ump | ||
* @see ump112: 7.3 MIDI 1.0 Channel Voice Messages | ||
* | ||
* When UMP_MT(x)=UMP_MT_MIDI1_CHANNEL_VOICE or UMP_MT_MIDI2_CHANNEL_VOICE, then | ||
* UMP_MIDI_COMMAND(x) may be one of: | ||
* @{ | ||
*/ | ||
#define UMP_MIDI_NOTE_OFF 0x8 /**< Note Off (p1=note number, p2=velocity) */ | ||
#define UMP_MIDI_NOTE_ON 0x9 /**< Note On (p1=note number, p2=velocity) */ | ||
#define UMP_MIDI_AFTERTOUCH 0xa /**< Polyphonic aftertouch (p1=note number, p2=data) */ | ||
#define UMP_MIDI_CONTROL_CHANGE 0xb /**< Control Change (p1=index, p2=data) */ | ||
#define UMP_MIDI_PROGRAM_CHANGE 0xc /**< Control Change (p1=program) */ | ||
#define UMP_MIDI_CHAN_AFTERTOUCH 0xd /**< Channel aftertouch (p1=data) */ | ||
#define UMP_MIDI_PITCH_BEND 0xe /**< Pitch bend (p1=lsb, p2=msb) */ | ||
/** @} */ | ||
|
||
/** | ||
* @defgroup usb_midi_ump_sys System common and System Real Time message status | ||
* @ingroup usb_midi_ump | ||
* @see ump112: 7.6 System Common and System Real Time Messages | ||
* | ||
* When UMP_MT(x)=UMP_MT_SYS_RT_COMMON, UMP_MIDI_STATUS(x) may be one of: | ||
* @{ | ||
*/ | ||
#define UMP_SYS_MIDI_TIME_CODE 0xf1 /**< MIDI Time Code (no param) */ | ||
#define UMP_SYS_SONG_POSITION 0xf2 /**< Song Position Pointer (p1=lsb, p2=msb) */ | ||
#define UMP_SYS_SONG_SELECT 0xf3 /**< Song Select (p1=song number) */ | ||
#define UMP_SYS_TUNE_REQUEST 0xf6 /**< Tune Request (no param) */ | ||
#define UMP_SYS_TIMING_CLOCK 0xf8 /**< Timing Clock (no param) */ | ||
#define UMP_SYS_START 0xfa /**< Start (no param) */ | ||
#define UMP_SYS_CONTINUE 0xfb /**< Continue (no param) */ | ||
#define UMP_SYS_STOP 0xfc /**< Stop (no param) */ | ||
#define UMP_SYS_ACTIVE_SENSING 0xfe /**< Active sensing (no param) */ | ||
#define UMP_SYS_RESET 0xff /**< Reset (no param) */ | ||
/** @} */ | ||
|
||
/** @} */ | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
/* | ||
* Copyright (c) 2024 Titouan Christophe | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
#ifndef ZEPHYR_INCLUDE_USB_CLASS_USBD_MIDI_H_ | ||
#define ZEPHYR_INCLUDE_USB_CLASS_USBD_MIDI_H_ | ||
|
||
/** | ||
* @brief USB-MIDI 2.0 class device API | ||
* @defgroup usb_midi USB MIDI 2.0 Class device API | ||
* @ingroup usb | ||
* @since 4.1 | ||
* @version 0.1.0 | ||
* @see midi20: "Universal Serial Bus Device Class Definition for MIDI Devices" | ||
* Document Release 2.0 (May 5, 2020) | ||
* @{ | ||
*/ | ||
|
||
#include <zephyr/device.h> | ||
|
||
/** | ||
* @brief Send a Universal MIDI Packet to the host | ||
* @param[in] dev The USB-MIDI interface | ||
* @param[in] ump The packet to send, in Universal MIDI Packet format | ||
* @return 0 on success | ||
* -EIO if MIDI2.0 is not enabled by the host | ||
* -EAGAIN if there isn't room in the transmission buffer | ||
*/ | ||
int usbd_midi_send(const struct device *dev, const uint32_t *ump); | ||
|
||
/** | ||
* @brief Callback type for incoming Universal MIDI Packets from host | ||
* @param[in] dev The USB-MIDI interface receiving the packet | ||
* @param[in] ump The received packet in Universal MIDI Packet format | ||
*/ | ||
typedef void (*usbd_midi_callback)(const struct device *dev, const uint32_t *ump); | ||
|
||
/** | ||
* @brief Set a user callback to invoke when receiving a packet from host | ||
* @param[in] dev The USB-MIDI interface | ||
* @param[in] cb The function to call | ||
*/ | ||
void usbd_midi_set_callback(const struct device *dev, usbd_midi_callback cb); | ||
|
||
/** | ||
* @} | ||
*/ | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,3 +10,4 @@ rsource "Kconfig.bt" | |
rsource "Kconfig.msc" | ||
rsource "Kconfig.uac2" | ||
rsource "Kconfig.hid" | ||
rsource "Kconfig.midi" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
# Copyright (c) 2024 Titouan Christophe | ||
# | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
config USBD_MIDI_CLASS | ||
bool "USB MIDI 2.0 class support [EXPERIMENTAL]" | ||
select RING_BUFFER | ||
help | ||
Enable the USB MIDI 2.0 device class support. | ||
|
||
if USBD_MIDI_CLASS | ||
|
||
module = USBD_MIDI | ||
module-str = usbd midi | ||
source "subsys/logging/Kconfig.template.log_config" | ||
|
||
endif |
Oops, something went wrong.