diff mbox series

[alsa-utils,09/10] aseqsend: Support UMP mode

Message ID 20240722175215.8223-10-tiwai@suse.de (mailing list archive)
State New, archived
Headers show
Series Cleanup seq/* stuff and extend aseqsend | expand

Commit Message

Takashi Iwai July 22, 2024, 5:52 p.m. UTC
Add a new option -u to specify the UMP MIDI1 or MIDI2 mode.  As
default (-u 0), the program reads the legacy MIDI 1.0 byte stream,
while in UMP mode, it reads as UMP packets and send to the target.
The UMP packet bytes are encoded in big endian.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 seq/aseqsend/aseqsend.1 | 13 ++++++++++---
 seq/aseqsend/aseqsend.c | 43 ++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 52 insertions(+), 4 deletions(-)
diff mbox series

Patch

diff --git a/seq/aseqsend/aseqsend.1 b/seq/aseqsend/aseqsend.1
index 340c3292f5ed..febbf55dfb16 100644
--- a/seq/aseqsend/aseqsend.1
+++ b/seq/aseqsend/aseqsend.1
@@ -14,6 +14,10 @@  It can also send any other MIDI commands.
 Messages to be send can be given in the last argument as hex encoded byte string or can be read from raw binary file.
 When sending several SysEx messages at once there is a delay of 1ms after each message as deafult and can be set to different value with option \-i.
 
+A client can be specified by its number, its name, or a prefix of its
+name.  A port is specified by its number; for port 0 of a client, the
+":0" part of the port specification can be omitted.
+
 .SH OPTIONS
 
 .TP
@@ -44,10 +48,13 @@  Send raw binary data from given file name
 \-i
 Interval between SysEx messages in miliseconds
 
+.TP
+\-u
+Specify the MIDI version. 0 for the legacy MIDI 1.0 (default),
+1 for UMP MIDI 1.0 protocol and 2 for UMP MIDI 2.0 protocol.
 
-A client can be specified by its number, its name, or a prefix of its
-name.  A port is specified by its number; for port 0 of a client, the
-":0" part of the port specification can be omitted.
+When UMP MIDI 1.0 or MIDI 2.0 protocol is specified, \fBaseqsend\fP
+reads the input as raw UMP packets, 4 each byte in big endian.
 
 .SH EXAMPLES
 
diff --git a/seq/aseqsend/aseqsend.c b/seq/aseqsend/aseqsend.c
index 95b0024c0fd6..bd1a221d4149 100644
--- a/seq/aseqsend/aseqsend.c
+++ b/seq/aseqsend/aseqsend.c
@@ -33,6 +33,7 @@ 
 #include <signal.h>
 #include <unistd.h>
 #include <alsa/asoundlib.h>
+#include <alsa/ump_msg.h>
 
 typedef unsigned char mbyte_t;
 
@@ -43,6 +44,7 @@  static char *send_hex;
 static mbyte_t *send_data;
 static snd_seq_addr_t addr;
 static int send_data_length;
+static int ump_version;
 
 static void error(const char *format, ...)
 {
@@ -320,6 +322,32 @@  static void send_midi_msg(snd_seq_event_type_t type, mbyte_t *data, int len)
 	snd_seq_drain_output(seq);
 }
 
+static int send_ump(const unsigned char *data)
+{
+	static int ump_len = 0, offset = 0;
+	unsigned int ump[4];
+	snd_seq_ump_event_t ev;
+
+	ump[offset] = (data[0] << 24) | (data[1] << 16) |
+		(data[2] << 8) | data[3];
+	if (!offset)
+		ump_len = snd_ump_packet_length(snd_ump_msg_type(ump));
+
+	offset++;
+	if (offset < ump_len)
+		return 0;
+
+	snd_seq_ump_ev_clear(&ev);
+	snd_seq_ev_set_source(&ev, 0);
+	snd_seq_ev_set_dest(&ev, addr.client, addr.port);
+	snd_seq_ev_set_direct(&ev);
+	snd_seq_ev_set_ump_data(&ev, ump, ump_len * 4);
+	snd_seq_ump_event_output(seq, &ev);
+	snd_seq_drain_output(seq);
+	offset = 0;
+	return ump_len * 4;
+}
+
 static int msg_byte_in_range(mbyte_t *data, mbyte_t len)
 {
 	for (int i = 0; i < len; i++) {
@@ -342,7 +370,7 @@  int main(int argc, char *argv[])
 	int sent_data_c;
 	int k;
 
-	while ((c = getopt(argc, argv, "hi:Vvlp:s:")) != -1) {
+	while ((c = getopt(argc, argv, "hi:Vvlp:s:u:")) != -1) {
 		switch (c) {
 		case 'h':
 			usage();
@@ -366,6 +394,9 @@  int main(int argc, char *argv[])
 		case 'i':
 			sysex_interval = atoi(optarg) * 1000; //ms--->us
 			break;
+		case 'u':
+			ump_version = atoi(optarg);
+			break;
 		default:
 			error("Try 'aseqsend -h' for more information.");
 			exit(EXIT_FAILURE);
@@ -401,7 +432,11 @@  int main(int argc, char *argv[])
 	if (!send_data)
 		exit(EXIT_SUCCESS);
 
+	if (ump_version && (send_data_length % 4) != 0)
+		fatal("UMP data must be aligned to 4 bytes");
+
 	init_seq();
+	snd_seq_set_client_midi_version(seq, ump_version);
 	create_port();
 
 	if (snd_seq_parse_address(seq, &addr, port_name) < 0) {
@@ -414,6 +449,12 @@  int main(int argc, char *argv[])
 
 	while (k < send_data_length) {
 
+		if (ump_version) {
+			sent_data_c += send_ump(send_data + k);
+			k += 4;
+			continue;
+		}
+
 		if (send_data[k] == 0xF0) {
 
 			int c1 = k;