* [PATCH alsa-lib 0/4] Add API helper functions for creating UMP Endpoint and Blocks
@ 2024-06-19 15:28 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
` (3 more replies)
0 siblings, 4 replies; 9+ messages in thread
From: Takashi Iwai @ 2024-06-19 15:28 UTC (permalink / raw)
To: alsa-devel
Hi,
this is a patch set to alsa-lib to add the new API functions for
creating a virtual UMP Endpoint and UMP Blocks arbitrarily from a
user-space, that is, to create a virtual UMP device.
An example program is included in test directory.
Takashi
===
Takashi Iwai (4):
ump: Add missing *_set variants for snd_ump_endpoint_info and
snd_ump_block_info
seq: Add API helper functions for creating UMP Endpoint and Blocks
test: Add an example program to create a virtual UMP Endpoint
Add test/seq-ump-example to .gitignore
.gitignore | 1 +
include/seqmid.h | 7 +
include/ump.h | 36 ++++-
src/rawmidi/ump.c | 304 +++++++++++++++++++++++++++++++++++++++--
src/seq/seq.c | 6 +-
src/seq/seq_local.h | 4 +
src/seq/seqmid.c | 249 +++++++++++++++++++++++++++++++++
test/Makefile.am | 3 +-
test/seq-ump-example.c | 187 +++++++++++++++++++++++++
9 files changed, 783 insertions(+), 14 deletions(-)
create mode 100644 test/seq-ump-example.c
--
2.43.0
^ permalink raw reply [flat|nested] 9+ messages in thread
* [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
* [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
* 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
end of thread, other threads:[~2024-07-31 9:34 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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-07-31 8:46 ` Amadeusz Sławiński
2024-07-31 9:21 ` Takashi Iwai
2024-07-31 9:29 ` Amadeusz Sławiński
2024-07-31 9:34 ` Takashi Iwai
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
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.