PipeWire 1.4.10

Loading...
Searching...
No Matches
ump-utils.h
Go to the documentation of this file.
1/* Simple Plugin API */
2/* SPDX-FileCopyrightText: Copyright © 2024 Wim Taymans */
3/* SPDX-License-Identifier: MIT */
4
5
6#ifndef SPA_CONTROL_UMP_UTILS_H
7#define SPA_CONTROL_UMP_UTILS_H
8
9#ifdef __cplusplus
10 extern "C" {
11#endif
12
13#include <errno.h>
14#include <spa/utils/defs.h>
15
16#ifndef SPA_API_CONTROL_UMP_UTILS
17 #ifdef SPA_API_IMPL
18 #define SPA_API_CONTROL_UMP_UTILS SPA_API_IMPL
19 #else
20 #define SPA_API_CONTROL_UMP_UTILS static inline
21 #endif
22#endif
27
28 SPA_API_CONTROL_UMP_UTILS size_t spa_ump_message_size(uint8_t message_type)
29{
30 static const uint32_t ump_sizes[] = {
31 [0x0] = 1, /* Utility messages */
32 [0x1] = 1, /* System messages */
33 [0x2] = 1, /* MIDI 1.0 messages */
34 [0x3] = 2, /* 7bit SysEx messages */
35 [0x4] = 2, /* MIDI 2.0 messages */
36 [0x5] = 4, /* 8bit data message */
37 [0x6] = 1,
38 [0x7] = 1,
39 [0x8] = 2,
40 [0x9] = 2,
41 [0xa] = 2,
42 [0xb] = 3,
43 [0xc] = 3,
44 [0xd] = 4, /* Flexible data messages */
45 [0xe] = 4,
46 [0xf] = 4, /* Stream messages */
47 };
48 return ump_sizes[message_type & 0xf];
49}
50
51 SPA_API_CONTROL_UMP_UTILS int spa_ump_to_midi(uint32_t *ump, size_t ump_size,
52 uint8_t *midi, size_t midi_maxsize)
53{
54 int size = 0;
55
56 if (ump_size < 4)
57 return 0;
58 if (midi_maxsize < 8)
59 return -ENOSPC;
60
61 switch (ump[0] >> 28) {
62 case 0x1: /* System Real Time and System Common Messages (except System Exclusive) */
63 midi[size++] = (ump[0] >> 16) & 0xff;
64 if (midi[0] >= 0xf1 && midi[0] <= 0xf3) {
65 midi[size++] = (ump[0] >> 8) & 0x7f;
66 if (midi[0] == 0xf2)
67 midi[size++] = ump[0] & 0x7f;
68 }
69 break;
70 case 0x2: /* MIDI 1.0 Channel Voice Messages */
71 midi[size++] = (ump[0] >> 16);
72 midi[size++] = (ump[0] >> 8);
73 if (midi[0] < 0xc0 || midi[0] > 0xdf)
74 midi[size++] = (ump[0]);
75 break;
76 case 0x3: /* Data Messages (including System Exclusive) */
77 {
78 uint8_t status, i, bytes;
79
80 if (ump_size < 8)
81 return 0;
82
83 status = (ump[0] >> 20) & 0xf;
84 bytes = SPA_CLAMP((ump[0] >> 16) & 0xf, 0u, 6u);
85
86 if (status == 0 || status == 1)
87 midi[size++] = 0xf0;
88 for (i = 0 ; i < bytes; i++)
89 /* ump[0] >> 8 | ump[0] | ump[1] >> 24 | ump[1] >>16 ... */
90 midi[size++] = ump[(i+2)/4] >> ((5-i)%4 * 8);
91 if (status == 0 || status == 3)
92 midi[size++] = 0xf7;
93 break;
94 }
95 case 0x4: /* MIDI 2.0 Channel Voice Messages */
96 if (ump_size < 8)
97 return 0;
98 midi[size++] = (ump[0] >> 16) | 0x80;
99 switch (midi[0] & 0xf0) {
100 case 0xc0:
101 midi[size++] = (ump[1] >> 24);
102 break;
103 default:
104 midi[size++] = (ump[0] >> 8) & 0x7f;
105 SPA_FALLTHROUGH;
106 case 0xd0:
107 midi[size++] = (ump[1] >> 25);
108 break;
109 }
110 break;
111
112 case 0x0: /* Utility Messages */
113 case 0x5: /* Data Messages */
114 default:
115 return 0;
116 }
117 return size;
118}
119
120 SPA_API_CONTROL_UMP_UTILS int spa_ump_from_midi(uint8_t **midi, size_t *midi_size,
121 uint32_t *ump, size_t ump_maxsize, uint8_t group, uint64_t *state)
122{
123 int size = 0;
124 uint32_t i, prefix = group << 24, to_consume = 0, bytes;
125 uint8_t status, *m = (*midi), end;
126
127 if (*midi_size < 1)
128 return 0;
129 if (ump_maxsize < 16)
130 return -ENOSPC;
131
132 status = m[0];
133
134 /* SysEx */
135 if (*state == 0) {
136 if (status == 0xf0)
137 *state = 1; /* sysex start */
138 else if (status == 0xf7)
139 *state = 2; /* sysex continue */
140 }
141 if (*state & 3) {
142 prefix |= 0x30000000;
143 if (status & 0x80) {
144 m++;
145 to_consume++;
146 }
147 bytes = SPA_CLAMP(*midi_size - to_consume, 0u, 7u);
148 if (bytes > 0) {
149 end = m[bytes-1];
150 if (end & 0x80) {
151 bytes--; /* skip terminator */
152 to_consume++;
153 }
154 else
155 end = 0xf0; /* pretend there is a continue terminator */
156
157 bytes = SPA_CLAMP(bytes, 0u, 6u);
158 to_consume += bytes;
159
160 if (end == 0xf7) {
161 if (*state == 2) {
162 /* continue and done */
163 prefix |= 0x3 << 20;
164 *state = 0;
165 }
166 } else if (*state == 1) {
167 /* first packet but not finished */
168 prefix |= 0x1 << 20;
169 *state = 2; /* sysex continue */
170 } else {
171 /* continue and not finished */
172 prefix |= 0x2 << 20;
173 }
174 ump[size++] = prefix | bytes << 16;
175 ump[size++] = 0;
176 for (i = 0 ; i < bytes; i++)
177 /* ump[0] |= (m[0] & 0x7f) << 8
178 * ump[0] |= (m[1] & 0x7f)
179 * ump[1] |= (m[2] & 0x7f) << 24
180 * ... */
181 ump[(i+2)/4] |= (m[i] & 0x7f) << ((5-i)%4 * 8);
182 }
183 } else {
184 /* regular messages */
185 switch (status) {
186 case 0x80 ... 0x8f:
187 case 0x90 ... 0x9f:
188 case 0xa0 ... 0xaf:
189 case 0xb0 ... 0xbf:
190 case 0xe0 ... 0xef:
191 to_consume = 3;
192 prefix |= 0x20000000;
193 break;
194 case 0xc0 ... 0xdf:
195 to_consume = 2;
196 prefix |= 0x20000000;
197 break;
198 case 0xf2:
199 to_consume = 3;
200 prefix |= 0x10000000;
201 break;
202 case 0xf1: case 0xf3:
203 to_consume = 2;
204 prefix |= 0x10000000;
205 break;
206 case 0xf4 ... 0xff:
207 to_consume = 1;
208 prefix |= 0x10000000;
209 break;
210 default:
211 return -EIO;
212 }
213 if (*midi_size < to_consume) {
214 to_consume = *midi_size;
215 } else {
216 prefix |= status << 16;
217 if (to_consume > 1)
218 prefix |= (m[1] & 0x7f) << 8;
219 if (to_consume > 2)
220 prefix |= (m[2] & 0x7f);
221 ump[size++] = prefix;
222 }
223 }
224 (*midi_size) -= to_consume;
225 (*midi) += to_consume;
226
227 return size * 4;
228}
229
233
234#ifdef __cplusplus
235} /* extern "C" */
236#endif
237
238#endif /* SPA_CONTROL_UMP_UTILS_H */
defs.h
spa/utils/defs.h
spa_ump_to_midi
SPA_API_CONTROL_UMP_UTILS int spa_ump_to_midi(uint32_t *ump, size_t ump_size, uint8_t *midi, size_t midi_maxsize)
Definition ump-utils.h:58
spa_ump_message_size
SPA_API_CONTROL_UMP_UTILS size_t spa_ump_message_size(uint8_t message_type)
Definition ump-utils.h:35
spa_ump_from_midi
SPA_API_CONTROL_UMP_UTILS int spa_ump_from_midi(uint8_t **midi, size_t *midi_size, uint32_t *ump, size_t ump_maxsize, uint8_t group, uint64_t *state)
Definition ump-utils.h:127
SPA_CLAMP
#define SPA_CLAMP(v, low, high)
Definition defs.h:177
SPA_FALLTHROUGH
#define SPA_FALLTHROUGH
SPA_FALLTHROUGH is an annotation to suppress compiler warnings about switch cases that fall through w...
Definition defs.h:84
SPA_API_CONTROL_UMP_UTILS
#define SPA_API_CONTROL_UMP_UTILS
Definition ump-utils.h:27