Use -io options to specify files and -q option to specify one

or two ports, allowing port-to-port transfers.
This commit is contained in:
Alexandre Ratchov 2017-01-18 10:26:27 +01:00
parent 044421aad7
commit 3d710ac721
2 changed files with 153 additions and 53 deletions

View File

@ -24,8 +24,9 @@
.Nm midicat
.Bk -words
.Op Fl d
.Op Fl i Ar port
.Op Fl o Ar port
.Op Fl i Ar file
.Op Fl o Ar file
.Op Fl q Ar port
.Ek
.Sh DESCRIPTION
The
@ -36,21 +37,39 @@ The options are as follows:
.Bl -tag -width Ds
.It Fl d
Dump transferred data in hex on stderr.
.It Fl i Ar port
.It Fl i Ar file
Read MIDI data from this file instead of receiving it from the MIDI port.
If the option argument is
.Sq -
then standard input will be used.
.It Fl o Ar file
Write MIDI data to this file instead of sending it to the MIDI port.
If the option argument is
.Sq -
then standard output will be used.
.It Fl q Ar port
Use this
.Xr sndio 7
MIDI port as input instead of stdin.
.It Fl o Ar port
Use this
.Xr sndio 7
MIDI port as output instead of stdout.
MIDI port for input/output.
If the option is used twice, the first one specifies
the input port and the second one the output port.
.El
.Pp
If no files are specified, then
.Nm
transfers data from the MIDI input port to the MIDI output port.
.Sh EXAMPLES
Send the given file to
.Pa rmidi/0 :
.Bd -literal -offset indent
$ midicat -i file.syx -q rmidi/0
.Ed
.Pp
Dump data received from
.Pa rmidi/0
to stderr:
.Bd -literal -offset indent
$ midicat -di rmidi/0 >/dev/null
$ midicat -d -q rmidi/0 -o /dev/null
.Ed
.Pp
Send data from
@ -58,8 +77,9 @@ Send data from
to
.Pa midithru/0:
.Bd -literal -offset indent
$ midicat -i rmidi/0 -o midithru/0
$ midicat -q rmidi/0 -q midithru/0
.Ed
.Sh SEE ALSO
.Xr midi 4 ,
.Xr sndio 7
.Xr sndio 7 ,
.Xr sndiod 8

View File

@ -18,9 +18,11 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "bsd-compat.h"
char usagestr[] = "usage: midicat [-d] [-i port] [-o port]\n";
char usagestr[] = "usage: midicat [-d] [-i in-file] [-o out-file] "
"[-q in-port] [-q out-port]\n";
int
main(int argc, char **argv)
@ -28,25 +30,35 @@ main(int argc, char **argv)
#define MIDI_BUFSZ 1024
unsigned char buf[MIDI_BUFSZ];
struct mio_hdl *ih, *oh;
char *in, *out;
int dump, c, i, len, sep;
char *port0, *port1, *ifile, *ofile;
int ifd, ofd;
int dump, c, i, len, n, sep, mode;
dump = 0;
in = NULL;
out = NULL;
ih = NULL;
oh = NULL;
while ((c = getopt(argc, argv, "di:o:")) != -1) {
port0 = port1 = ifile = ofile = NULL;
ih = oh = NULL;
ifd = ofd = -1;
while ((c = getopt(argc, argv, "di:o:q:")) != -1) {
switch (c) {
case 'd':
dump = 1;
break;
case 'q':
if (port0 == NULL)
port0 = optarg;
else if (port1 == NULL)
port1 = optarg;
else {
fputs("too many -q options\n", stderr);
return 1;
}
break;
case 'i':
in = optarg;
ifile = optarg;
break;
case 'o':
out = optarg;
ofile = optarg;
break;
default:
goto bad_usage;
@ -59,44 +71,106 @@ main(int argc, char **argv)
fputs(usagestr, stderr);
return 1;
}
if (in == NULL && out == NULL) {
fputs("either -i or -o required\n", stderr);
exit(1);
/* we don't support more than one data flow */
if (ifile != NULL && ofile != NULL) {
fputs("-i and -o are exclusive\n", stderr);
return 1;
}
if (in) {
ih = mio_open(in, MIO_IN, 0);
if (ih == NULL) {
fprintf(stderr, "%s: couldn't open MIDI in\n", in);
exit(1);
}
/* second port makes sense only for port-to-port transfers */
if (port1 != NULL && !(ifile == NULL && ofile == NULL)) {
fputs("too many -q options\n", stderr);
return 1;
}
if (out) {
oh = mio_open(out, MIO_OUT, 0);
if (oh == NULL) {
fprintf(stderr, "%s: couldn't open MIDI out\n", out);
exit(1);
}
}
for (;;) {
if (in) {
len = mio_read(ih, buf, sizeof(buf));
if (len == 0) {
fprintf(stderr, "%s: disconnected\n", in);
break;
/* if there're neither files nor ports, then we've nothing to do */
if (port0 == NULL && ifile == NULL && ofile == NULL)
goto bad_usage;
/* if no port specified, use default one */
if (port0 == NULL)
port0 = MIO_PORTANY;
/* open input or output file (if any) */
if (ifile) {
if (strcmp(ifile, "-") == 0)
ifd = STDIN_FILENO;
else {
ifd = open(ifile, O_RDONLY, 0);
if (ifd < 0) {
perror(ifile);
return 1;
}
} else {
len = read(STDIN_FILENO, buf, sizeof(buf));
}
} else if (ofile) {
if (strcmp(ofile, "-") == 0)
ofd = STDOUT_FILENO;
else {
ofd = open(ofile, O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (ofd < 0) {
perror(ofile);
return 1;
}
}
}
/* open first port for input and output (if output needed) */
if (ofile)
mode = MIO_IN;
else if (ifile)
mode = MIO_OUT;
else if (port1 == NULL)
mode = MIO_IN | MIO_OUT;
else
mode = MIO_IN;
ih = mio_open(port0, mode, 0);
if (ih == NULL) {
fprintf(stderr, "%s: couldn't open port\n", port0);
return 1;
}
/* open second port, output only */
if (port1 == NULL)
oh = ih;
else {
oh = mio_open(port1, MIO_OUT, 0);
if (oh == NULL) {
fprintf(stderr, "%s: couldn't open port\n", port1);
exit(1);
}
}
/* transfer until end-of-file or error */
for (;;) {
if (ifile != NULL) {
len = read(ifd, buf, sizeof(buf));
if (len == 0)
break;
if (len < 0) {
perror("stdin");
exit(1);
break;
}
} else {
len = mio_read(ih, buf, sizeof(buf));
if (len == 0) {
fprintf(stderr, "%s: disconnected\n", port0);
break;
}
}
if (ofile != NULL) {
n = write(ofd, buf, len);
if (n != len) {
fprintf(stderr, "%s: short write\n", ofile);
break;
}
} else {
n = mio_write(oh, buf, len);
if (n != len) {
fprintf(stderr, "%s: disconnected\n", port1);
break;
}
}
if (out)
mio_write(oh, buf, len);
else
write(STDOUT_FILENO, buf, len);
if (dump) {
for (i = 0; i < len; i++) {
sep = (i % 16 == 15 || i == len - 1) ?
@ -105,9 +179,15 @@ main(int argc, char **argv)
}
}
}
if (in)
/* clean-up */
if (port0)
mio_close(ih);
if (out)
if (port1)
mio_close(oh);
if (ifile)
close(ifd);
if (ofile)
close(ofd);
return 0;
}