Yet a few more helpers for handling SysEx data with UMP packets.
Signed-off-by: Takashi Iwai tiwai@suse.de --- include/ump_msg.h | 27 +++++++++++++++ src/rawmidi/ump.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+)
diff --git a/include/ump_msg.h b/include/ump_msg.h index 1b7f70667054..4ccce546f8d5 100644 --- a/include/ump_msg.h +++ b/include/ump_msg.h @@ -500,6 +500,14 @@ enum { SND_UMP_MSG_RESET = 0xff, };
+/** MIDI 2.0 SysEx / Data Status; same values for both 7-bit and 8-bit SysEx */ +enum { + SND_UMP_SYSEX_STATUS_SINGLE = 0, + SND_UMP_SYSEX_STATUS_START = 1, + SND_UMP_SYSEX_STATUS_CONTINUE = 2, + SND_UMP_SYSEX_STATUS_END = 3, +}; + /** * \brief get UMP status (4bit) from 32bit UMP message header */ @@ -564,6 +572,25 @@ static inline uint8_t snd_ump_msg_group(const uint32_t *ump) return snd_ump_msg_hdr_group(*ump); }
+/** + * \brief get UMP sysex message status + */ +static inline uint8_t snd_ump_sysex_msg_status(const uint32_t *ump) +{ + return (*ump >> 20) & 0xf; +} + +/** + * \brief get UMP sysex message length + */ +static inline uint8_t snd_ump_sysex_msg_length(const uint32_t *ump) +{ + return (*ump >> 16) & 0xf; +} + +int snd_ump_msg_sysex_expand(const uint32_t *ump, uint8_t *buf, size_t maxlen, + size_t *filled); + #ifdef __cplusplus } #endif diff --git a/src/rawmidi/ump.c b/src/rawmidi/ump.c index 5da79459f618..2482884f2661 100644 --- a/src/rawmidi/ump.c +++ b/src/rawmidi/ump.c @@ -614,3 +614,89 @@ int snd_ump_block_info(snd_ump_t *ump, snd_ump_block_info_t *info) { return _snd_rawmidi_ump_block_info(ump->rawmidi, info); } + +/* + * UMP sysex helpers + */ +static int expand_sysex_data(const uint32_t *data, uint8_t *buf, + size_t maxlen, unsigned char bytes, int offset) +{ + int size = 0; + + for (; bytes; bytes--, size++) { + if (!maxlen) + break; + buf[size] = (*data >> offset) & 0x7f; + if (!offset) { + offset = 24; + data++; + } else { + offset -= 8; + } + } + + return size; +} + +static int expand_sysex7(const uint32_t *ump, uint8_t *buf, size_t maxlen, + size_t *filled) +{ + unsigned char status; + unsigned char bytes; + + *filled = 0; + if (!maxlen) + return 0; + + status = snd_ump_sysex_msg_status(ump); + bytes = snd_ump_sysex_msg_length(ump); + if (bytes > 6) + return 0; // invalid - skip + + *filled = expand_sysex_data(ump, buf, maxlen, bytes, 8); + return (status == SND_UMP_SYSEX_STATUS_SINGLE || + status == SND_UMP_SYSEX_STATUS_END); +} + +static int expand_sysex8(const uint32_t *ump, uint8_t *buf, size_t maxlen, + size_t *filled) +{ + unsigned char status; + unsigned char bytes; + + *filled = 0; + if (!maxlen) + return 0; + + status = snd_ump_sysex_msg_status(ump); + if (status > SND_UMP_SYSEX_STATUS_END) + return 0; // unsupported, skip + bytes = snd_ump_sysex_msg_length(ump); + if (!bytes || bytes > 14) + return 0; // skip + + *filled = expand_sysex_data(ump, buf, maxlen, bytes - 1, 0); + return (status == SND_UMP_SYSEX_STATUS_SINGLE || + status == SND_UMP_SYSEX_STATUS_END); +} + +/** + * \brief fill sysex byte from a UMP packet + * \param ump UMP packet pointer + * \param buf buffer point to fill sysex bytes + * \param maxlen max buffer size in bytes + * \param filled the size of filled sysex bytes on the buffer + * \return 1 if the sysex finished, otherwise 0 + */ +int snd_ump_msg_sysex_expand(const uint32_t *ump, uint8_t *buf, size_t maxlen, + size_t *filled) +{ + switch (snd_ump_msg_type(ump)) { + case SND_UMP_MSG_TYPE_DATA: + return expand_sysex7(ump, buf, maxlen, filled); + case SND_UMP_MSG_TYPE_EXTENDED_DATA: + return expand_sysex8(ump, buf, maxlen, filled); + default: + return -EINVAL; + } +}