ump: Add helpers for handling SysEx data

Yet a few more helpers for handling SysEx data with UMP packets.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
Takashi Iwai 2022-11-29 16:42:45 +01:00
parent 040356ecf0
commit e80ee6ae75
2 changed files with 113 additions and 0 deletions

View 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

View 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;
}
}