diff mbox series

[alsa-utils,2/2] aseqdump: Support of UMP Stream and Flex Data message types

Message ID 20240719123454.24493-2-tiwai@suse.de (mailing list archive)
State New, archived
Headers show
Series [alsa-utils,1/2] aplaymidi2: Add -a option to pass all UMP packets | expand

Commit Message

Takashi Iwai July 19, 2024, 12:34 p.m. UTC
Enhance aseqdump to interpret more UMP messages.  Now it includes the
standard  Stream messages and Flex Data messages.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 seq/aseqdump/aseqdump.c | 247 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 247 insertions(+)
diff mbox series

Patch

diff --git a/seq/aseqdump/aseqdump.c b/seq/aseqdump/aseqdump.c
index b8137112d836..04901d6187f7 100644
--- a/seq/aseqdump/aseqdump.c
+++ b/seq/aseqdump/aseqdump.c
@@ -705,6 +705,247 @@  static void dump_ump_sysex_event(const unsigned int *ump)
 	printf("\n");
 }
 
+static void print_ump_string(const unsigned int *ump, unsigned int fmt,
+			     unsigned int offset, int maxlen)
+{
+	static const char *fmtstr[4] = { "Single", "Start", "Cont", "End" };
+	unsigned char buf[32];
+	int i = 0;
+
+	do {
+		buf[i] = (*ump >> (24 - offset)) & 0xff;
+		if (!buf[i])
+			break;
+		if (buf[i] < 0x20)
+			buf[i] = '.';
+		if (offset == 24) {
+			offset = 0;
+			ump++;
+		} else {
+			offset += 8;
+		}
+	} while (++i < maxlen);
+	buf[i] = 0;
+
+	printf("%6s: %s", fmtstr[fmt], buf);
+}
+
+static void dump_ump_stream_event(const unsigned int *ump)
+{
+	const snd_ump_msg_stream_t *s = (const snd_ump_msg_stream_t *)ump;
+
+	printf("          "); /* stream message is groupless */
+	switch (s->gen.status) {
+	case SND_UMP_STREAM_MSG_STATUS_EP_DISCOVERY:
+		printf("EP Discovery    ver=%d/%d, filter=0x%x\n",
+		       (ump[0] >> 8) & 0xff, ump[0] & 0xff, ump[1] & 0xff);
+		break;
+	case SND_UMP_STREAM_MSG_STATUS_EP_INFO:
+		printf("EP Info         ver=%d/%d, static=%d, fb#=%d, midi2=%d, midi1=%d, rxjr=%d, txjr=%d\n",
+		       (ump[0] >> 8) & 0xff, ump[0] & 0xff, (ump[1] >> 31),
+		       (ump[1] >> 24) & 0x7f,
+		       (ump[1] >> 9) & 1, (ump[1] >> 8) & 1,
+		       (ump[1] >> 1) & 1, ump[1] & 1);
+		break;
+	case SND_UMP_STREAM_MSG_STATUS_DEVICE_INFO:
+		printf("Device Info     sysid=%02x:%02x:%02x, family=%02x:%02x, model=%02x:%02x, rev=%02x:%02x:%02x:%02x\n",
+		       (ump[1] >> 16) & 0x7f, (ump[1] >> 8) & 0x7f, ump[1] & 0x7f,
+		       (ump[2] >> 16) & 0x7f, (ump[2] >> 24) & 0x7f,
+		       ump[2] & 0x7f, (ump[2] >> 8) & 0x7f,
+		       (ump[3] >> 24) & 0x7f, (ump[3] >> 16) & 0x7f,
+		       (ump[3] >> 8) & 0x7f, ump[3] & 0x7f);
+		break;
+	case SND_UMP_STREAM_MSG_STATUS_EP_NAME:
+		printf("EP Name        ");
+		print_ump_string(ump, (ump[0] >> 26) & 3, 16, 14);
+		printf("\n");
+		break;
+	case SND_UMP_STREAM_MSG_STATUS_PRODUCT_ID:
+		printf("Product Id     ");
+		print_ump_string(ump, (ump[0] >> 26) & 3, 16, 14);
+		printf("\n");
+		break;
+	case SND_UMP_STREAM_MSG_STATUS_STREAM_CFG_REQUEST:
+		printf("Stream Cfg Req protocl=%d, rxjr=%d, txjr=%d\n",
+		       (ump[0] >> 8) & 0xff, (ump[0] >> 1) & 1, ump[0] & 1);
+		break;
+	case SND_UMP_STREAM_MSG_STATUS_STREAM_CFG:
+		printf("Stream Cfg     protocl=%d, rxjr=%d, txjr=%d\n",
+		       (ump[0] >> 8) & 0xff, (ump[0] >> 1) & 1, ump[0] & 1);
+		break;
+	case SND_UMP_STREAM_MSG_STATUS_FB_DISCOVERY:
+		printf("FB Discovery   fb#=%d, filter=0x%x\n",
+		       (ump[0] >> 8) & 0xff, ump[0] & 0xff);
+		break;
+	case SND_UMP_STREAM_MSG_STATUS_FB_INFO:
+		printf("FB Info        fb#=%d, active=%d, ui=%d, MIDI1=%d, dir=%d, group=%d-%d, MIDI-CI=%d, SysEx8=%d\n",
+		       (ump[0] >> 8) & 0x7f, (ump[0] >> 15) & 1,
+		       (ump[0] >> 4) & 3, (ump[0] >> 2) & 3, ump[0] & 3,
+		       (ump[1] >> 24) & 0xff, (ump[1] >> 16) & 0xff,
+		       (ump[1] >> 8) * 0xff, ump[1] & 0xff);
+		break;
+	case SND_UMP_STREAM_MSG_STATUS_FB_NAME:
+		printf("Product Id     ");
+		printf("FB Name #%02d    ", (ump[0] >> 8) & 0xff);
+		print_ump_string(ump, (ump[0] >> 26) & 3, 24, 13);
+		printf("\n");
+		break;
+	case SND_UMP_STREAM_MSG_STATUS_START_CLIP:
+		printf("Start Clip\n");
+		break;
+	case SND_UMP_STREAM_MSG_STATUS_END_CLIP:
+		printf("End Clip\n");
+		break;
+	default:
+		printf("UMP Stream event: status = %d, 0x%08x:0x%08x:0x%08x:0x%08x\n",
+		       s->gen.status, ump[0], ump[1], ump[2], ump[3]);
+		break;
+	}
+}
+
+struct flexdata_text_prefix {
+	unsigned char status_bank;
+	unsigned char status;
+	const char *prefix;
+};
+
+static struct flexdata_text_prefix text_prefix[] = {
+	{ .status_bank = SND_UMP_FLEX_DATA_MSG_BANK_METADATA,
+	  .status = SND_UMP_FLEX_DATA_MSG_STATUS_PROJECT_NAME,
+	  .prefix = "Project" },
+	{ .status_bank = SND_UMP_FLEX_DATA_MSG_BANK_METADATA,
+	  .status = SND_UMP_FLEX_DATA_MSG_STATUS_SONG_NAME,
+	  .prefix = "Song" },
+	{ .status_bank = SND_UMP_FLEX_DATA_MSG_BANK_METADATA,
+	  .status = SND_UMP_FLEX_DATA_MSG_STATUS_MIDI_CLIP_NAME,
+	  .prefix = "MIDI Clip" },
+	{ .status_bank = SND_UMP_FLEX_DATA_MSG_BANK_METADATA,
+	  .status = SND_UMP_FLEX_DATA_MSG_STATUS_COPYRIGHT_NOTICE,
+	  .prefix = "Copyright" },
+	{ .status_bank = SND_UMP_FLEX_DATA_MSG_BANK_METADATA,
+	  .status = SND_UMP_FLEX_DATA_MSG_STATUS_COMPOSER_NAME,
+	  .prefix = "Composer" },
+	{ .status_bank = SND_UMP_FLEX_DATA_MSG_BANK_METADATA,
+	  .status = SND_UMP_FLEX_DATA_MSG_STATUS_LYRICIST_NAME,
+	  .prefix = "Lyricist" },
+	{ .status_bank = SND_UMP_FLEX_DATA_MSG_BANK_METADATA,
+	  .status = SND_UMP_FLEX_DATA_MSG_STATUS_ARRANGER_NAME,
+	  .prefix = "Arranger" },
+	{ .status_bank = SND_UMP_FLEX_DATA_MSG_BANK_METADATA,
+	  .status = SND_UMP_FLEX_DATA_MSG_STATUS_PUBLISHER_NAME,
+	  .prefix = "Publisher" },
+	{ .status_bank = SND_UMP_FLEX_DATA_MSG_BANK_METADATA,
+	  .status = SND_UMP_FLEX_DATA_MSG_STATUS_PRIMARY_PERFORMER,
+	  .prefix = "Performer" },
+	{ .status_bank = SND_UMP_FLEX_DATA_MSG_BANK_METADATA,
+	  .status = SND_UMP_FLEX_DATA_MSG_STATUS_ACCOMPANY_PERFORMAER,
+	  .prefix = "Accompany Performer" },
+	{ .status_bank = SND_UMP_FLEX_DATA_MSG_BANK_METADATA,
+	  .status = SND_UMP_FLEX_DATA_MSG_STATUS_RECORDING_DATE,
+	  .prefix = "Recording Date" },
+	{ .status_bank = SND_UMP_FLEX_DATA_MSG_BANK_METADATA,
+	  .status = SND_UMP_FLEX_DATA_MSG_STATUS_RECORDING_LOCATION,
+	  .prefix = "Recording Location" },
+	{ .status_bank = SND_UMP_FLEX_DATA_MSG_BANK_PERF_TEXT,
+	  .status = SND_UMP_FLEX_DATA_MSG_STATUS_LYRICS,
+	  .prefix = "Lyrics" },
+	{ .status_bank = SND_UMP_FLEX_DATA_MSG_BANK_PERF_TEXT,
+	  .status = SND_UMP_FLEX_DATA_MSG_STATUS_LYRICS_LANGUAGE,
+	  .prefix = "Lyrics Language" },
+	{ .status_bank = SND_UMP_FLEX_DATA_MSG_BANK_PERF_TEXT,
+	  .status = SND_UMP_FLEX_DATA_MSG_STATUS_RUBY,
+	  .prefix = "Ruby" },
+	{ .status_bank = SND_UMP_FLEX_DATA_MSG_BANK_PERF_TEXT,
+	  .status = SND_UMP_FLEX_DATA_MSG_STATUS_RUBY_LANGUAGE,
+	  .prefix = "Ruby Language" },
+	{}
+};
+
+static const char *ump_meta_prefix(const snd_ump_msg_flex_data_t *fh)
+{
+	static char buf[32];
+	int i;
+
+	for (i = 0; text_prefix[i].status_bank; i++) {
+		if (text_prefix[i].status_bank == fh->meta.status_bank &&
+		    text_prefix[i].status == fh->meta.status)
+			return text_prefix[i].prefix;
+	}
+
+	sprintf(buf, "(%d:%d)", fh->meta.status_bank, fh->meta.status);
+	return buf;
+}
+
+static void dump_ump_flex_data_event(const unsigned int *ump)
+{
+	const snd_ump_msg_flex_data_t *fh =
+		(const snd_ump_msg_flex_data_t *)ump;
+
+	printf("Group %2d, ", group_number(snd_ump_msg_group(ump)));
+
+	if (fh->meta.status_bank == SND_UMP_FLEX_DATA_MSG_BANK_SETUP &&
+	    fh->meta.status == SND_UMP_FLEX_DATA_MSG_STATUS_SET_TEMPO) {
+		printf("UMP Set Tempo          value %d\n", fh->set_tempo.tempo);
+		return;
+	}
+
+	if (fh->meta.status_bank == SND_UMP_FLEX_DATA_MSG_BANK_SETUP &&
+	    fh->meta.status == SND_UMP_FLEX_DATA_MSG_STATUS_SET_TIME_SIGNATURE) {
+		printf("UMP Set Time Signature value %d / %d, num_notes %d\n",
+		       fh->set_time_sig.numerator, fh->set_time_sig.denominator,
+		       fh->set_time_sig.num_notes);
+		return;
+	}
+
+	if (fh->meta.status_bank == SND_UMP_FLEX_DATA_MSG_BANK_SETUP &&
+	    fh->meta.status == SND_UMP_FLEX_DATA_MSG_STATUS_SET_METRONOME) {
+		printf("UMP Set Metronome      clock %d, bar %d/%d/%d, sub %d/%d\n",
+		       fh->set_metronome.clocks_primary,
+		       fh->set_metronome.bar_accent_1,
+		       fh->set_metronome.bar_accent_2,
+		       fh->set_metronome.bar_accent_3,
+		       fh->set_metronome.subdivision_1,
+		       fh->set_metronome.subdivision_2);
+		return;
+	}
+
+	if (fh->meta.status_bank == SND_UMP_FLEX_DATA_MSG_BANK_SETUP &&
+	    fh->meta.status == SND_UMP_FLEX_DATA_MSG_STATUS_SET_CHORD_NAME) {
+		printf("UMP Set Chord Name     tonic %d %d %d, alt1 %d/%d, alt2 %d/%d, alt3 %d/%d, alt4 %d/%d, bass %d %d %d, alt1 %d/%d alt2 %d/%d\n",
+		       fh->set_chord_name.tonic_sharp,
+		       fh->set_chord_name.chord_tonic,
+		       fh->set_chord_name.chord_type,
+		       fh->set_chord_name.alter1_type,
+		       fh->set_chord_name.alter1_degree,
+		       fh->set_chord_name.alter2_type,
+		       fh->set_chord_name.alter2_degree,
+		       fh->set_chord_name.alter3_type,
+		       fh->set_chord_name.alter3_degree,
+		       fh->set_chord_name.alter4_type,
+		       fh->set_chord_name.alter4_degree,
+		       fh->set_chord_name.bass_sharp,
+		       fh->set_chord_name.bass_note,
+		       fh->set_chord_name.bass_type,
+		       fh->set_chord_name.bass_alter1_type,
+		       fh->set_chord_name.bass_alter1_type,
+		       fh->set_chord_name.bass_alter2_degree,
+		       fh->set_chord_name.bass_alter2_degree);
+		return;
+	}
+
+	if (fh->meta.status_bank == SND_UMP_FLEX_DATA_MSG_BANK_METADATA ||
+	    fh->meta.status_bank == SND_UMP_FLEX_DATA_MSG_BANK_PERF_TEXT) {
+		printf("Meta (%s) ", ump_meta_prefix(fh));
+		print_ump_string(ump + 1, fh->meta.format, 0, 12);
+		printf("\n");
+		return;
+	}
+
+	printf("Flex Data: channel = %d, format = %d, addrs = %d, status_bank = %d, status = %d\n",
+	       fh->meta.channel, fh->meta.format, fh->meta.addrs,
+	       fh->meta.status_bank, fh->meta.status);
+}
+
 static void dump_ump_event(const snd_seq_ump_event_t *ev)
 {
 	if (!snd_seq_ev_is_ump(ev)) {
@@ -730,6 +971,12 @@  static void dump_ump_event(const snd_seq_ump_event_t *ev)
 	case SND_UMP_MSG_TYPE_DATA:
 		dump_ump_sysex_event(ev->ump);
 		break;
+	case SND_UMP_MSG_TYPE_FLEX_DATA:
+		dump_ump_flex_data_event(ev->ump);
+		break;
+	case SND_UMP_MSG_TYPE_STREAM:
+		dump_ump_stream_event(ev->ump);
+		break;
 	default:
 		printf("UMP event: type = %d, group = %d, status = %d, 0x%08x\n",
 		       snd_ump_msg_type(ev->ump),