mirror of
https://github.com/alsa-project/alsa-utils
synced 2024-10-06 08:18:00 +02:00
Compare commits
3 commits
33f6870f56
...
176c94591c
Author | SHA1 | Date | |
---|---|---|---|
|
176c94591c | ||
|
6a676f4a46 | ||
|
47931000fd |
3 changed files with 271 additions and 6 deletions
|
@ -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
|
||||||
|
|
|
@ -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_MIDI1_CHANNEL_VOICE ||
|
||||||
h->type == SND_UMP_MSG_TYPE_DATA ||
|
h->type == SND_UMP_MSG_TYPE_DATA ||
|
||||||
h->type == SND_UMP_MSG_TYPE_MIDI2_CHANNEL_VOICE) {
|
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;
|
||||||
|
|
|
@ -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),
|
||||||
|
|
Loading…
Reference in a new issue