* [PATCH alsa-lib 1/4] ump: Add missing *_set variants for snd_ump_endpoint_info and snd_ump_block_info
2024-06-19 15:28 [PATCH alsa-lib 0/4] Add API helper functions for creating UMP Endpoint and Blocks Takashi Iwai
@ 2024-06-19 15:28 ` Takashi Iwai
2024-06-19 15:28 ` [PATCH alsa-lib 2/4] seq: Add API helper functions for creating UMP Endpoint and Blocks Takashi Iwai
` (2 subsequent siblings)
3 siblings, 0 replies; 9+ messages in thread
From: Takashi Iwai @ 2024-06-19 15:28 UTC (permalink / raw)
To: alsa-devel
The API functions to fill the data on snd_ump_endpoint_info and
snd_ump_block_info were missing. Let's add them.
They can be used to construct a virtual UMP endpoint and block.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
include/ump.h | 30 ++++-
src/rawmidi/ump.c | 304 ++++++++++++++++++++++++++++++++++++++++++++--
2 files changed, 322 insertions(+), 12 deletions(-)
diff --git a/include/ump.h b/include/ump.h
index 1e5e053454b3..45b3ad270db7 100644
--- a/include/ump.h
+++ b/include/ump.h
@@ -77,6 +77,7 @@ size_t snd_ump_endpoint_info_sizeof(void);
#define snd_ump_endpoint_info_alloca(ptr) __snd_alloca(ptr, snd_ump_endpoint_info)
int snd_ump_endpoint_info_malloc(snd_ump_endpoint_info_t **info);
void snd_ump_endpoint_info_free(snd_ump_endpoint_info_t *info);
+void snd_ump_endpoint_info_clear(snd_ump_endpoint_info_t *info);
void snd_ump_endpoint_info_copy(snd_ump_endpoint_info_t *dst, const snd_ump_endpoint_info_t *src);
int snd_ump_endpoint_info_get_card(const snd_ump_endpoint_info_t *info);
int snd_ump_endpoint_info_get_device(const snd_ump_endpoint_info_t *info);
@@ -93,6 +94,20 @@ const char *snd_ump_endpoint_info_get_name(const snd_ump_endpoint_info_t *info);
const char *snd_ump_endpoint_info_get_product_id(const snd_ump_endpoint_info_t *info);
int snd_ump_endpoint_info(snd_ump_t *ump, snd_ump_endpoint_info_t *info);
+void snd_ump_endpoint_info_set_card(snd_ump_endpoint_info_t *info, unsigned int card);
+void snd_ump_endpoint_info_set_device(snd_ump_endpoint_info_t *info, unsigned int device);
+void snd_ump_endpoint_info_set_flags(snd_ump_endpoint_info_t *info, unsigned int flags);
+void snd_ump_endpoint_info_set_protocol_caps(snd_ump_endpoint_info_t *info, unsigned int caps);
+void snd_ump_endpoint_info_set_protocol(snd_ump_endpoint_info_t *info, unsigned int protocols);
+void snd_ump_endpoint_info_set_num_blocks(snd_ump_endpoint_info_t *info, unsigned int num_blocks);
+void snd_ump_endpoint_info_set_version(snd_ump_endpoint_info_t *info, unsigned int version);
+void snd_ump_endpoint_info_set_manufacturer_id(snd_ump_endpoint_info_t *info, unsigned int id);
+void snd_ump_endpoint_info_set_family_id(snd_ump_endpoint_info_t *info, unsigned int id);
+void snd_ump_endpoint_info_set_model_id(snd_ump_endpoint_info_t *info, unsigned int id);
+void snd_ump_endpoint_info_set_sw_revision(snd_ump_endpoint_info_t *info, const unsigned char *id);
+void snd_ump_endpoint_info_set_name(snd_ump_endpoint_info_t *info, const char *name);
+void snd_ump_endpoint_info_set_product_id(snd_ump_endpoint_info_t *info, const char *id);
+
/** Bit flag for MIDI 1.0 port w/o restrict in UMP Block info flags */
#define SND_UMP_BLOCK_IS_MIDI1 (1U << 0)
/** Bit flag for 31.25Kbps B/W MIDI1 port in UMP Block info flags */
@@ -118,11 +133,11 @@ size_t snd_ump_block_info_sizeof(void);
#define snd_ump_block_info_alloca(ptr) __snd_alloca(ptr, snd_ump_block_info)
int snd_ump_block_info_malloc(snd_ump_block_info_t **info);
void snd_ump_block_info_free(snd_ump_block_info_t *info);
+void snd_ump_block_info_clear(snd_ump_block_info_t *info);
void snd_ump_block_info_copy(snd_ump_block_info_t *dst, const snd_ump_block_info_t *src);
int snd_ump_block_info_get_card(const snd_ump_block_info_t *info);
int snd_ump_block_info_get_device(const snd_ump_block_info_t *info);
unsigned int snd_ump_block_info_get_block_id(const snd_ump_block_info_t *info);
-void snd_ump_block_info_set_block_id(snd_ump_block_info_t *info, unsigned int id);
unsigned int snd_ump_block_info_get_active(const snd_ump_block_info_t *info);
unsigned int snd_ump_block_info_get_flags(const snd_ump_block_info_t *info);
unsigned int snd_ump_block_info_get_direction(const snd_ump_block_info_t *info);
@@ -134,6 +149,19 @@ unsigned int snd_ump_block_info_get_ui_hint(const snd_ump_block_info_t *info);
const char *snd_ump_block_info_get_name(const snd_ump_block_info_t *info);
int snd_ump_block_info(snd_ump_t *ump, snd_ump_block_info_t *info);
+void snd_ump_block_info_set_card(snd_ump_block_info_t *info, unsigned int card);
+void snd_ump_block_info_set_device(snd_ump_block_info_t *info, unsigned int device);
+void snd_ump_block_info_set_block_id(snd_ump_block_info_t *info, unsigned int id);
+void snd_ump_block_info_set_active(snd_ump_block_info_t *info, unsigned int active);
+void snd_ump_block_info_set_flags(snd_ump_block_info_t *info, unsigned int flags);
+void snd_ump_block_info_set_direction(snd_ump_block_info_t *info, unsigned int direction);
+void snd_ump_block_info_set_first_group(snd_ump_block_info_t *info, unsigned int first_group);
+void snd_ump_block_info_set_num_groups(snd_ump_block_info_t *info, unsigned int num_groups);
+void snd_ump_block_info_set_midi_ci_version(snd_ump_block_info_t *info, unsigned int version);
+void snd_ump_block_info_set_sysex8_streams(snd_ump_block_info_t *info, unsigned int streams);
+void snd_ump_block_info_set_ui_hint(snd_ump_block_info_t *info, unsigned int hint);
+void snd_ump_block_info_set_name(snd_ump_block_info_t *info, const char *name);
+
#ifdef __cplusplus
}
#endif
diff --git a/src/rawmidi/ump.c b/src/rawmidi/ump.c
index 39c1c4a91928..6c1097a7452b 100644
--- a/src/rawmidi/ump.c
+++ b/src/rawmidi/ump.c
@@ -337,6 +337,17 @@ void snd_ump_endpoint_info_free(snd_ump_endpoint_info_t *info)
free(info);
}
+/**
+ * \brief clears the snd_ump_endpoint_info_t structure
+ * \param info pointer to the snd_ump_endpoint_info_t structure to clear
+ *
+ * Zero-clear the snd_ump_endpoint_info_t object.
+ */
+void snd_ump_endpoint_info_clear(snd_ump_endpoint_info_t *info)
+{
+ memset(info, 0, sizeof(*info));
+}
+
/**
* \brief copy one snd_ump_endpoint_info_t structure to another
* \param dst destination snd_ump_endpoint_info_t structure
@@ -478,6 +489,149 @@ const char *snd_ump_endpoint_info_get_product_id(const snd_ump_endpoint_info_t *
return (const char *)info->product_id;
}
+/**
+ * \brief set card number of UMP endpoint
+ * \param info pointer to a snd_ump_endpoint_info_t structure
+ * \param card the card number of the given UMP endpoint
+ */
+void snd_ump_endpoint_info_set_card(snd_ump_endpoint_info_t *info,
+ unsigned int card)
+{
+ info->card = card;
+}
+
+/**
+ * \brief set device number of UMP endpoint
+ * \param info pointer to a snd_ump_endpoint_info_t structure
+ * \param device the device number of the given UMP endpoint
+ */
+void snd_ump_endpoint_info_set_device(snd_ump_endpoint_info_t *info,
+ unsigned int device)
+{
+ info->device = device;
+}
+
+/**
+ * \brief set info flags of UMP endpoint
+ * \param info pointer to a snd_ump_endpoint_info_t structure
+ * \param flags UMP endpoint flag bits
+ */
+void snd_ump_endpoint_info_set_flags(snd_ump_endpoint_info_t *info,
+ unsigned int flags)
+{
+ info->flags = flags;
+}
+
+/**
+ * \brief set protocol capability bits of UMP endpoint
+ * \param info pointer to a snd_ump_endpoint_info_t structure
+ * \param caps UMP endpoint protocol capability bits
+ */
+void snd_ump_endpoint_info_set_protocol_caps(snd_ump_endpoint_info_t *info,
+ unsigned int caps)
+{
+ info->protocol_caps = caps;
+}
+
+/**
+ * \brief set the current protocol of UMP endpoint
+ * \param info pointer to a snd_ump_endpoint_info_t structure
+ * \param caps the UMP endpoint protocol bits
+ */
+void snd_ump_endpoint_info_set_protocol(snd_ump_endpoint_info_t *info,
+ unsigned int protocol)
+{
+ info->protocol = protocol;
+}
+
+/**
+ * \brief set the number of UMP blocks of UMP endpoint
+ * \param info pointer to a snd_ump_endpoint_info_t structure
+ * \param blocks the number of UMP blocks
+ */
+void snd_ump_endpoint_info_set_num_blocks(snd_ump_endpoint_info_t *info,
+ unsigned int blocks)
+{
+ info->num_blocks = blocks;
+}
+
+/**
+ * \brief set the UMP version number of UMP endpoint
+ * \param info pointer to a snd_ump_endpoint_info_t structure
+ * \param version the UMP version number
+ */
+void snd_ump_endpoint_info_set_version(snd_ump_endpoint_info_t *info,
+ unsigned int version)
+{
+ info->version = version;
+}
+
+/**
+ * \brief set the UMP manufacturer ID of UMP endpoint
+ * \param info pointer to a snd_ump_endpoint_info_t structure
+ * \param id UMP manufacturer ID
+ */
+void snd_ump_endpoint_info_set_manufacturer_id(snd_ump_endpoint_info_t *info,
+ unsigned int id)
+{
+ info->manufacturer_id = id;
+}
+
+/**
+ * \brief set the UMP family ID of UMP endpoint
+ * \param info pointer to a snd_ump_endpoint_info_t structure
+ * \param id UMP family ID
+ */
+void snd_ump_endpoint_info_set_family_id(snd_ump_endpoint_info_t *info,
+ unsigned int id)
+{
+ info->family_id = id;
+}
+
+/**
+ * \brief set the UMP model ID of UMP endpoint
+ * \param info pointer to a snd_ump_endpoint_info_t structure
+ * \param id UMP model ID
+ */
+void snd_ump_endpoint_info_set_model_id(snd_ump_endpoint_info_t *info,
+ unsigned int id)
+{
+ info->model_id = id;
+}
+
+/**
+ * \brief set the UMP software revision of UMP endpoint
+ * \param info pointer to a snd_ump_endpoint_info_t structure
+ * \param id UMP software revision in 4 bytes array
+ */
+void snd_ump_endpoint_info_set_sw_revision(snd_ump_endpoint_info_t *info,
+ const unsigned char *id)
+{
+ memcpy(info->sw_revision, id, sizeof(info->sw_revision));
+}
+
+/**
+ * \brief set the name of UMP endpoint
+ * \param info pointer to a snd_ump_endpoint_info_t structure
+ * \param name UMP endpoint name string
+ */
+void snd_ump_endpoint_info_set_name(snd_ump_endpoint_info_t *info,
+ const char *name)
+{
+ snd_strlcpy((char *)info->name, name, sizeof(info->name));
+}
+
+/**
+ * \brief set the product ID string of UMP endpoint
+ * \param info pointer to a snd_ump_endpoint_info_t structure
+ * \param id UMP endpoint product ID string
+ */
+void snd_ump_endpoint_info_set_product_id(snd_ump_endpoint_info_t *info,
+ const char *id)
+{
+ snd_strlcpy((char *)info->product_id, id, sizeof(info->product_id));
+}
+
/**
* \brief get endpoint information about UMP handle
* \param ump UMP handle
@@ -526,6 +680,17 @@ void snd_ump_block_info_free(snd_ump_block_info_t *info)
free(info);
}
+/**
+ * \brief clears the snd_ump_block_info_t structure
+ * \param info pointer to the snd_ump_block_info_t structure to clear
+ *
+ * Zero-clear the snd_ump_block_info_t object.
+ */
+void snd_ump_block_info_clear(snd_ump_block_info_t *info)
+{
+ memset(info, 0, sizeof(*info));
+}
+
/**
* \brief copy one snd_ump_block_info_t structure to another
* \param dst destination snd_ump_block_info_t structure
@@ -567,17 +732,6 @@ unsigned int snd_ump_block_info_get_block_id(const snd_ump_block_info_t *info)
return info->block_id;
}
-/**
- * \brief set UMP block ID for query
- * \param info pointer to a snd_ump_block_info_t structure
- * \param id the ID number for query
- */
-void snd_ump_block_info_set_block_id(snd_ump_block_info_t *info,
- unsigned int id)
-{
- info->block_id = id;
-}
-
/**
* \brief get UMP block activeness
* \param info pointer to a snd_ump_block_info_t structure
@@ -668,6 +822,134 @@ const char *snd_ump_block_info_get_name(const snd_ump_block_info_t *info)
return (const char *)info->name;
}
+/**
+ * \brief set card number to snd_ump_block_info_t structure
+ * \param info pointer to a snd_ump_block_info_t structure
+ * \param card the card number
+ */
+void snd_ump_block_info_set_card(snd_ump_block_info_t *info, unsigned int card)
+{
+ info->card = card;
+}
+
+/**
+ * \brief set device number to snd_ump_block_info_t structure
+ * \param info pointer to a snd_ump_block_info_t structure
+ * \param device the device number
+ */
+void snd_ump_block_info_set_device(snd_ump_block_info_t *info, unsigned int device)
+{
+ info->device = device;
+}
+
+/**
+ * \brief set UMP block ID to snd_ump_block_info_t structure
+ * \param info pointer to a snd_ump_block_info_t structure
+ * \param id the ID number
+ *
+ * This function is mostly used for setting the block ID to query.
+ */
+void snd_ump_block_info_set_block_id(snd_ump_block_info_t *info,
+ unsigned int id)
+{
+ info->block_id = id;
+}
+
+/**
+ * \brief set activeness to snd_ump_block_info_t structure
+ * \param info pointer to a snd_ump_block_info_t structure
+ * \param active 1 if the block is active or 0 if inactive
+ */
+void snd_ump_block_info_set_active(snd_ump_block_info_t *info, unsigned int active)
+{
+ info->active = !!active;
+}
+
+/**
+ * \brief set UMP block information flags to snd_ump_block_info_t structure
+ * \param info pointer to a snd_ump_block_info_t structure
+ * \param flags flag bits for the given UMP block
+ */
+void snd_ump_block_info_set_flags(snd_ump_block_info_t *info, unsigned int flags)
+{
+ info->flags = flags;
+}
+
+/**
+ * \brief set UMP block direction to snd_ump_block_info_t structure
+ * \param info pointer to a snd_ump_block_info_t structure
+ * \param direction direction of UMP block (input,output,bidirectional)
+ */
+void snd_ump_block_info_set_direction(snd_ump_block_info_t *info, unsigned int direction)
+{
+ info->direction = direction;
+}
+
+/**
+ * \brief set first UMP group to snd_ump_block_info_t structure
+ * \param info pointer to a snd_ump_block_info_t structure
+ * \param first_group the first UMP group ID belonging to the block
+ */
+void snd_ump_block_info_set_first_group(snd_ump_block_info_t *info,
+ unsigned int first_group)
+{
+ info->first_group = first_group;
+}
+
+/**
+ * \brief set number of UMP groups to snd_ump_block_info_t structure
+ * \param info pointer to a snd_ump_block_info_t structure
+ * \param num_groups the number of UMP groups belonging to the block
+ */
+void snd_ump_block_info_set_num_groups(snd_ump_block_info_t *info,
+ unsigned int num_groups)
+{
+ info->num_groups = num_groups;
+}
+
+/**
+ * \brief set MIDI-CI version number to snd_ump_block_info_t structure
+ * \param info pointer to a snd_ump_block_info_t structure
+ * \param version MIDI-CI version number
+ */
+void snd_ump_block_info_set_midi_ci_version(snd_ump_block_info_t *info,
+ unsigned int version)
+{
+ info->midi_ci_version = version;
+}
+
+/**
+ * \brief set number of supported SysEx8 streams to snd_ump_block_info_t structure
+ * \param info pointer to a snd_ump_block_info_t structure
+ * \param streams number of supported SysEx8 streams
+ */
+void snd_ump_block_info_set_sysex8_streams(snd_ump_block_info_t *info,
+ unsigned int streams)
+{
+ info->sysex8_streams = streams;
+}
+
+/**
+ * \brief set UI Hint to snd_ump_block_info_t structure
+ * \param info pointer to a snd_ump_block_info_t structure
+ * \param hint the hint bits
+ */
+void snd_ump_block_info_set_ui_hint(snd_ump_block_info_t *info, unsigned int hint)
+{
+ info->ui_hint = hint;
+}
+
+/**
+ * \brief set the name string to snd_ump_block_info_t structure
+ * \param info pointer to a snd_ump_block_info_t structure
+ * \param name the name string of UMP block
+ */
+void snd_ump_block_info_set_name(snd_ump_block_info_t *info,
+ const char *name)
+{
+ snd_strlcpy((char *)info->name, name, sizeof(info->name));
+}
+
/**
* \brief get UMP block information
* \param ump UMP handle
--
2.43.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH alsa-lib 2/4] seq: Add API helper functions for creating UMP Endpoint and Blocks
2024-06-19 15:28 [PATCH alsa-lib 0/4] Add API helper functions for creating UMP Endpoint and Blocks Takashi Iwai
2024-06-19 15:28 ` [PATCH alsa-lib 1/4] ump: Add missing *_set variants for snd_ump_endpoint_info and snd_ump_block_info Takashi Iwai
@ 2024-06-19 15:28 ` Takashi Iwai
2024-07-31 8:46 ` Amadeusz Sławiński
2024-06-19 15:28 ` [PATCH alsa-lib 3/4] test: Add an example program to create a virtual UMP Endpoint Takashi Iwai
2024-06-19 15:28 ` [PATCH alsa-lib 4/4] Add test/seq-ump-example to .gitignore Takashi Iwai
3 siblings, 1 reply; 9+ messages in thread
From: Takashi Iwai @ 2024-06-19 15:28 UTC (permalink / raw)
To: alsa-devel
For making it easer for applications to create a virtual UMP Endpoint
and UMP blocks, add two API helper functions.
snd_seq_create_ump_endpoint() creates (unsurprisingly) a UMP Endpoint,
based on the given snd_ump_endpoint_info_t information. The number of
(max) UMP groups belonging to this Endpoint has to be specified.
This function sets up the Endpoint info on the sequencer client, and
creates a MIDI 2.0 UMP port as well as UMP Group ports automatically.
The name of the sequencer client is updated from the Endpoint name,
too.
After creating a UMP Endpoint, create each UMP Block via
snd_seq_create_ump_block() function with a snd_ump_block_info_t info.
The associated groups for each block have to be specified there.
The port names and capability bits are updated accordingly after
setting each block information.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
include/seqmid.h | 7 ++
include/ump.h | 6 ++
src/seq/seq.c | 6 +-
src/seq/seq_local.h | 4 +
src/seq/seqmid.c | 249 ++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 271 insertions(+), 1 deletion(-)
diff --git a/include/seqmid.h b/include/seqmid.h
index 4464c2d3af0b..bf968a5b2c7b 100644
--- a/include/seqmid.h
+++ b/include/seqmid.h
@@ -520,6 +520,13 @@ int snd_seq_reset_pool_input(snd_seq_t *seq);
((ev)->type = SND_SEQ_EVENT_SYSEX,\
snd_seq_ev_set_variable(ev, datalen, dataptr))
+/* Helper API functions for UMP endpoint and block creations */
+int snd_seq_create_ump_endpoint(snd_seq_t *seq,
+ const snd_ump_endpoint_info_t *info,
+ unsigned int num_groups);
+int snd_seq_create_ump_block(snd_seq_t *seq, int blkid,
+ const snd_ump_block_info_t *info);
+
/** \} */
#ifdef __cplusplus
diff --git a/include/ump.h b/include/ump.h
index 45b3ad270db7..01363a329fa7 100644
--- a/include/ump.h
+++ b/include/ump.h
@@ -69,6 +69,9 @@ enum _snd_ump_direction {
/** Bit flag for JRTS in Receive */
#define SND_UMP_EP_INFO_PROTO_JRTS_RX 0x0002
+/** Default version passed to UMP Endpoint info */
+#define SND_UMP_EP_INFO_DEFAULT_VERSION 0x0101
+
size_t snd_ump_endpoint_info_sizeof(void);
/** \hideinitializer
* \brief allocate an invalid #snd_ump_endpoint_info_t using standard alloca
@@ -125,6 +128,9 @@ enum _snd_ump_block_ui_hint {
SND_UMP_BLOCK_UI_HINT_BOTH = 0x03,
};
+/** Default MIDI CI version passed to UMP Block info */
+#define SND_UMP_BLOCK_INFO_DEFAULT_MIDI_CI_VERSION 0x01
+
size_t snd_ump_block_info_sizeof(void);
/** \hideinitializer
* \brief allocate an invalid #snd_ump_block_info_t using standard alloca
diff --git a/src/seq/seq.c b/src/seq/seq.c
index 5eac4848b9c7..ff0468140177 100644
--- a/src/seq/seq.c
+++ b/src/seq/seq.c
@@ -1042,7 +1042,8 @@ int _snd_seq_open_lconf(snd_seq_t **seqp, const char *name,
*/
int snd_seq_close(snd_seq_t *seq)
{
- int err;
+ int i, err;
+
assert(seq);
err = seq->ops->close(seq);
if (seq->dl_handle)
@@ -1051,6 +1052,9 @@ int snd_seq_close(snd_seq_t *seq)
free(seq->ibuf);
free(seq->tmpbuf);
free(seq->name);
+ free(seq->ump_ep);
+ for (i = 0; i < 16; i++)
+ free(seq->ump_blks[i]);
free(seq);
return err;
}
diff --git a/src/seq/seq_local.h b/src/seq/seq_local.h
index 468248062638..263029702739 100644
--- a/src/seq/seq_local.h
+++ b/src/seq/seq_local.h
@@ -94,6 +94,10 @@ struct _snd_seq {
size_t tmpbufsize; /* size of errbuf */
size_t packet_size; /* input packet alignment size */
int midi_version; /* current protocol version */
+
+ unsigned int num_ump_groups; /* number of UMP groups */
+ snd_ump_endpoint_info_t *ump_ep; /* optional UMP info */
+ snd_ump_block_info_t *ump_blks[16]; /* optional UMP block info */
};
int snd_seq_hw_open(snd_seq_t **handle, const char *name, int streams, int mode);
diff --git a/src/seq/seqmid.c b/src/seq/seqmid.c
index 9ec93ee8ade1..d7eac6cafa0e 100644
--- a/src/seq/seqmid.c
+++ b/src/seq/seqmid.c
@@ -493,3 +493,252 @@ int snd_seq_parse_address(snd_seq_t *seq, snd_seq_addr_t *addr, const char *arg)
return 0;
}
+/**
+ * \brief create a UMP Endpoint for the given sequencer client
+ * \param seq sequencer handle
+ * \param info UMP Endpoint information to initialize
+ * \param num_groups max number of groups in the endpoint
+ * \return 0 on success or negative error code
+ *
+ * This function initializes the sequencer client to the corresponding
+ * MIDI 2.0 mode (either MIDI 1.0 or MIDI 2.0 protocol) depending on the
+ * given snd_ump_endpoint_info_t info.
+ *
+ * This function should be called right after opening a sequencer client.
+ * The client name is updated from the UMP Endpoint name, and a primary
+ * MIDI 2.0 UMP port and each UMP Group port are created.
+ * The application should pass each UMP block info via succeeding
+ * snd_seq_create_ump_block() call.
+ */
+int snd_seq_create_ump_endpoint(snd_seq_t *seq,
+ const snd_ump_endpoint_info_t *info,
+ unsigned int num_groups)
+{
+ int err, version;
+ unsigned int i;
+ snd_seq_port_info_t *pinfo;
+
+ if (seq->ump_ep)
+ return -EBUSY;
+
+ if (num_groups < 1 || num_groups > SND_UMP_MAX_GROUPS)
+ return -EINVAL;
+
+ if (!(info->protocol_caps & info->protocol)) {
+ SNDERR("Inconsistent UMP protocol_caps and protocol\n");
+ return -EINVAL;
+ }
+
+ if (info->protocol & SND_UMP_EP_INFO_PROTO_MIDI2) {
+ version = SND_SEQ_CLIENT_UMP_MIDI_2_0;
+ } else if (info->protocol & SND_UMP_EP_INFO_PROTO_MIDI1) {
+ version = SND_SEQ_CLIENT_UMP_MIDI_1_0;
+ } else {
+ SNDERR("Invalid UMP protocol set 0x%x\n", info->protocol);
+ return -EINVAL;
+ }
+
+ err = snd_seq_set_client_midi_version(seq, version);
+ if (err < 0) {
+ SNDERR("Failed to set to MIDI protocol 0x%x\n", version);
+ return err;
+ }
+
+ seq->ump_ep = malloc(sizeof(*info));
+ if (!seq->ump_ep)
+ return -ENOMEM;
+
+ *seq->ump_ep = *info;
+ if (!seq->ump_ep->version)
+ seq->ump_ep->version = SND_UMP_EP_INFO_DEFAULT_VERSION;
+
+ if (info->name) {
+ err = snd_seq_set_client_name(seq, (const char *)info->name);
+ if (err < 0)
+ goto error_free;
+ }
+
+ err = snd_seq_set_ump_endpoint_info(seq, seq->ump_ep);
+ if (err < 0) {
+ SNDERR("Failed to set UMP EP info\n");
+ goto error_free;
+ }
+
+ snd_seq_port_info_alloca(&pinfo);
+
+ snd_seq_port_info_set_port(pinfo, 0);
+ snd_seq_port_info_set_port_specified(pinfo, 1);
+ snd_seq_port_info_set_name(pinfo, "MIDI 2.0");
+ snd_seq_port_info_set_capability(pinfo,
+ SNDRV_SEQ_PORT_CAP_READ |
+ SNDRV_SEQ_PORT_CAP_SYNC_READ |
+ SNDRV_SEQ_PORT_CAP_SUBS_READ |
+ SNDRV_SEQ_PORT_CAP_WRITE |
+ SNDRV_SEQ_PORT_CAP_SYNC_WRITE |
+ SNDRV_SEQ_PORT_CAP_SUBS_WRITE |
+ SNDRV_SEQ_PORT_CAP_DUPLEX);
+ snd_seq_port_info_set_type(pinfo,
+ SND_SEQ_PORT_TYPE_MIDI_GENERIC |
+ SNDRV_SEQ_PORT_TYPE_MIDI_UMP |
+ SND_SEQ_PORT_TYPE_APPLICATION |
+ SNDRV_SEQ_PORT_TYPE_PORT);
+ snd_seq_port_info_set_ump_group(pinfo,
+ SND_SEQ_PORT_TYPE_MIDI_GENERIC |
+ SNDRV_SEQ_PORT_TYPE_MIDI_UMP |
+ SND_SEQ_PORT_TYPE_APPLICATION |
+ SNDRV_SEQ_PORT_TYPE_PORT);
+ err = snd_seq_create_port(seq, pinfo);
+ if (err < 0) {
+ SNDERR("Failed to create MIDI 2.0 port\n");
+ goto error_free;
+ }
+
+ for (i = 0; i < num_groups; i++) {
+ char name[32];
+
+ snd_seq_port_info_set_port(pinfo, i + 1);
+ snd_seq_port_info_set_port_specified(pinfo, 1);
+ sprintf(name, "Group %d", i + 1);
+ snd_seq_port_info_set_capability(pinfo, 0); /* set later */
+ snd_seq_port_info_set_name(pinfo, name);
+ snd_seq_port_info_set_ump_group(pinfo, i + 1);
+ err = snd_seq_create_port(seq, pinfo);
+ if (err < 0) {
+ SNDERR("Failed to create Group port %d\n", i + 1);
+ goto error;
+ }
+ }
+
+ seq->num_ump_groups = num_groups;
+ return 0;
+
+ error:
+ /* delete all ports including port 0 */
+ for (i = 0; i <= num_groups; i++)
+ snd_seq_delete_port(seq, i);
+ error_free:
+ free(seq->ump_ep);
+ seq->ump_ep = NULL;
+ return err;
+}
+
+/* update each port name and capability from the block list */
+static void update_group_ports(snd_seq_t *seq, snd_ump_endpoint_info_t *ep)
+{
+ unsigned int i, b;
+ snd_seq_port_info_t *pinfo;
+ snd_ump_block_info_t *bp;
+
+ snd_seq_port_info_alloca(&pinfo);
+
+ for (i = 0; i < seq->num_ump_groups; i++) {
+ char blknames[64];
+ char name[64];
+ unsigned int caps = 0;
+
+ blknames[0] = 0;
+ for (b = 0; b < ep->num_blocks; b++) {
+ bp = seq->ump_blks[b];
+ if (!bp)
+ continue;
+ if (i < bp->first_group ||
+ i >= bp->first_group + bp->num_groups)
+ continue;
+ switch (bp->direction) {
+ case SNDRV_UMP_DIR_INPUT:
+ caps |= SNDRV_SEQ_PORT_CAP_READ |
+ SNDRV_SEQ_PORT_CAP_SYNC_READ |
+ SNDRV_SEQ_PORT_CAP_SUBS_READ;
+ break;
+ case SNDRV_UMP_DIR_OUTPUT:
+ caps |= SNDRV_SEQ_PORT_CAP_WRITE |
+ SNDRV_SEQ_PORT_CAP_SYNC_WRITE |
+ SNDRV_SEQ_PORT_CAP_SUBS_WRITE;
+ break;
+ case SNDRV_UMP_DIR_BIDIRECTION:
+ caps |= SNDRV_SEQ_PORT_CAP_READ |
+ SNDRV_SEQ_PORT_CAP_SYNC_READ |
+ SNDRV_SEQ_PORT_CAP_SUBS_READ |
+ SNDRV_SEQ_PORT_CAP_WRITE |
+ SNDRV_SEQ_PORT_CAP_SYNC_WRITE |
+ SNDRV_SEQ_PORT_CAP_SUBS_WRITE |
+ SNDRV_SEQ_PORT_CAP_DUPLEX;
+ break;
+ }
+
+ if (!*bp->name)
+ continue;
+ if (*blknames) {
+ strlcat(blknames, ", ", sizeof(blknames));
+ strlcat(blknames, (const char *)bp->name,
+ sizeof(blknames));
+ } else {
+ snd_strlcpy(blknames, (const char *)bp->name,
+ sizeof(blknames));
+ }
+ }
+
+ if (!*blknames)
+ continue;
+
+ snprintf(name, sizeof(name), "Group %d (%s)", i + 1, blknames);
+ if (snd_seq_get_port_info(seq, i + 1, pinfo) < 0)
+ continue;
+
+ if (strcmp(name, snd_seq_port_info_get_name(pinfo)) ||
+ snd_seq_port_info_get_capability(pinfo) != caps) {
+ snd_seq_port_info_set_name(pinfo, name);
+ snd_seq_port_info_set_capability(pinfo, caps);
+ snd_seq_set_port_info(seq, i + 1, pinfo);
+ }
+ }
+}
+
+/**
+ * \brief create a UMP block for the given sequencer client
+ * \param seq sequencer handle
+ * \param blkid 0-based block id
+ * \param info UMP block info to initialize
+ * \return 0 on success or negative error code
+ *
+ * This function sets up the UMP block info of the given block id.
+ * The sequencer port name is updated accordingly with the associated
+ * block name automatically.
+ */
+int snd_seq_create_ump_block(snd_seq_t *seq, int blkid,
+ const snd_ump_block_info_t *info)
+{
+ snd_ump_block_info_t *bp;
+ snd_ump_endpoint_info_t *ep = seq->ump_ep;
+ int err;
+
+ if (!ep)
+ return -EINVAL;
+ if (info->first_group >= seq->num_ump_groups ||
+ info->first_group + info->num_groups > seq->num_ump_groups)
+ return -EINVAL;
+ if (blkid < 0 || blkid >= (int)ep->num_blocks)
+ return -EINVAL;
+
+ if (seq->ump_blks[blkid])
+ return -EBUSY;
+ seq->ump_blks[blkid] = bp = malloc(sizeof(*info));
+ if (!bp)
+ return -ENOMEM;
+ *bp = *info;
+
+ if (!bp->midi_ci_version)
+ bp->midi_ci_version = SND_UMP_BLOCK_INFO_DEFAULT_MIDI_CI_VERSION;
+ bp->active = 1;
+
+ err = snd_seq_set_ump_block_info(seq, blkid, bp);
+ if (err < 0) {
+ SNDERR("Failed to set UMP EP info\n");
+ free(bp);
+ seq->ump_blks[blkid] = NULL;
+ return err;
+ }
+
+ update_group_ports(seq, ep);
+ return 0;
+}
--
2.43.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH alsa-lib 2/4] seq: Add API helper functions for creating UMP Endpoint and Blocks
2024-06-19 15:28 ` [PATCH alsa-lib 2/4] seq: Add API helper functions for creating UMP Endpoint and Blocks Takashi Iwai
@ 2024-07-31 8:46 ` Amadeusz Sławiński
2024-07-31 9:21 ` Takashi Iwai
0 siblings, 1 reply; 9+ messages in thread
From: Amadeusz Sławiński @ 2024-07-31 8:46 UTC (permalink / raw)
To: Takashi Iwai, alsa-devel
On 6/19/2024 5:28 PM, Takashi Iwai wrote:
> For making it easer for applications to create a virtual UMP Endpoint
> and UMP blocks, add two API helper functions.
>
> snd_seq_create_ump_endpoint() creates (unsurprisingly) a UMP Endpoint,
> based on the given snd_ump_endpoint_info_t information. The number of
> (max) UMP groups belonging to this Endpoint has to be specified.
> This function sets up the Endpoint info on the sequencer client, and
> creates a MIDI 2.0 UMP port as well as UMP Group ports automatically.
> The name of the sequencer client is updated from the Endpoint name,
> too.
>
> After creating a UMP Endpoint, create each UMP Block via
> snd_seq_create_ump_block() function with a snd_ump_block_info_t info.
> The associated groups for each block have to be specified there.
> The port names and capability bits are updated accordingly after
> setting each block information.
>
> Signed-off-by: Takashi Iwai <tiwai@suse.de>
> ---
...
> + if (*blknames) {
> + strlcat(blknames, ", ", sizeof(blknames));
> + strlcat(blknames, (const char *)bp->name,
> + sizeof(blknames));
FYI, this seems to introduce build problems on systems that do not have
strlcpy:
During build:
seqmid.c: In function ‘update_group_ports’:
seqmid.c:672:33: warning: implicit declaration of function ‘strlcat’;
did you mean ‘strncat’? [-Wimplicit-function-declaration]
672 | strlcat(blknames, ", ",
sizeof(blknames));
| ^~~~~~~
| strncat
And then during linking:
/usr/bin/ld: seq/.libs/libseq.a(seqmid.o): in function `update_group_ports':
/home/amade/workdir/avs/alsa-lib/src/seq/seqmid.c:672: undefined
reference to `strlcat'
/usr/bin/ld: /home/amade/workdir/avs/alsa-lib/src/seq/seqmid.c:673:
undefined reference to `strlcat'
collect2: error: ld returned 1 exit status
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH alsa-lib 2/4] seq: Add API helper functions for creating UMP Endpoint and Blocks
2024-07-31 8:46 ` Amadeusz Sławiński
@ 2024-07-31 9:21 ` Takashi Iwai
2024-07-31 9:29 ` Amadeusz Sławiński
0 siblings, 1 reply; 9+ messages in thread
From: Takashi Iwai @ 2024-07-31 9:21 UTC (permalink / raw)
To: Amadeusz Sławiński; +Cc: alsa-devel
On Wed, 31 Jul 2024 10:46:08 +0200,
Amadeusz Sławiński wrote:
>
> On 6/19/2024 5:28 PM, Takashi Iwai wrote:
> > For making it easer for applications to create a virtual UMP Endpoint
> > and UMP blocks, add two API helper functions.
> >
> > snd_seq_create_ump_endpoint() creates (unsurprisingly) a UMP Endpoint,
> > based on the given snd_ump_endpoint_info_t information. The number of
> > (max) UMP groups belonging to this Endpoint has to be specified.
> > This function sets up the Endpoint info on the sequencer client, and
> > creates a MIDI 2.0 UMP port as well as UMP Group ports automatically.
> > The name of the sequencer client is updated from the Endpoint name,
> > too.
> >
> > After creating a UMP Endpoint, create each UMP Block via
> > snd_seq_create_ump_block() function with a snd_ump_block_info_t info.
> > The associated groups for each block have to be specified there.
> > The port names and capability bits are updated accordingly after
> > setting each block information.
> >
> > Signed-off-by: Takashi Iwai <tiwai@suse.de>
> > ---
>
> ...
>
> > + if (*blknames) {
> > + strlcat(blknames, ", ", sizeof(blknames));
> > + strlcat(blknames, (const char *)bp->name,
> > + sizeof(blknames));
>
> FYI, this seems to introduce build problems on systems that do not
> have strlcpy:
>
> During build:
> seqmid.c: In function ‘update_group_ports’:
> seqmid.c:672:33: warning: implicit declaration of function
> ‘strlcat’; did you mean ‘strncat’?
> [-Wimplicit-function-declaration]
> 672 | strlcat(blknames, ", ",
> sizeof(blknames));
> | ^~~~~~~
> | strncat
>
> And then during linking:
> /usr/bin/ld: seq/.libs/libseq.a(seqmid.o): in function `update_group_ports':
> /home/amade/workdir/avs/alsa-lib/src/seq/seqmid.c:672: undefined
> reference to `strlcat'
> /usr/bin/ld: /home/amade/workdir/avs/alsa-lib/src/seq/seqmid.c:673:
> undefined reference to `strlcat'
> collect2: error: ld returned 1 exit status
Thanks, I'll modify it to avoid strlcat() like below.
Takashi
-- 8< --
Subject: [PATCH] seq: Avoid strlcat()
strlcat() isn't available in every system, so better to avoid it.
Rewrite the code without strlcat().
Fixes: 6167b8ce3e80 ("seq: Add API helper functions for creating UMP Endpoint and Blocks")
Link: https://lore.kernel.org/0796c157-1ac3-47a3-9d54-ba86f59d64d5@linux.intel.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
src/seq/seqmid.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/seq/seqmid.c b/src/seq/seqmid.c
index 08c62d5c24b8..b30db4075254 100644
--- a/src/seq/seqmid.c
+++ b/src/seq/seqmid.c
@@ -635,6 +635,7 @@ static void update_group_ports(snd_seq_t *seq, snd_ump_endpoint_info_t *ep)
char blknames[64];
char name[64];
unsigned int caps = 0;
+ int len;
blknames[0] = 0;
for (b = 0; b < ep->num_blocks; b++) {
@@ -668,14 +669,13 @@ static void update_group_ports(snd_seq_t *seq, snd_ump_endpoint_info_t *ep)
if (!*bp->name)
continue;
- if (*blknames) {
- strlcat(blknames, ", ", sizeof(blknames));
- strlcat(blknames, (const char *)bp->name,
- sizeof(blknames));
- } else {
+ len = strlen(blknames);
+ if (len)
+ snprintf(blknames + len, sizeof(blknames) - len,
+ ", %s", bp->name);
+ else
snd_strlcpy(blknames, (const char *)bp->name,
sizeof(blknames));
- }
}
if (!*blknames)
--
2.43.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH alsa-lib 2/4] seq: Add API helper functions for creating UMP Endpoint and Blocks
2024-07-31 9:21 ` Takashi Iwai
@ 2024-07-31 9:29 ` Amadeusz Sławiński
2024-07-31 9:34 ` Takashi Iwai
0 siblings, 1 reply; 9+ messages in thread
From: Amadeusz Sławiński @ 2024-07-31 9:29 UTC (permalink / raw)
To: Takashi Iwai; +Cc: alsa-devel
On 7/31/2024 11:21 AM, Takashi Iwai wrote:
> On Wed, 31 Jul 2024 10:46:08 +0200,
> Amadeusz Sławiński wrote:
>>
>> On 6/19/2024 5:28 PM, Takashi Iwai wrote:
>>> For making it easer for applications to create a virtual UMP Endpoint
>>> and UMP blocks, add two API helper functions.
>>>
>>> snd_seq_create_ump_endpoint() creates (unsurprisingly) a UMP Endpoint,
>>> based on the given snd_ump_endpoint_info_t information. The number of
>>> (max) UMP groups belonging to this Endpoint has to be specified.
>>> This function sets up the Endpoint info on the sequencer client, and
>>> creates a MIDI 2.0 UMP port as well as UMP Group ports automatically.
>>> The name of the sequencer client is updated from the Endpoint name,
>>> too.
>>>
>>> After creating a UMP Endpoint, create each UMP Block via
>>> snd_seq_create_ump_block() function with a snd_ump_block_info_t info.
>>> The associated groups for each block have to be specified there.
>>> The port names and capability bits are updated accordingly after
>>> setting each block information.
>>>
>>> Signed-off-by: Takashi Iwai <tiwai@suse.de>
>>> ---
>>
>> ...
>>
>>> + if (*blknames) {
>>> + strlcat(blknames, ", ", sizeof(blknames));
>>> + strlcat(blknames, (const char *)bp->name,
>>> + sizeof(blknames));
>>
>> FYI, this seems to introduce build problems on systems that do not
>> have strlcpy:
>>
>> During build:
>> seqmid.c: In function ‘update_group_ports’:
>> seqmid.c:672:33: warning: implicit declaration of function
>> ‘strlcat’; did you mean ‘strncat’?
>> [-Wimplicit-function-declaration]
>> 672 | strlcat(blknames, ", ",
>> sizeof(blknames));
>> | ^~~~~~~
>> | strncat
>>
>> And then during linking:
>> /usr/bin/ld: seq/.libs/libseq.a(seqmid.o): in function `update_group_ports':
>> /home/amade/workdir/avs/alsa-lib/src/seq/seqmid.c:672: undefined
>> reference to `strlcat'
>> /usr/bin/ld: /home/amade/workdir/avs/alsa-lib/src/seq/seqmid.c:673:
>> undefined reference to `strlcat'
>> collect2: error: ld returned 1 exit status
>
> Thanks, I'll modify it to avoid strlcat() like below.
>
>
> Takashi
>
> -- 8< --
> Subject: [PATCH] seq: Avoid strlcat()
>
> strlcat() isn't available in every system, so better to avoid it.
> Rewrite the code without strlcat().
>
> Fixes: 6167b8ce3e80 ("seq: Add API helper functions for creating UMP Endpoint and Blocks")
> Link: https://lore.kernel.org/0796c157-1ac3-47a3-9d54-ba86f59d64d5@linux.intel.com
> Signed-off-by: Takashi Iwai <tiwai@suse.de>
> ---
> src/seq/seqmid.c | 12 ++++++------
> 1 file changed, 6 insertions(+), 6 deletions(-)
>
> diff --git a/src/seq/seqmid.c b/src/seq/seqmid.c
> index 08c62d5c24b8..b30db4075254 100644
> --- a/src/seq/seqmid.c
> +++ b/src/seq/seqmid.c
> @@ -635,6 +635,7 @@ static void update_group_ports(snd_seq_t *seq, snd_ump_endpoint_info_t *ep)
> char blknames[64];
> char name[64];
> unsigned int caps = 0;
> + int len;
>
> blknames[0] = 0;
> for (b = 0; b < ep->num_blocks; b++) {
> @@ -668,14 +669,13 @@ static void update_group_ports(snd_seq_t *seq, snd_ump_endpoint_info_t *ep)
>
> if (!*bp->name)
> continue;
> - if (*blknames) {
> - strlcat(blknames, ", ", sizeof(blknames));
> - strlcat(blknames, (const char *)bp->name,
> - sizeof(blknames));
> - } else {
> + len = strlen(blknames);
> + if (len)
> + snprintf(blknames + len, sizeof(blknames) - len,
> + ", %s", bp->name);
> + else
> snd_strlcpy(blknames, (const char *)bp->name,
> sizeof(blknames));
> - }
> }
>
> if (!*blknames)
Builds now, but still gives warning:
seqmid.c: In function ‘update_group_ports’:
seqmid.c:675:45: warning: ‘%s’ directive output may be truncated writing
up to 127 bytes into a region of size 61 [-Wformat-truncation=]
675 | ", %s", bp->name);
| ^~
In file included from /usr/include/stdio.h:894,
from ../../include/local.h:28,
from seq_local.h:26,
from seqmid.c:23:
In function ‘snprintf’,
inlined from ‘update_group_ports’ at seqmid.c:674:5:
/usr/include/x86_64-linux-gnu/bits/stdio2.h:71:10: note:
‘__builtin___snprintf_chk’ output between 3 and 130 bytes into a
destination of size 63
71 | return __builtin___snprintf_chk (__s, __n,
__USE_FORTIFY_LEVEL - 1,
|
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
72 | __glibc_objsize (__s), __fmt,
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
73 | __va_arg_pack ());
| ~~~~~~~~~~~~~~~~~
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH alsa-lib 2/4] seq: Add API helper functions for creating UMP Endpoint and Blocks
2024-07-31 9:29 ` Amadeusz Sławiński
@ 2024-07-31 9:34 ` Takashi Iwai
0 siblings, 0 replies; 9+ messages in thread
From: Takashi Iwai @ 2024-07-31 9:34 UTC (permalink / raw)
To: Amadeusz Sławiński; +Cc: alsa-devel
On Wed, 31 Jul 2024 11:29:41 +0200,
Amadeusz Sławiński wrote:
>
> On 7/31/2024 11:21 AM, Takashi Iwai wrote:
> > On Wed, 31 Jul 2024 10:46:08 +0200,
> > Amadeusz Sławiński wrote:
> >>
> >> On 6/19/2024 5:28 PM, Takashi Iwai wrote:
> >>> For making it easer for applications to create a virtual UMP Endpoint
> >>> and UMP blocks, add two API helper functions.
> >>>
> >>> snd_seq_create_ump_endpoint() creates (unsurprisingly) a UMP Endpoint,
> >>> based on the given snd_ump_endpoint_info_t information. The number of
> >>> (max) UMP groups belonging to this Endpoint has to be specified.
> >>> This function sets up the Endpoint info on the sequencer client, and
> >>> creates a MIDI 2.0 UMP port as well as UMP Group ports automatically.
> >>> The name of the sequencer client is updated from the Endpoint name,
> >>> too.
> >>>
> >>> After creating a UMP Endpoint, create each UMP Block via
> >>> snd_seq_create_ump_block() function with a snd_ump_block_info_t info.
> >>> The associated groups for each block have to be specified there.
> >>> The port names and capability bits are updated accordingly after
> >>> setting each block information.
> >>>
> >>> Signed-off-by: Takashi Iwai <tiwai@suse.de>
> >>> ---
> >>
> >> ...
> >>
> >>> + if (*blknames) {
> >>> + strlcat(blknames, ", ", sizeof(blknames));
> >>> + strlcat(blknames, (const char *)bp->name,
> >>> + sizeof(blknames));
> >>
> >> FYI, this seems to introduce build problems on systems that do not
> >> have strlcpy:
> >>
> >> During build:
> >> seqmid.c: In function ‘update_group_ports’:
> >> seqmid.c:672:33: warning: implicit declaration of function
> >> ‘strlcat’; did you mean ‘strncat’?
> >> [-Wimplicit-function-declaration]
> >> 672 | strlcat(blknames, ", ",
> >> sizeof(blknames));
> >> | ^~~~~~~
> >> | strncat
> >>
> >> And then during linking:
> >> /usr/bin/ld: seq/.libs/libseq.a(seqmid.o): in function `update_group_ports':
> >> /home/amade/workdir/avs/alsa-lib/src/seq/seqmid.c:672: undefined
> >> reference to `strlcat'
> >> /usr/bin/ld: /home/amade/workdir/avs/alsa-lib/src/seq/seqmid.c:673:
> >> undefined reference to `strlcat'
> >> collect2: error: ld returned 1 exit status
> >
> > Thanks, I'll modify it to avoid strlcat() like below.
> >
> >
> > Takashi
> >
> > -- 8< --
> > Subject: [PATCH] seq: Avoid strlcat()
> >
> > strlcat() isn't available in every system, so better to avoid it.
> > Rewrite the code without strlcat().
> >
> > Fixes: 6167b8ce3e80 ("seq: Add API helper functions for creating UMP Endpoint and Blocks")
> > Link: https://lore.kernel.org/0796c157-1ac3-47a3-9d54-ba86f59d64d5@linux.intel.com
> > Signed-off-by: Takashi Iwai <tiwai@suse.de>
> > ---
> > src/seq/seqmid.c | 12 ++++++------
> > 1 file changed, 6 insertions(+), 6 deletions(-)
> >
> > diff --git a/src/seq/seqmid.c b/src/seq/seqmid.c
> > index 08c62d5c24b8..b30db4075254 100644
> > --- a/src/seq/seqmid.c
> > +++ b/src/seq/seqmid.c
> > @@ -635,6 +635,7 @@ static void update_group_ports(snd_seq_t *seq, snd_ump_endpoint_info_t *ep)
> > char blknames[64];
> > char name[64];
> > unsigned int caps = 0;
> > + int len;
> > blknames[0] = 0;
> > for (b = 0; b < ep->num_blocks; b++) {
> > @@ -668,14 +669,13 @@ static void update_group_ports(snd_seq_t *seq, snd_ump_endpoint_info_t *ep)
> > if (!*bp->name)
> > continue;
> > - if (*blknames) {
> > - strlcat(blknames, ", ", sizeof(blknames));
> > - strlcat(blknames, (const char *)bp->name,
> > - sizeof(blknames));
> > - } else {
> > + len = strlen(blknames);
> > + if (len)
> > + snprintf(blknames + len, sizeof(blknames) - len,
> > + ", %s", bp->name);
> > + else
> > snd_strlcpy(blknames, (const char *)bp->name,
> > sizeof(blknames));
> > - }
> > }
> > if (!*blknames)
>
> Builds now, but still gives warning:
>
> seqmid.c: In function ‘update_group_ports’:
> seqmid.c:675:45: warning: ‘%s’ directive output may be truncated
> writing up to 127 bytes into a region of size 61
> [-Wformat-truncation=]
> 675 | ", %s", bp->name);
> | ^~
> In file included from /usr/include/stdio.h:894,
> from ../../include/local.h:28,
> from seq_local.h:26,
> from seqmid.c:23:
> In function ‘snprintf’,
> inlined from ‘update_group_ports’ at seqmid.c:674:5:
> /usr/include/x86_64-linux-gnu/bits/stdio2.h:71:10: note:
> ‘__builtin___snprintf_chk’ output between 3 and 130 bytes into a
> destination of size 63
> 71 | return __builtin___snprintf_chk (__s, __n,
> __USE_FORTIFY_LEVEL - 1,
> | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> 72 | __glibc_objsize (__s), __fmt,
> | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> 73 | __va_arg_pack ());
> | ~~~~~~~~~~~~~~~~~
The compiler gives too much false positives.
Takashi
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH alsa-lib 3/4] test: Add an example program to create a virtual UMP Endpoint
2024-06-19 15:28 [PATCH alsa-lib 0/4] Add API helper functions for creating UMP Endpoint and Blocks Takashi Iwai
2024-06-19 15:28 ` [PATCH alsa-lib 1/4] ump: Add missing *_set variants for snd_ump_endpoint_info and snd_ump_block_info Takashi Iwai
2024-06-19 15:28 ` [PATCH alsa-lib 2/4] seq: Add API helper functions for creating UMP Endpoint and Blocks Takashi Iwai
@ 2024-06-19 15:28 ` Takashi Iwai
2024-06-19 15:28 ` [PATCH alsa-lib 4/4] Add test/seq-ump-example to .gitignore Takashi Iwai
3 siblings, 0 replies; 9+ messages in thread
From: Takashi Iwai @ 2024-06-19 15:28 UTC (permalink / raw)
To: alsa-devel
Provide an example program to demonstrate how to create a UMP Endpoint
and Blocks, i.e. a virtual UMP device.
It's a simple filtering application that just haves the incoming note
on/off velocity and sends out to the output. The UMP Endpoint and
Block attributes can be adjusted via command-line options.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
test/Makefile.am | 3 +-
test/seq-ump-example.c | 187 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 189 insertions(+), 1 deletion(-)
create mode 100644 test/seq-ump-example.c
diff --git a/test/Makefile.am b/test/Makefile.am
index 99c2c4ff9f06..635fa39bb7e3 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -1,6 +1,6 @@
SUBDIRS=. lsb
-check_PROGRAMS=control pcm pcm_min latency seq \
+check_PROGRAMS=control pcm pcm_min latency seq seq-ump-example \
playmidi1 timer rawmidi midiloop \
oldapi queue_timer namehint client_event_filter \
chmap audio_time user-ctl-element-set pcm-multi-thread
@@ -12,6 +12,7 @@ pcm_min_LDADD=../src/libasound.la
latency_LDADD=../src/libasound.la
latency_LDFLAGS= -lm
seq_LDADD=../src/libasound.la
+seq_ump_example_LDADD=../src/libasound.la
playmidi1_LDADD=../src/libasound.la
timer_LDADD=../src/libasound.la
rawmidi_LDADD=../src/libasound.la
diff --git a/test/seq-ump-example.c b/test/seq-ump-example.c
new file mode 100644
index 000000000000..7f6286827f36
--- /dev/null
+++ b/test/seq-ump-example.c
@@ -0,0 +1,187 @@
+// An example program to create a virtual UMP Endpoint
+//
+// A client simply reads each UMP packet and sends to subscribers
+// while the note on/off velocity is halved
+
+#include <stdio.h>
+#include <getopt.h>
+#include <alsa/asoundlib.h>
+#include <alsa/ump_msg.h>
+
+/* make the note on/off velocity half for MIDI1 CVM */
+static void midi1_half_note_velocity(snd_seq_ump_event_t *ev)
+{
+ snd_ump_msg_midi1_t *midi1 = (snd_ump_msg_midi1_t *)ev->ump;
+
+ switch (snd_ump_msg_status(ev->ump)) {
+ case SND_UMP_MSG_NOTE_OFF:
+ case SND_UMP_MSG_NOTE_ON:
+ midi1->note_on.velocity >>= 1;
+ break;
+ }
+}
+
+/* make the note on/off velocity half for MIDI2 CVM */
+static void midi2_half_note_velocity(snd_seq_ump_event_t *ev)
+{
+ snd_ump_msg_midi2_t *midi2 = (snd_ump_msg_midi2_t *)ev->ump;
+
+ switch (snd_ump_msg_status(ev->ump)) {
+ case SND_UMP_MSG_NOTE_OFF:
+ case SND_UMP_MSG_NOTE_ON:
+ midi2->note_on.velocity >>= 1;
+ break;
+ }
+}
+
+static void help(void)
+{
+ printf("seq-ump-example: Create a virtual UMP Endpoint and Blocks\n"
+ "\n"
+ "Usage: seq-ump-example [OPTIONS]\n"
+ "\n"
+ "-n,--num-blocks blocks Number of blocks (groups) to create\n"
+ "-m,--midi-version version MIDI protocol version (1 or 2)\n"
+ "-N--name UMP Endpoint name string\n"
+ "-P,--product name UMP Product ID string\n"
+ "-M,--manufacturer id UMP Manufacturer ID value (24bit)\n"
+ "-F,--family id UMP Family ID value (16bit)\n"
+ "-O,--model id UMP Model ID value (16bit)\n"
+ "-R,--sw-revision id UMP Software Revision ID (32bit)\n");
+}
+
+int main(int argc, char **argv)
+{
+ int midi_version = 2;
+ int num_blocks = 1;
+ const char *name = "ACMESynth";
+ const char *product = "Halfmoon";
+ unsigned int manufacturer = 0x123456;
+ unsigned int family = 0x1234;
+ unsigned int model = 0xabcd;
+ unsigned int sw_revision = 0x12345678;
+ snd_seq_t *seq;
+ snd_ump_endpoint_info_t *ep;
+ snd_ump_block_info_t *blk;
+ snd_seq_ump_event_t *ev;
+ int i, c, err;
+ unsigned char tmp[4];
+
+ static const struct option long_option[] = {
+ {"num-blocks", required_argument, 0, 'n'},
+ {"midi-version", required_argument, 0, 'm'},
+ {"name", required_argument, 0, 'N'},
+ {"product", required_argument, 0, 'P'},
+ {"manufacturer", required_argument, 0, 'M'},
+ {"family", required_argument, 0, 'F'},
+ {"model", required_argument, 0, 'O'},
+ {"sw-revision", required_argument, 0, 'R'},
+ {0, 0, 0, 0}
+ };
+
+ while ((c = getopt_long(argc, argv, "n:m:N:P:M:F:O:R:",
+ long_option, NULL)) >= 0) {
+ switch (c) {
+ case 'n':
+ num_blocks = atoi(optarg);
+ break;
+ case 'm':
+ midi_version = atoi(optarg);
+ break;
+ case 'N':
+ name = optarg;
+ break;
+ case 'P':
+ product = optarg;
+ break;
+ case 'M':
+ manufacturer = strtol(optarg, NULL, 0);
+ break;
+ case 'F':
+ family = strtol(optarg, NULL, 0);
+ break;
+ case 'O':
+ model = strtol(optarg, NULL, 0);
+ break;
+ case 'R':
+ sw_revision = strtol(optarg, NULL, 0);
+ break;
+ default:
+ help();
+ return 1;
+ }
+ }
+
+ err = snd_seq_open(&seq, "default", SND_SEQ_OPEN_DUPLEX, 0);
+ if (err < 0) {
+ fprintf(stderr, "failed to open sequencer: %d\n", err);
+ return 1;
+ }
+
+ snd_ump_endpoint_info_alloca(&ep);
+ snd_ump_endpoint_info_set_name(ep, name);
+ snd_ump_endpoint_info_set_product_id(ep, product);
+ if (midi_version == 1) {
+ snd_ump_endpoint_info_set_protocol_caps(ep, SND_UMP_EP_INFO_PROTO_MIDI1);
+ snd_ump_endpoint_info_set_protocol(ep, SND_UMP_EP_INFO_PROTO_MIDI1);
+ } else {
+ snd_ump_endpoint_info_set_protocol_caps(ep, SND_UMP_EP_INFO_PROTO_MIDI2);
+ snd_ump_endpoint_info_set_protocol(ep, SND_UMP_EP_INFO_PROTO_MIDI2);
+ }
+ snd_ump_endpoint_info_set_num_blocks(ep, num_blocks);
+ snd_ump_endpoint_info_set_manufacturer_id(ep, manufacturer);
+ snd_ump_endpoint_info_set_family_id(ep, family);
+ snd_ump_endpoint_info_set_model_id(ep, model);
+ for (i = 0; i < 4; i++)
+ tmp[i] = (sw_revision >> ((3 - i) * 8)) & 0xff;
+ snd_ump_endpoint_info_set_sw_revision(ep, tmp);
+
+ err = snd_seq_create_ump_endpoint(seq, ep, num_blocks);
+ if (err < 0) {
+ fprintf(stderr, "failed to set UMP EP info: %d\n", err);
+ return 1;
+ }
+
+ snd_ump_block_info_alloca(&blk);
+
+ for (i = 0; i < num_blocks; i++) {
+ char blkname[32];
+
+ sprintf(blkname, "Filter %d", i + 1);
+ snd_ump_block_info_set_name(blk, blkname);
+ snd_ump_block_info_set_direction(blk, SND_UMP_DIR_BIDIRECTION);
+ snd_ump_block_info_set_first_group(blk, i);
+ snd_ump_block_info_set_num_groups(blk, 1);
+ snd_ump_block_info_set_ui_hint(blk, SND_UMP_BLOCK_UI_HINT_BOTH);
+
+ err = snd_seq_create_ump_block(seq, i, blk);
+ if (err < 0) {
+ fprintf(stderr, "failed to set UMP block info %d: %d\n",
+ i, err);
+ return 1;
+ }
+ }
+
+ /* halve the incoming note-on / off velocity and pass through
+ * to subscribers
+ */
+ while (snd_seq_ump_event_input(seq, &ev) >= 0) {
+ if (!snd_seq_ev_is_ump(ev))
+ continue;
+ switch (snd_ump_msg_type(ev->ump)) {
+ case SND_UMP_MSG_TYPE_MIDI1_CHANNEL_VOICE:
+ midi1_half_note_velocity(ev);
+ break;
+ case SND_UMP_MSG_TYPE_MIDI2_CHANNEL_VOICE:
+ midi2_half_note_velocity(ev);
+ break;
+ }
+
+ snd_seq_ev_set_subs(ev);
+ snd_seq_ev_set_direct(ev);
+ snd_seq_ump_event_output(seq, ev);
+ snd_seq_drain_output(seq);
+ }
+
+ return 0;
+}
--
2.43.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH alsa-lib 4/4] Add test/seq-ump-example to .gitignore
2024-06-19 15:28 [PATCH alsa-lib 0/4] Add API helper functions for creating UMP Endpoint and Blocks Takashi Iwai
` (2 preceding siblings ...)
2024-06-19 15:28 ` [PATCH alsa-lib 3/4] test: Add an example program to create a virtual UMP Endpoint Takashi Iwai
@ 2024-06-19 15:28 ` Takashi Iwai
3 siblings, 0 replies; 9+ messages in thread
From: Takashi Iwai @ 2024-06-19 15:28 UTC (permalink / raw)
To: alsa-devel
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
.gitignore | 1 +
1 file changed, 1 insertion(+)
diff --git a/.gitignore b/.gitignore
index a74b5195a7d9..947eba45c685 100644
--- a/.gitignore
+++ b/.gitignore
@@ -65,6 +65,7 @@ test/playmidi1
test/queue_timer
test/rawmidi
test/seq
+test/seq-ump-example
test/timer
test/lsb/config
test/lsb/midi_event
--
2.43.0
^ permalink raw reply related [flat|nested] 9+ messages in thread