]> git.alsa-project.org Git - alsa-lib.git/commitdiff
ump: Add helpers for handling SysEx data
authorTakashi Iwai <tiwai@suse.de>
Tue, 29 Nov 2022 15:42:45 +0000 (16:42 +0100)
committerTakashi Iwai <tiwai@suse.de>
Tue, 6 Jun 2023 13:13:27 +0000 (15:13 +0200)
Yet a few more helpers for handling SysEx data with UMP packets.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
include/ump_msg.h
src/rawmidi/ump.c

index 1b7f706670547936218e2181f41793c1ab145a5a..4ccce546f8d5ac7f66f4ca3fd8918bcf232d7272 100644 (file)
@@ -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
index 5da79459f6185a867cc7c5e5c3218d9488f0fdfc..2482884f2661f3dc78683636cf0ef628261a7b5d 100644 (file)
@@ -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;
+       }
+}