@@ -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
@@ -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;
+ }
+}
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(+)