1 /*
2  * Copyright (c) 2024 Titouan Christophe
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #ifndef ZEPHYR_INCLUDE_AUDIO_MIDI_H_
8 #define ZEPHYR_INCLUDE_AUDIO_MIDI_H_
9 
10 #ifdef __cplusplus
11 extern "C" {
12 #endif
13 
14 #include <stdint.h>
15 
16 /**
17  * @brief Universal MIDI Packet definitions
18  * @defgroup midi_ump MIDI2 Universal MIDI Packet definitions
19  * @ingroup audio_interface
20  * @since 4.1
21  * @version 0.1.0
22  * @see ump112: "Universal MIDI Packet (UMP) Format and MIDI 2.0 Protocol"
23  *              Document version 1.1.2
24  * @{
25  */
26 
27 /**
28  * @brief      Universal MIDI Packet container
29  */
30 struct midi_ump {
31 	uint32_t data[4]; /**< Raw content, in the CPU native endianness */
32 };
33 
34 /**
35  * @defgroup midi_ump_mt Message types
36  * @ingroup midi_ump
37  * @see ump112: 2.1.4 Message Type (MT) Allocation
38  * @{
39  */
40 
41 /** Utility Messages */
42 #define UMP_MT_UTILITY             0x00
43 /** System Real Time and System Common Messages (except System Exclusive) */
44 #define UMP_MT_SYS_RT_COMMON       0x01
45 /** MIDI 1.0 Channel Voice Messages */
46 #define UMP_MT_MIDI1_CHANNEL_VOICE 0x02
47 /** 64 bits Data Messages (including System Exclusive) */
48 #define UMP_MT_DATA_64             0x03
49 /** MIDI 2.0 Channel Voice Messages */
50 #define UMP_MT_MIDI2_CHANNEL_VOICE 0x04
51 /** 128 bits Data Messages */
52 #define UMP_MT_DATA_128            0x05
53 /** Flex Data Messages */
54 #define UMP_MT_FLEX_DATA           0x0d
55 /** UMP Stream Message */
56 #define UMP_MT_UMP_STREAM          0x0f
57 /** @} */
58 
59 /**
60  * @brief      Message Type field of a Universal MIDI Packet
61  * @param[in]  ump    Universal MIDI Packet
62  */
63 #define UMP_MT(ump) \
64 	((ump).data[0] >> 28)
65 
66 /**
67  * There are 16 UMP message types, each of which can be 1 to 4 uint32 long.
68  * Hence this packed representation of 16x2b array as an uint32 lookup table
69  */
70 #define UMP_NUM_WORDS_LOOKUP_TABLE \
71 	((0U << 0) | (0U << 2) | (0U << 4) | (1U << 6) | \
72 	(1U << 8) | (3U << 10) | (0U << 12) | (0U << 14) | \
73 	(1U << 16) | (1U << 18) | (1U << 20) | (2U << 22) | \
74 	(2U << 24) | (3U << 26) | (3U << 28) | (3U << 30))
75 
76 /**
77  * @brief      Size of a Universal MIDI Packet, in 32bit words
78  * @param[in]  ump    Universal MIDI Packet
79  * @see ump112: 2.1.4 Message Type (MT) Allocation
80  */
81 #define UMP_NUM_WORDS(ump) \
82 	(1 + ((UMP_NUM_WORDS_LOOKUP_TABLE >> (2 * UMP_MT(ump))) & 3))
83 
84 /**
85  * @brief      MIDI group field of a Universal MIDI Packet
86  * @param[in]  ump    Universal MIDI Packet
87  */
88 #define UMP_GROUP(ump) \
89 	(((ump).data[0] >> 24) & 0x0f)
90 
91 /**
92  * @brief      Status byte of a MIDI channel voice or system message
93  * @param[in]  ump    Universal MIDI Packet (containing a MIDI1 event)
94  */
95 #define UMP_MIDI_STATUS(ump) \
96 	(((ump).data[0] >> 16) & 0xff)
97 /**
98  * @brief      Command of a MIDI channel voice message
99  * @param[in]  ump    Universal MIDI Packet (containing a MIDI event)
100  * @see midi_ump_cmd
101  */
102 #define UMP_MIDI_COMMAND(ump) \
103 	(UMP_MIDI_STATUS(ump) >> 4)
104 /**
105  * @brief      Channel of a MIDI channel voice message
106  * @param[in]  ump    Universal MIDI Packet (containing a MIDI event)
107  */
108 #define UMP_MIDI_CHANNEL(ump) \
109 	(UMP_MIDI_STATUS(ump) & 0x0f)
110 /**
111  * @brief      First parameter of a MIDI1 channel voice or system message
112  * @param[in]  ump     Universal MIDI Packet (containing a MIDI1 message)
113  */
114 #define UMP_MIDI1_P1(ump) \
115 	(((ump).data[0] >> 8) & 0x7f)
116 /**
117  * @brief      Second parameter of a MIDI1 channel voice or system message
118  * @param[in]  ump     Universal MIDI Packet (containing a MIDI1 message)
119  */
120 #define UMP_MIDI1_P2(ump) \
121 	((ump).data[0] & 0x7f)
122 
123 /**
124  * @brief      Initialize a UMP with a MIDI1 channel voice message
125  * @remark     For messages that take a single parameter, p2 is ignored by the receiver.
126  * @param      group    The UMP group
127  * @param      command  The MIDI1 command
128  * @param      channel  The MIDI1 channel number
129  * @param      p1       The 1st MIDI1 parameter
130  * @param      p2       The 2nd MIDI1 parameter
131  */
132 #define UMP_MIDI1_CHANNEL_VOICE(group, command, channel, p1, p2) \
133 	(struct midi_ump) {.data = {                             \
134 		(UMP_MT_MIDI1_CHANNEL_VOICE << 28)               \
135 		| (((group) & 0x0f) << 24)                       \
136 		| (((command) & 0x0f) << 20)                     \
137 		| (((channel) & 0x0f) << 16)                     \
138 		| (((p1) & 0x7f) << 8)                           \
139 		| ((p2) & 0x7f)                                  \
140 	}}
141 
142 /**
143  * @defgroup midi_ump_cmd MIDI commands
144  * @ingroup midi_ump
145  * @see ump112: 7.3 MIDI 1.0 Channel Voice Messages
146  *
147  * When UMP_MT(x)=UMP_MT_MIDI1_CHANNEL_VOICE or UMP_MT_MIDI2_CHANNEL_VOICE, then
148  * UMP_MIDI_COMMAND(x) may be one of:
149  * @{
150  */
151 #define UMP_MIDI_NOTE_OFF        0x8 /**< Note Off (p1=note number, p2=velocity) */
152 #define UMP_MIDI_NOTE_ON         0x9 /**< Note On (p1=note number, p2=velocity) */
153 #define UMP_MIDI_AFTERTOUCH      0xa /**< Polyphonic aftertouch (p1=note number, p2=data) */
154 #define UMP_MIDI_CONTROL_CHANGE  0xb /**< Control Change (p1=index, p2=data) */
155 #define UMP_MIDI_PROGRAM_CHANGE  0xc /**< Control Change (p1=program) */
156 #define UMP_MIDI_CHAN_AFTERTOUCH 0xd /**< Channel aftertouch (p1=data) */
157 #define UMP_MIDI_PITCH_BEND      0xe /**< Pitch bend (p1=lsb, p2=msb) */
158 /** @} */
159 
160 /**
161  * @brief      Initialize a UMP with a System Real Time and System Common Message
162  * @remark     For messages that take only one (or no) parameter, p2 (and p1)
163  *             are ignored by the receiver.
164  * @param      group    The UMP group
165  * @param      status   The status byte
166  * @param      p1       The 1st parameter
167  * @param      p2       The 2nd parameter
168  */
169 #define UMP_SYS_RT_COMMON(group, status, p1, p2) \
170 	(struct midi_ump) {.data = {             \
171 		(UMP_MT_SYS_RT_COMMON << 28)     \
172 		| (((group) & 0x0f) << 24)       \
173 		| ((status) << 16)               \
174 		| (((p1) & 0x7f) << 8)           \
175 		| ((p2) & 0x7f)                  \
176 	}}
177 
178 /**
179  * @defgroup midi_ump_sys System common and System Real Time message status
180  * @ingroup midi_ump
181  * @see ump112: 7.6 System Common and System Real Time Messages
182  *
183  * When UMP_MT(x)=UMP_MT_SYS_RT_COMMON, UMP_MIDI_STATUS(x) may be one of:
184  * @{
185  */
186 #define UMP_SYS_MIDI_TIME_CODE 0xf1 /**< MIDI Time Code (no param) */
187 #define UMP_SYS_SONG_POSITION  0xf2 /**< Song Position Pointer (p1=lsb, p2=msb) */
188 #define UMP_SYS_SONG_SELECT    0xf3 /**< Song Select (p1=song number) */
189 #define UMP_SYS_TUNE_REQUEST   0xf6 /**< Tune Request (no param) */
190 #define UMP_SYS_TIMING_CLOCK   0xf8 /**< Timing Clock (no param) */
191 #define UMP_SYS_START          0xfa /**< Start (no param) */
192 #define UMP_SYS_CONTINUE       0xfb /**< Continue (no param) */
193 #define UMP_SYS_STOP           0xfc /**< Stop (no param) */
194 #define UMP_SYS_ACTIVE_SENSING 0xfe /**< Active sensing (no param) */
195 #define UMP_SYS_RESET          0xff /**< Reset (no param) */
196 /** @} */
197 
198 /** @} */
199 
200 #ifdef __cplusplus
201 }
202 #endif
203 
204 #endif
205