Compare commits

...

4 commits

Author SHA1 Message Date
Takashi Iwai
274f1b9ebf arecordmidi2: Add --profile option
Allow to add arbitrary profile UMP data to be put into the
configuration of the recorded stream via --profile option.
The file must contain valid UMP data encoded in big-endian.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
2024-07-09 08:09:45 +02:00
Takashi Iwai
f0df4b4cfe arecordmidi2: Add stdout output and --silent option
When the output file is '-', it's recorded to stdout.

For avoiding the corruption, this mode also suppresses the messages to
stdout, too, which can be enabled also via -s / --silent option.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
2024-07-09 08:03:27 +02:00
Takashi Iwai
b1269eefdd aplaymidi2: Add --silent option
For suppressing the messages, add -s / --silent option.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
2024-07-09 07:48:05 +02:00
Takashi Iwai
99ce4b1d8a Revert "arecordmidi2: Correct the MIDI FB direction"
This reverts commit e609d66807.

It turned out that the failure was rather in alsa-lib API; the
input and output have been incorrectly implemented.
Now that the alsa-lib code got fixed, let's revert the bad fix.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
2024-07-09 07:32:52 +02:00
4 changed files with 109 additions and 19 deletions

View file

@ -44,8 +44,9 @@ environment variable if none is given on the command line.
.B aplaymidi2 .B aplaymidi2
supports only basic UMP events: in addition to the standard MIDI1 and supports only basic UMP events: in addition to the standard MIDI1 and
MIDI2 CVMs and 7bit SysEx, only the following are supported: MIDI2 CVMs and 7bit SysEx, only the following are supported:
DCTPQ, DC, Set Tempo, Start Clip and End Clip. DCTPQ, DC, Set Tempo, Start Clip, End Clip.
Lyrics and other meta data in Flex Data are skipped, so far. Lyrics and other meta data in Flex Data are printed, too, unless
\fI\-s\fP option is given.
The multiple output ports are useful when the given MIDI Clip file The multiple output ports are useful when the given MIDI Clip file
contains the UMP packets for multiple Groups. contains the UMP packets for multiple Groups.
@ -62,6 +63,10 @@ Specifies how long to wait after the end of each MIDI Clip file,
to allow the last notes to die away. to allow the last notes to die away.
Default is 2 seconds. Default is 2 seconds.
.TP
.I \-s, \-\-silent
Don't show message texts.
.SH SEE ALSO .SH SEE ALSO
pmidi(1) pmidi(1)
.br .br

View file

