Compare commits

...

3 commits

Author SHA1 Message Date
Takashi Iwai
176c94591c aseqdump: Support of UMP Stream and Flex Data message types
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>
2024-07-19 14:29:00 +02:00
Takashi Iwai
6a676f4a46 aplaymidi2: Add -a option to pass all UMP packets
So far, aplaymidi2 passes the MIDI1/MIDI2 channel voice UMP messages
to the target while processing other UMP messages internally.  But
sometimes we'd like to pass all UMP messages as is and let the
receiver processes.

This patch adds a new option -a (or --passall) to pass the all UMP
packets included in the given MIDI Clip file to the target as-is.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
2024-07-19 14:28:44 +02:00
Takashi Iwai
47931000fd aplaymidi2: Fix --silent option handling
The --silent option takes no argument.  Correct the wrong setup.

Fixes: b1269eefdd ("aplaymidi2: Add --silent option")
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2024-07-19 14:27:15 +02:00
3 changed files with 271 additions and 6 deletions

View file

@ -67,6 +67,14 @@ Default is 2 seconds.
.I \-s, \-\-silent .I \-s, \-\-silent
Don't show message texts. Don't show message texts.
.TP
.I \-a, \-\-passall
Pass all UMP packets as is.
As default, \fBaplaymidi2\fP passes only MIDI1 and MIDI2 channel voice
messages and process other UMP packets internally.
With this option, it passes all UMP packets to the target.
.SH SEE ALSO .SH SEE ALSO
pmidi(1) pmidi(1)
.br .br

View file

@ -21,6 +21,7 @@ static snd_seq_addr_t ports[16];
static int queue; static int queue;
static int end_delay = 2; static int end_delay = 2;
static int silent; static int silent;
static int passall;
static unsigned int _current_tempo = 50000000; /* default 120 bpm */ static unsigned int _current_tempo = 50000000; /* default 120 bpm */
static unsigned int tempo_base = 10; static unsigned int tempo_base = 10;
@ -411,6 +412,9 @@ static void play_midi(FILE *file)
while ((len = read_ump_packet(file, ump)) > 0) { while ((len = read_ump_packet(file, ump)) > 0) {
const snd_ump_msg_hdr_t *h = (snd_ump_msg_hdr_t *)ump; const snd_ump_msg_hdr_t *h = (snd_ump_msg_hdr_t *)ump;
if (passall)
send_ump(ump, len);
if (h->type == SND_UMP_MSG_TYPE_UTILITY) { if (h->type == SND_UMP_MSG_TYPE_UTILITY) {
const snd_ump_msg_utility_t *uh = const snd_ump_msg_utility_t *uh =
(const snd_ump_msg_utility_t *)ump; (const snd_ump_msg_utility_t *)ump;
@ -448,9 +452,10 @@ static void play_midi(FILE *file)
end_clip(); end_clip();
continue; continue;
} }
} else if (h->type == SND_UMP_MSG_TYPE_MIDI1_CHANNEL_VOICE || } else if (!passall &&
h->type == SND_UMP_MSG_TYPE_DATA || (h->type == SND_UMP_MSG_TYPE_MIDI1_CHANNEL_VOICE ||
h->type == SND_UMP_MSG_TYPE_MIDI2_CHANNEL_VOICE) { h->type == SND_UMP_MSG_TYPE_DATA ||
h->type == SND_UMP_MSG_TYPE_MIDI2_CHANNEL_VOICE)) {
send_ump(ump, len); send_ump(ump, len);
} }
} }
@ -496,7 +501,8 @@ static void usage(const char *argv0)
"-V, --version print current version\n" "-V, --version print current version\n"
"-p, --port=client:port,... set port(s) to play to\n" "-p, --port=client:port,... set port(s) to play to\n"
"-d, --delay=seconds delay after song ends\n" "-d, --delay=seconds delay after song ends\n"
"-s, --silent don't show texts\n", "-s, --silent don't show texts\n"
"-a, --passall pass all UMP packets as-is\n",
argv0); argv0);
} }
@ -512,14 +518,15 @@ int main(int argc, char *argv[])
{"version", 0, NULL, 'V'}, {"version", 0, NULL, 'V'},
{"port", 1, NULL, 'p'}, {"port", 1, NULL, 'p'},
{"delay", 1, NULL, 'd'}, {"delay", 1, NULL, 'd'},
{"silent", 1, NULL, 's'}, {"silent", 0, NULL, 's'},
{"passall", 0, NULL, 'a'},
{0} {0}
}; };
int c; int c;
init_seq(); init_seq();
while ((c = getopt_long(argc, argv, "hVp:d:s", while ((c = getopt_long(argc, argv, "hVp:d:sa",
long_options, NULL)) != -1) { long_options, NULL)) != -1) {
switch (c) { switch (c) {
case 'h': case 'h':
@ -537,6 +544,9 @@ int main(int argc, char *argv[])
case 's': case 's':
silent = 1; silent = 1;
break; break;
case 'a':
passall = 1;
break;
default: default:
usage(argv[0]); usage(argv[0]);
return 1; return 1;

View file

@ -705,6 +705,247 @@ static void dump_ump_sysex_event(const unsigned int *ump)
printf("\n"); 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) static void dump_ump_event(const snd_seq_ump_event_t *ev)
{ {
if (!snd_seq_ev_is_ump(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: case SND_UMP_MSG_TYPE_DATA:
dump_ump_sysex_event(ev->ump); dump_ump_sysex_event(ev->ump);
break; 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: default:
printf("UMP event: type = %d, group = %d, status = %d, 0x%08x\n", printf("UMP event: type = %d, group = %d, status = %d, 0x%08x\n",
snd_ump_msg_type(ev->ump), snd_ump_msg_type(ev->ump),