1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /**
3 * \file rawmidi/ump.c
4 * \brief Universal MIDI Protocol (UMP) Interface
5 */
6
7 #include "rawmidi_local.h"
8 #include "ump_local.h"
9
get_rawmidi_flags(snd_ump_t *ump)10 static int get_rawmidi_flags(snd_ump_t *ump)
11 {
12 snd_rawmidi_info_t info;
13 int err;
14
15 err = snd_rawmidi_info(ump->rawmidi, &info);
16 if (err < 0)
17 return err;
18 if (!(info.flags & SNDRV_RAWMIDI_INFO_UMP))
19 return -EINVAL;
20 ump->flags = info.flags;
21 return 0;
22 }
23
24 /**
25 * \brief Opens a new connection to the UMP interface.
26 * \param inputp Returned input handle (NULL if not wanted)
27 * \param outputp Returned output handle (NULL if not wanted)
28 * \param name ASCII identifier of the UMP handle
29 * \param mode Open mode
30 * \return 0 on success otherwise a negative error code
31 *
32 * Opens a new connection to the UMP interface specified with
33 * an ASCII identifier and mode.
34 */
snd_ump_open(snd_ump_t **inputp, snd_ump_t **outputp, const char *name, int mode)35 int snd_ump_open(snd_ump_t **inputp, snd_ump_t **outputp, const char *name,
36 int mode)
37 {
38 snd_ump_t *input = NULL, *output = NULL;
39 int err;
40
41 if (inputp)
42 *inputp = NULL;
43 if (outputp)
44 *outputp = NULL;
45 if (!inputp && !outputp)
46 return -EINVAL;
47
48 err = -ENOMEM;
49 if (inputp) {
50 input = calloc(1, sizeof(*input));
51 if (!input)
52 goto error;
53 input->is_input = 1;
54 }
55 if (outputp) {
56 output = calloc(1, sizeof(*output));
57 if (!output)
58 goto error;
59 }
60
61 err = snd_rawmidi_open(input ? &input->rawmidi : NULL,
62 output ? &output->rawmidi : NULL,
63 name, mode | _SND_RAWMIDI_OPEN_UMP);
64 if (err < 0)
65 goto error;
66
67 if (input) {
68 err = get_rawmidi_flags(input);
69 if (err < 0)
70 goto error;
71 }
72 if (output) {
73 err = get_rawmidi_flags(output);
74 if (err < 0)
75 goto error;
76 }
77
78 if (inputp)
79 *inputp = input;
80 if (outputp)
81 *outputp = output;
82
83 return 0;
84
85 error:
86 if (input) {
87 if (input->rawmidi)
88 snd_rawmidi_close(input->rawmidi);
89 free(input);
90 }
91 if (output) {
92 if (output->rawmidi)
93 snd_rawmidi_close(output->rawmidi);
94 free(output);
95 }
96 return err;
97 }
98
99 /**
100 * \brief close UMP handle
101 * \param ump UMP handle
102 * \return 0 on success otherwise a negative error code
103 *
104 * Closes the specified UMP handle and frees all associated
105 * resources.
106 */
snd_ump_close(snd_ump_t *ump)107 int snd_ump_close(snd_ump_t *ump)
108 {
109 int err;
110
111 err = snd_rawmidi_close(ump->rawmidi);
112 free(ump);
113 return err;
114 }
115
116 /**
117 * \brief get RawMidi instance associated with the UMP handle
118 * \param ump UMP handle
119 * \return the associated RawMidi handle
120 *
121 * Returns the associated RawMidi instance with the given UMP handle
122 */
snd_ump_rawmidi(snd_ump_t *ump)123 snd_rawmidi_t *snd_ump_rawmidi(snd_ump_t *ump)
124 {
125 return ump->rawmidi;
126 }
127
128 /**
129 * \brief get identifier of UMP handle
130 * \param ump UMP handle
131 * \return ascii identifier of UMP handle
132 *
133 * Returns the ASCII identifier of given UMP handle. It's the same
134 * identifier specified in snd_ump_open().
135 */
snd_ump_name(snd_ump_t *ump)136 const char *snd_ump_name(snd_ump_t *ump)
137 {
138 return snd_rawmidi_name(ump->rawmidi);
139 }
140
141 /**
142 * \brief get count of poll descriptors for UMP handle
143 * \param ump UMP handle
144 * \return count of poll descriptors
145 */
snd_ump_poll_descriptors_count(snd_ump_t *ump)146 int snd_ump_poll_descriptors_count(snd_ump_t *ump)
147 {
148 return snd_rawmidi_poll_descriptors_count(ump->rawmidi);
149 }
150
151 /**
152 * \brief get poll descriptors
153 * \param ump UMP handle
154 * \param pfds array of poll descriptors
155 * \param space space in the poll descriptor array
156 * \return count of filled descriptors
157 */
snd_ump_poll_descriptors(snd_ump_t *ump, struct pollfd *pfds, unsigned int space)158 int snd_ump_poll_descriptors(snd_ump_t *ump, struct pollfd *pfds,
159 unsigned int space)
160 {
161 return snd_rawmidi_poll_descriptors(ump->rawmidi, pfds, space);
162 }
163
164 /**
165 * \brief get returned events from poll descriptors
166 * \param ump UMP handle
167 * \param pfds array of poll descriptors
168 * \param nfds count of poll descriptors
169 * \param revents returned events
170 * \return zero if success, otherwise a negative error code
171 */
snd_ump_poll_descriptors_revents(snd_ump_t *ump, struct pollfd *pfds, unsigned int nfds, unsigned short *revents)172 int snd_ump_poll_descriptors_revents(snd_ump_t *ump, struct pollfd *pfds,
173 unsigned int nfds, unsigned short *revents)
174 {
175 return snd_rawmidi_poll_descriptors_revents(ump->rawmidi, pfds, nfds,
176 revents);
177 }
178
179 /**
180 * \brief set nonblock mode
181 * \param ump UMP handle
182 * \param nonblock 0 = block, 1 = nonblock mode
183 * \return 0 on success otherwise a negative error code
184 *
185 * The nonblock mode cannot be used when the stream is in
186 * #SND_RAWMIDI_APPEND state.
187 */
snd_ump_nonblock(snd_ump_t *ump, int nonblock)188 int snd_ump_nonblock(snd_ump_t *ump, int nonblock)
189 {
190 return snd_rawmidi_nonblock(ump->rawmidi, nonblock);
191 }
192
193 /**
194 * \brief get information about associated RawMidi handle
195 * \param ump UMP handle
196 * \param info pointer to a snd_rawmidi_info_t structure to be filled
197 * \return 0 on success otherwise a negative error code
198 */
snd_ump_rawmidi_info(snd_ump_t *ump, snd_rawmidi_info_t *info)199 int snd_ump_rawmidi_info(snd_ump_t *ump, snd_rawmidi_info_t *info)
200 {
201 return snd_rawmidi_info(ump->rawmidi, info);
202 }
203
204 /**
205 * \brief set parameters about associated RawMidi stream
206 * \param ump UMP handle
207 * \param params pointer to a snd_rawmidi_params_t structure to be filled
208 * \return 0 on success otherwise a negative error code
209 */
snd_ump_rawmidi_params(snd_ump_t *ump, snd_rawmidi_params_t *params)210 int snd_ump_rawmidi_params(snd_ump_t *ump, snd_rawmidi_params_t *params)
211 {
212 return snd_rawmidi_params(ump->rawmidi, params);
213 }
214
215 /**
216 * \brief get current parameters about associated RawMidi stream
217 * \param ump UMP handle
218 * \param params pointer to a snd_rawmidi_params_t structure to be filled
219 * \return 0 on success otherwise a negative error code
220 */
snd_ump_rawmidi_params_current(snd_ump_t *ump, snd_rawmidi_params_t *params)221 int snd_ump_rawmidi_params_current(snd_ump_t *ump, snd_rawmidi_params_t *params)
222 {
223 return snd_rawmidi_params_current(ump->rawmidi, params);
224 }
225
226 /**
227 * \brief get status of associated RawMidi stream
228 * \param ump UMP handle
229 * \param status pointer to a snd_rawmidi_status_t structure to be filled
230 * \return 0 on success otherwise a negative error code
231 */
snd_ump_rawmidi_status(snd_ump_t *ump, snd_rawmidi_status_t *status)232 int snd_ump_rawmidi_status(snd_ump_t *ump, snd_rawmidi_status_t *status)
233 {
234 return snd_rawmidi_status(ump->rawmidi, status);
235 }
236
237 /**
238 * \brief drop all packets in the rawmidi I/O ring buffer immediately
239 * \param ump UMP handle
240 * \return 0 on success otherwise a negative error code
241 */
snd_ump_drop(snd_ump_t *ump)242 int snd_ump_drop(snd_ump_t *ump)
243 {
244 return snd_rawmidi_drop(ump->rawmidi);
245 }
246
247 /**
248 * \brief drain all packets in the UMP I/O ring buffer
249 * \param ump UMP handle
250 * \return 0 on success otherwise a negative error code
251 *
252 * Waits until all MIDI packets are not drained (sent) to the
253 * hardware device.
254 */
snd_ump_drain(snd_ump_t *ump)255 int snd_ump_drain(snd_ump_t *ump)
256 {
257 return snd_rawmidi_drain(ump->rawmidi);
258 }
259
260 /**
261 * \brief write UMP packets to UMP stream
262 * \param ump UMP handle
263 * \param buffer buffer containing UMP packets
264 * \param size output buffer size in bytes
265 */
snd_ump_write(snd_ump_t *ump, const void *buffer, size_t size)266 ssize_t snd_ump_write(snd_ump_t *ump, const void *buffer, size_t size)
267 {
268 if (ump->is_input)
269 return -EINVAL;
270 return snd_rawmidi_write(ump->rawmidi, buffer, size);
271 }
272
273 /**
274 * \brief read UMP packets from UMP stream
275 * \param ump UMP handle
276 * \param buffer buffer to store the input MIDI bytes
277 * \param size input buffer size in bytes
278 * \retval count of UMP packet in bytes otherwise a negative error code
279 */
snd_ump_read(snd_ump_t *ump, void *buffer, size_t size)280 ssize_t snd_ump_read(snd_ump_t *ump, void *buffer, size_t size)
281 {
282 if (!ump->is_input)
283 return -EINVAL;
284 return snd_rawmidi_read(ump->rawmidi, buffer, size);
285 }
286
287 /**
288 * \brief read UMP packets from UMP stream with timestamp
289 * \param ump UMP handle
290 * \param[out] tstamp timestamp for the returned UMP packets
291 * \param buffer buffer to store the input UMP packets
292 * \param size input buffer size in bytes
293 * \retval count of UMP packet in bytes otherwise a negative error code
294 */
snd_ump_tread(snd_ump_t *ump, struct timespec *tstamp, void *buffer, size_t size)295 ssize_t snd_ump_tread(snd_ump_t *ump, struct timespec *tstamp, void *buffer,
296 size_t size)
297 {
298 if (!ump->is_input)
299 return -EINVAL;
300 return snd_rawmidi_tread(ump->rawmidi, tstamp, buffer, size);
301 }
302
303 /**
304 * \brief get size of the snd_ump_endpoint_info_t structure in bytes
305 * \return size of the snd_ump_endpoint_info_t structure in bytes
306 */
snd_ump_endpoint_info_sizeof(void)307 size_t snd_ump_endpoint_info_sizeof(void)
308 {
309 return sizeof(snd_ump_endpoint_info_t);
310 }
311
312 /**
313 * \brief allocate the snd_ump_endpoint_info_t structure
314 * \param info returned pointer
315 * \return 0 on success otherwise a negative error code if fails
316 *
317 * Allocates a new snd_rawmidi_status_t structure using the standard
318 * malloc C library function.
319 */
snd_ump_endpoint_info_malloc(snd_ump_endpoint_info_t **info)320 int snd_ump_endpoint_info_malloc(snd_ump_endpoint_info_t **info)
321 {
322 *info = calloc(1, sizeof(snd_ump_endpoint_info_t));
323 if (!*info)
324 return -ENOMEM;
325 return 0;
326 }
327
328 /**
329 * \brief frees the snd_ump_endpoint_info_t structure
330 * \param info pointer to the snd_ump_endpoint_info_t structure to free
331 *
332 * Frees the given snd_ump_endpoint_info_t structure using the standard
333 * free C library function.
334 */
snd_ump_endpoint_info_free(snd_ump_endpoint_info_t *info)335 void snd_ump_endpoint_info_free(snd_ump_endpoint_info_t *info)
336 {
337 free(info);
338 }
339
340 /**
341 * \brief copy one snd_ump_endpoint_info_t structure to another
342 * \param dst destination snd_ump_endpoint_info_t structure
343 * \param src source snd_ump_endpoint_info_t structure
344 */
snd_ump_endpoint_info_copy(snd_ump_endpoint_info_t *dst, const snd_ump_endpoint_info_t *src)345 void snd_ump_endpoint_info_copy(snd_ump_endpoint_info_t *dst,
346 const snd_ump_endpoint_info_t *src)
347 {
348 *dst = *src;
349 }
350
351 /**
352 * \brief get card number of UMP endpoint
353 * \param info pointer to a snd_ump_endpoint_info_t structure
354 * \return the card number of the given UMP endpoint
355 */
snd_ump_endpoint_info_get_card(const snd_ump_endpoint_info_t *info)356 int snd_ump_endpoint_info_get_card(const snd_ump_endpoint_info_t *info)
357 {
358 return info->card;
359 }
360
361 /**
362 * \brief get device number of UMP endpoint
363 * \param info pointer to a snd_ump_endpoint_info_t structure
364 * \return the device number of the given UMP endpoint
365 */
snd_ump_endpoint_info_get_device(const snd_ump_endpoint_info_t *info)366 int snd_ump_endpoint_info_get_device(const snd_ump_endpoint_info_t *info)
367 {
368 return info->device;
369 }
370
371 /**
372 * \brief get UMP endpoint info flags
373 * \param info pointer to a snd_ump_endpoint_info_t structure
374 * \return UMP endpoint flag bits
375 */
snd_ump_endpoint_info_get_flags(const snd_ump_endpoint_info_t *info)376 unsigned int snd_ump_endpoint_info_get_flags(const snd_ump_endpoint_info_t *info)
377 {
378 return info->flags;
379 }
380
381 /**
382 * \brief get UMP endpoint protocol capability bits
383 * \param info pointer to a snd_ump_endpoint_info_t structure
384 * \return UMP endpoint protocol capability bits
385 */
snd_ump_endpoint_info_get_protocol_caps(const snd_ump_endpoint_info_t *info)386 unsigned int snd_ump_endpoint_info_get_protocol_caps(const snd_ump_endpoint_info_t *info)
387 {
388 return info->protocol_caps;
389 }
390
391 /**
392 * \brief get the current UMP endpoint protocol
393 * \param info pointer to a snd_ump_endpoint_info_t structure
394 * \return UMP endpoint protocol bits
395 */
snd_ump_endpoint_info_get_protocol(const snd_ump_endpoint_info_t *info)396 unsigned int snd_ump_endpoint_info_get_protocol(const snd_ump_endpoint_info_t *info)
397 {
398 return info->protocol;
399 }
400
401 /**
402 * \brief get the number of UMP blocks belonging to the endpoint
403 * \param info pointer to a snd_ump_endpoint_info_t structure
404 * \return number of UMP blocks
405 */
snd_ump_endpoint_info_get_num_blocks(const snd_ump_endpoint_info_t *info)406 unsigned int snd_ump_endpoint_info_get_num_blocks(const snd_ump_endpoint_info_t *info)
407 {
408 return info->num_blocks;
409 }
410
411 /**
412 * \brief get UMP version number
413 * \param info pointer to a snd_ump_endpoint_info_t structure
414 * \return UMP version number
415 */
snd_ump_endpoint_info_get_version(const snd_ump_endpoint_info_t *info)416 unsigned int snd_ump_endpoint_info_get_version(const snd_ump_endpoint_info_t *info)
417 {
418 return info->version;
419 }
420
421 /**
422 * \brief get UMP manufacturer ID
423 * \param info pointer to a snd_ump_endpoint_info_t structure
424 * \return UMP manufacturer ID
425 */
snd_ump_endpoint_info_get_manufacturer_id(const snd_ump_endpoint_info_t *info)426 unsigned int snd_ump_endpoint_info_get_manufacturer_id(const snd_ump_endpoint_info_t *info)
427 {
428 return info->manufacturer_id;
429 }
430
431 /**
432 * \brief get UMP family ID
433 * \param info pointer to a snd_ump_endpoint_info_t structure
434 * \return UMP family ID
435 */
snd_ump_endpoint_info_get_family_id(const snd_ump_endpoint_info_t *info)436 unsigned int snd_ump_endpoint_info_get_family_id(const snd_ump_endpoint_info_t *info)
437 {
438 return info->family_id;
439 }
440
441 /**
442 * \brief get UMP model ID
443 * \param info pointer to a snd_ump_endpoint_info_t structure
444 * \return UMP model ID
445 */
snd_ump_endpoint_info_get_model_id(const snd_ump_endpoint_info_t *info)446 unsigned int snd_ump_endpoint_info_get_model_id(const snd_ump_endpoint_info_t *info)
447 {
448 return info->model_id;
449 }
450
451 /**
452 * \brief get UMP software revision
453 * \param info pointer to a snd_ump_endpoint_info_t structure
454 * \return UMP software revision
455 */
snd_ump_endpoint_info_get_sw_revision(const snd_ump_endpoint_info_t *info)456 const unsigned char *snd_ump_endpoint_info_get_sw_revision(const snd_ump_endpoint_info_t *info)
457 {
458 return info->sw_revision;
459 }
460
461 /**
462 * \brief get UMP endpoint name string
463 * \param info pointer to a snd_ump_endpoint_info_t structure
464 * \return UMP endpoint name string
465 */
snd_ump_endpoint_info_get_name(const snd_ump_endpoint_info_t *info)466 const char *snd_ump_endpoint_info_get_name(const snd_ump_endpoint_info_t *info)
467 {
468 return (const char *)info->name;
469 }
470
471 /**
472 * \brief get UMP endpoint product ID string
473 * \param info pointer to a snd_ump_endpoint_info_t structure
474 * \return UMP endpoint product ID string
475 */
snd_ump_endpoint_info_get_product_id(const snd_ump_endpoint_info_t *info)476 const char *snd_ump_endpoint_info_get_product_id(const snd_ump_endpoint_info_t *info)
477 {
478 return (const char *)info->product_id;
479 }
480
481 /**
482 * \brief get endpoint information about UMP handle
483 * \param ump UMP handle
484 * \param info pointer to a snd_ump_endpoint_info_t structure to be filled
485 * \return 0 on success otherwise a negative error code
486 */
snd_ump_endpoint_info(snd_ump_t *ump, snd_ump_endpoint_info_t *info)487 int snd_ump_endpoint_info(snd_ump_t *ump, snd_ump_endpoint_info_t *info)
488 {
489 return _snd_rawmidi_ump_endpoint_info(ump->rawmidi, info);
490 }
491
492 /**
493 * \brief get size of the snd_ump_block_info_t structure in bytes
494 * \return size of the snd_ump_block_info_t structure in bytes
495 */
snd_ump_block_info_sizeof(void)496 size_t snd_ump_block_info_sizeof(void)
497 {
498 return sizeof(snd_ump_block_info_t);
499 }
500
501 /**
502 * \brief allocate the snd_ump_block_info_t structure
503 * \param info returned pointer
504 * \return 0 on success otherwise a negative error code if fails
505 *
506 * Allocates a new snd_ump_block_info_t structure using the standard
507 * malloc C library function.
508 */
snd_ump_block_info_malloc(snd_ump_block_info_t **info)509 int snd_ump_block_info_malloc(snd_ump_block_info_t **info)
510 {
511 *info = calloc(1, sizeof(snd_ump_block_info_t));
512 if (!*info)
513 return -ENOMEM;
514 return 0;
515 }
516
517 /**
518 * \brief frees the snd_ump_block_info_t structure
519 * \param info pointer to the snd_ump_block_info_t structure to free
520 *
521 * Frees the given snd_ump_block_info_t structure using the standard
522 * free C library function.
523 */
snd_ump_block_info_free(snd_ump_block_info_t *info)524 void snd_ump_block_info_free(snd_ump_block_info_t *info)
525 {
526 free(info);
527 }
528
529 /**
530 * \brief copy one snd_ump_block_info_t structure to another
531 * \param dst destination snd_ump_block_info_t structure
532 * \param src source snd_ump_block_info_t structure
533 */
snd_ump_block_info_copy(snd_ump_block_info_t *dst, const snd_ump_block_info_t *src)534 void snd_ump_block_info_copy(snd_ump_block_info_t *dst,
535 const snd_ump_block_info_t *src)
536 {
537 *dst = *src;
538 }
539
540 /**
541 * \brief get card number of UMP block
542 * \param info pointer to a snd_ump_block_info_t structure
543 * \return the card number of the given UMP block
544 */
snd_ump_block_info_get_card(const snd_ump_block_info_t *info)545 int snd_ump_block_info_get_card(const snd_ump_block_info_t *info)
546 {
547 return info->card;
548 }
549
550 /**
551 * \brief get device number of UMP block
552 * \param info pointer to a snd_ump_block_info_t structure
553 * \return the device number of the given UMP block
554 */
snd_ump_block_info_get_device(const snd_ump_block_info_t *info)555 int snd_ump_block_info_get_device(const snd_ump_block_info_t *info)
556 {
557 return info->device;
558 }
559
560 /**
561 * \brief get UMP block ID
562 * \param info pointer to a snd_ump_block_info_t structure
563 * \return ID number of the given UMP block
564 */
snd_ump_block_info_get_block_id(const snd_ump_block_info_t *info)565 unsigned int snd_ump_block_info_get_block_id(const snd_ump_block_info_t *info)
566 {
567 return info->block_id;
568 }
569
570 /**
571 * \brief set UMP block ID for query
572 * \param info pointer to a snd_ump_block_info_t structure
573 * \param id the ID number for query
574 */
snd_ump_block_info_set_block_id(snd_ump_block_info_t *info, unsigned int id)575 void snd_ump_block_info_set_block_id(snd_ump_block_info_t *info,
576 unsigned int id)
577 {
578 info->block_id = id;
579 }
580
581 /**
582 * \brief get UMP block activeness
583 * \param info pointer to a snd_ump_block_info_t structure
584 * \return 1 if the block is active or 0 if inactive
585 */
snd_ump_block_info_get_active(const snd_ump_block_info_t *info)586 unsigned int snd_ump_block_info_get_active(const snd_ump_block_info_t *info)
587 {
588 return info->active;
589 }
590
591 /**
592 * \brief get UMP block information flags
593 * \param info pointer to a snd_ump_block_info_t structure
594 * \return info flag bits for the given UMP block
595 */
snd_ump_block_info_get_flags(const snd_ump_block_info_t *info)596 unsigned int snd_ump_block_info_get_flags(const snd_ump_block_info_t *info)
597 {
598 return info->flags;
599 }
600
601 /**
602 * \brief get UMP block direction
603 * \param info pointer to a snd_ump_block_info_t structure
604 * \return direction of UMP block (input,output,bidirectional)
605 */
snd_ump_block_info_get_direction(const snd_ump_block_info_t *info)606 unsigned int snd_ump_block_info_get_direction(const snd_ump_block_info_t *info)
607 {
608 return info->direction;
609 }
610
611 /**
612 * \brief get first UMP group ID belonging to the block
613 * \param info pointer to a snd_ump_block_info_t structure
614 * \return the first UMP group ID belonging to the block
615 */
snd_ump_block_info_get_first_group(const snd_ump_block_info_t *info)616 unsigned int snd_ump_block_info_get_first_group(const snd_ump_block_info_t *info)
617 {
618 return info->first_group;
619 }
620
621 /**
622 * \brief get number of UMP groups belonging to the block
623 * \param info pointer to a snd_ump_block_info_t structure
624 * \return the number of UMP groups belonging to the block
625 */
snd_ump_block_info_get_num_groups(const snd_ump_block_info_t *info)626 unsigned int snd_ump_block_info_get_num_groups(const snd_ump_block_info_t *info)
627 {
628 return info->num_groups;
629 }
630
631 /**
632 * \brief get MIDI-CI version number
633 * \param info pointer to a snd_ump_block_info_t structure
634 * \return MIDI-CI version number
635 */
snd_ump_block_info_get_midi_ci_version(const snd_ump_block_info_t *info)636 unsigned int snd_ump_block_info_get_midi_ci_version(const snd_ump_block_info_t *info)
637 {
638 return info->midi_ci_version;
639 }
640
641 /**
642 * \brief get number of supported SysEx8 streams
643 * \param info pointer to a snd_ump_block_info_t structure
644 * \return number of supported SysEx8 streams
645 */
snd_ump_block_info_get_sysex8_streams(const snd_ump_block_info_t *info)646 unsigned int snd_ump_block_info_get_sysex8_streams(const snd_ump_block_info_t *info)
647 {
648 return info->sysex8_streams;
649 }
650
651 /**
652 * \brief get UI hint of the given UMP block
653 * \param info pointer to a snd_ump_block_info_t structure
654 * \return the hint bits
655 */
snd_ump_block_info_get_ui_hint(const snd_ump_block_info_t *info)656 unsigned int snd_ump_block_info_get_ui_hint(const snd_ump_block_info_t *info)
657 {
658 return info->ui_hint;
659 }
660
661 /**
662 * \brief get the name string of UMP block
663 * \param info pointer to a snd_ump_block_info_t structure
664 * \return the name string of UMP block
665 */
snd_ump_block_info_get_name(const snd_ump_block_info_t *info)666 const char *snd_ump_block_info_get_name(const snd_ump_block_info_t *info)
667 {
668 return (const char *)info->name;
669 }
670
671 /**
672 * \brief get UMP block information
673 * \param ump UMP handle
674 * \param info pointer to a snd_ump_block_info_t structure
675 * \return 0 on success otherwise a negative error code
676 *
677 * The caller should fill the block ID to query at first via
678 * snd_ump_block_info_set_block_id().
679 */
snd_ump_block_info(snd_ump_t *ump, snd_ump_block_info_t *info)680 int snd_ump_block_info(snd_ump_t *ump, snd_ump_block_info_t *info)
681 {
682 return _snd_rawmidi_ump_block_info(ump->rawmidi, info);
683 }
684
685 /*
686 * UMP sysex helpers
687 */
expand_sysex_data(const uint32_t *data, uint8_t *buf, size_t maxlen, unsigned char bytes, int offset)688 static int expand_sysex_data(const uint32_t *data, uint8_t *buf,
689 size_t maxlen, unsigned char bytes, int offset)
690 {
691 int size = 0;
692
693 for (; bytes; bytes--, size++) {
694 if (!maxlen)
695 break;
696 buf[size] = (*data >> offset) & 0x7f;
697 if (!offset) {
698 offset = 24;
699 data++;
700 } else {
701 offset -= 8;
702 }
703 }
704
705 return size;
706 }
707
expand_sysex7(const uint32_t *ump, uint8_t *buf, size_t maxlen, size_t *filled)708 static int expand_sysex7(const uint32_t *ump, uint8_t *buf, size_t maxlen,
709 size_t *filled)
710 {
711 unsigned char status;
712 unsigned char bytes;
713
714 *filled = 0;
715 if (!maxlen)
716 return 0;
717
718 status = snd_ump_sysex_msg_status(ump);
719 bytes = snd_ump_sysex_msg_length(ump);
720 if (bytes > 6)
721 return 0; // invalid - skip
722
723 *filled = expand_sysex_data(ump, buf, maxlen, bytes, 8);
724 return (status == SND_UMP_SYSEX_STATUS_SINGLE ||
725 status == SND_UMP_SYSEX_STATUS_END);
726 }
727
expand_sysex8(const uint32_t *ump, uint8_t *buf, size_t maxlen, size_t *filled)728 static int expand_sysex8(const uint32_t *ump, uint8_t *buf, size_t maxlen,
729 size_t *filled)
730 {
731 unsigned char status;
732 unsigned char bytes;
733
734 *filled = 0;
735 if (!maxlen)
736 return 0;
737
738 status = snd_ump_sysex_msg_status(ump);
739 if (status > SND_UMP_SYSEX_STATUS_END)
740 return 0; // unsupported, skip
741 bytes = snd_ump_sysex_msg_length(ump);
742 if (!bytes || bytes > 14)
743 return 0; // skip
744
745 *filled = expand_sysex_data(ump, buf, maxlen, bytes - 1, 0);
746 return (status == SND_UMP_SYSEX_STATUS_SINGLE ||
747 status == SND_UMP_SYSEX_STATUS_END);
748 }
749
750 /**
751 * \brief fill sysex byte from a UMP packet
752 * \param ump UMP packet pointer
753 * \param buf buffer point to fill sysex bytes
754 * \param maxlen max buffer size in bytes
755 * \param filled the size of filled sysex bytes on the buffer
756 * \return 1 if the sysex finished, otherwise 0
757 */
snd_ump_msg_sysex_expand(const uint32_t *ump, uint8_t *buf, size_t maxlen, size_t *filled)758 int snd_ump_msg_sysex_expand(const uint32_t *ump, uint8_t *buf, size_t maxlen,
759 size_t *filled)
760 {
761 switch (snd_ump_msg_type(ump)) {
762 case SND_UMP_MSG_TYPE_DATA:
763 return expand_sysex7(ump, buf, maxlen, filled);
764 case SND_UMP_MSG_TYPE_EXTENDED_DATA:
765 return expand_sysex8(ump, buf, maxlen, filled);
766 default:
767 return -EINVAL;
768 }
769 }
770