@ -20,6 +20,7 @@ static int port_count;
static snd_seq_addr_t ports[16]; 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 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;
@ -432,7 +433,8 @@ static void play_midi(FILE *file)
if (fh->meta.status_bank == SND_UMP_FLEX_DATA_MSG_BANK_METADATA || if (fh->meta.status_bank == SND_UMP_FLEX_DATA_MSG_BANK_METADATA ||
fh->meta.status_bank == SND_UMP_FLEX_DATA_MSG_BANK_PERF_TEXT) { fh->meta.status_bank == SND_UMP_FLEX_DATA_MSG_BANK_PERF_TEXT) {
show_text(ump); if (!silent)
show_text(ump);
continue; continue;
} }
} else if (h->type == SND_UMP_MSG_TYPE_STREAM) { } else if (h->type == SND_UMP_MSG_TYPE_STREAM) {
@ -493,7 +495,8 @@ static void usage(const char *argv0)
"-h, --help this help\n" "-h, --help this help\n"
"-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",
argv0); argv0);
} }
@ -509,13 +512,14 @@ 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'},
{0} {0}
}; };
int c; int c;
init_seq(); init_seq();
while ((c = getopt_long(argc, argv, "hVp:d:", while ((c = getopt_long(argc, argv, "hVp:d:s",
long_options, NULL)) != -1) { long_options, NULL)) != -1) {
switch (c) { switch (c) {
case 'h': case 'h':
@ -530,6 +534,9 @@ int main(int argc, char *argv[])
case 'd': case 'd':
end_delay = atoi(optarg); end_delay = atoi(optarg);
break; break;
case 's':
silent = 1;
break;
default: default:
usage(argv[0]); usage(argv[0]);
return 1; return 1;

View file

@ -14,6 +14,9 @@ more ALSA sequencer ports.
To stop recording, press Ctrl+C. To stop recording, press Ctrl+C.
When \fB\-\fP is passed to the MIDI Clip file argument,
it's recorded to stdout. It implies \fI\-s\fP option, too.
.SH OPTIONS .SH OPTIONS
.TP .TP
@ -80,6 +83,16 @@ the recording ends when another RETURN key is input from the
terminal. The received events before the start of recording are terminal. The received events before the start of recording are
discarded. discarded.
.TP
.I \-s,\-\-silent
Don't print messages to stdout.
.TP
.I \-P,\-\-profile=file
Read the UMP data from the given file and put them into the
configuration section of the recorded output.
The file must contain only valid UMP data encoded in big-endian.
.SH SEE ALSO .SH SEE ALSO
arecordmidi(1) arecordmidi(1)
.br .br

View file

@ -26,6 +26,8 @@ static volatile sig_atomic_t stop;
static int ts_num = 4; /* time signature: numerator */ static int ts_num = 4; /* time signature: numerator */
static int ts_div = 4; /* time signature: denominator */ static int ts_div = 4; /* time signature: denominator */
static int last_tick; static int last_tick;
static int silent;
static const char *profile_ump_file;
/* Parse a decimal number from a command line argument. */ /* Parse a decimal number from a command line argument. */
static long arg_parse_decimal_num(const char *str, int *err) static long arg_parse_decimal_num(const char *str, int *err)
@ -124,7 +126,7 @@ static void create_ump_client(void)
sprintf(blkname, "Group %d", i + 1); sprintf(blkname, "Group %d", i + 1);
snd_ump_block_info_set_name(blk, blkname); snd_ump_block_info_set_name(blk, blkname);
snd_ump_block_info_set_direction(blk, SND_UMP_DIR_OUTPUT); snd_ump_block_info_set_direction(blk, SND_UMP_DIR_INPUT);
snd_ump_block_info_set_first_group(blk, i); snd_ump_block_info_set_first_group(blk, i);
snd_ump_block_info_set_num_groups(blk, 1); snd_ump_block_info_set_num_groups(blk, 1);
snd_ump_block_info_set_ui_hint(blk, SND_UMP_BLOCK_UI_HINT_RECEIVER); snd_ump_block_info_set_ui_hint(blk, SND_UMP_BLOCK_UI_HINT_RECEIVER);
@ -336,6 +338,47 @@ static void record_event(FILE *file, const snd_seq_ump_event_t *ev)
write_ump(file, ev->ump); write_ump(file, ev->ump);
} }
/* read a UMP raw (big-endian) packet, return the packet length in words */
static int read_ump_raw(FILE *file, uint32_t *buf)
{
uint32_t v;
int i, num;
if (fread(buf, 4, 1, file) != 1)
return 0;
v = be32toh(v);
num = snd_ump_packet_length(snd_ump_msg_hdr_type(v));
for (i = 1; i < num; i++) {
if (fread(buf + i, 4, 1, file) != 1)
return 0;
}
return num;
}
/* read the profile UMP data and write to the configuration */
static void write_profiles(FILE *file)
{
FILE *fp;
uint32_t ump[4];
int len;
if (!profile_ump_file)
return;
fp = fopen(profile_ump_file, "rb");
if (!fp)
fatal("cannot open the profile '%s'", profile_ump_file);
while (!feof(fp)) {
len = read_ump_raw(fp, ump);
if (!len)
break;
fwrite(ump, 4, len, file);
}
fclose(fp);
}
/* write MIDI Clip file header and the configuration packets */ /* write MIDI Clip file header and the configuration packets */
static void write_file_header(FILE *file) static void write_file_header(FILE *file)
{ {
@ -343,7 +386,7 @@ static void write_file_header(FILE *file)
fwrite("SMF2CLIP", 1, 8, file); fwrite("SMF2CLIP", 1, 8, file);
/* clip configuration header */ /* clip configuration header */
/* FIXME: add profiles */ write_profiles(file);
/* first DCS */ /* first DCS */
write_dcs(file, 0); write_dcs(file, 0);
@ -377,7 +420,9 @@ static void help(const char *argv0)
" -i,--timesig=nn:dd time signature\n" " -i,--timesig=nn:dd time signature\n"
" -n,--num-events=events fixed number of events to record, then exit\n" " -n,--num-events=events fixed number of events to record, then exit\n"
" -u,--ump=version UMP MIDI version (1 or 2)\n" " -u,--ump=version UMP MIDI version (1 or 2)\n"
" -r,--interactive Interactive mode\n", " -r,--interactive Interactive mode\n"
" -s,--silent don't print messages\n"
" -P,--profile=file configuration profile UMP\n",
argv0); argv0);
} }
@ -393,7 +438,7 @@ static void sighandler(int sig ATTRIBUTE_UNUSED)
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
static const char short_options[] = "hVp:b:t:n:u:r"; static const char short_options[] = "hVp:b:t:n:u:rsP:";
static const struct option long_options[] = { static const struct option long_options[] = {
{"help", 0, NULL, 'h'}, {"help", 0, NULL, 'h'},
{"version", 0, NULL, 'V'}, {"version", 0, NULL, 'V'},
@ -404,6 +449,8 @@ int main(int argc, char *argv[])
{"num-events", 1, NULL, 'n'}, {"num-events", 1, NULL, 'n'},
{"ump", 1, NULL, 'u'}, {"ump", 1, NULL, 'u'},
{"interactive", 0, NULL, 'r'}, {"interactive", 0, NULL, 'r'},
{"silent", 0, NULL, 's'},
{"profile", 1, NULL, 'P'},
{0} {0}
}; };
@ -463,6 +510,12 @@ int main(int argc, char *argv[])
case 'r': case 'r':
interactive = 1; interactive = 1;
break; break;
case 's':
silent = 1;
break;
case 'P':
profile_ump_file = optarg;
break;
default: default:
help(argv[0]); help(argv[0]);
return 1; return 1;
@ -481,14 +534,21 @@ int main(int argc, char *argv[])
filename = argv[optind]; filename = argv[optind];
file = fopen(filename, "wb"); if (!strcmp(filename, "-")) {
if (!file) file = stdout;
fatal("Cannot open %s - %s", filename, strerror(errno)); silent = 1; // imply silent mode
} else {
file = fopen(filename, "wb");
if (!file)
fatal("Cannot open %s - %s", filename, strerror(errno));
}
write_file_header(file); write_file_header(file);
if (interactive) { if (interactive) {
printf("Press RETURN to start recording:"); if (!silent) {
fflush(stdout); printf("Press RETURN to start recording:");
fflush(stdout);
}
} else { } else {
start_bar(file); start_bar(file);
start = 1; start = 1;
@ -515,8 +575,10 @@ int main(int argc, char *argv[])
if (!start) { if (!start) {
start_bar(file); start_bar(file);
start = 1; start = 1;
printf("Press RETURN to stop recording:"); if (!silent) {
fflush(stdout); printf("Press RETURN to stop recording:");
fflush(stdout);
}
continue; continue;
} else { } else {
stop = 1; stop = 1;
@ -544,11 +606,14 @@ int main(int argc, char *argv[])
break; break;
} }
if (num_events && events_received < num_events) if (num_events && events_received < num_events) {
fputs("Warning: Received signal before num_events\n", stdout); if (!silent)
fputs("Warning: Received signal before num_events\n", stdout);
}
write_end_clip(file); write_end_clip(file);
fclose(file); if (file != stdout)
fclose(file);
snd_seq_close(seq); snd_seq_close(seq);
return 0; return 0;
} }