From 3d710ac72152eed2703dc5e785b80037345a4f73 Mon Sep 17 00:00:00 2001 From: Alexandre Ratchov Date: Wed, 18 Jan 2017 10:26:27 +0100 Subject: [PATCH] Use -io options to specify files and -q option to specify one or two ports, allowing port-to-port transfers. --- midicat/midicat.1 | 42 ++++++++---- midicat/midicat.c | 164 ++++++++++++++++++++++++++++++++++------------ 2 files changed, 153 insertions(+), 53 deletions(-) diff --git a/midicat/midicat.1 b/midicat/midicat.1 index f8eaed1..bb95e1b 100644 --- a/midicat/midicat.1 +++ b/midicat/midicat.1 @@ -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 diff --git a/midicat/midicat.c b/midicat/midicat.c index 5848276..2cc8bd7 100644 --- a/midicat/midicat.c +++ b/midicat/midicat.c @@ -18,9 +18,11 @@ #include #include #include +#include #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; }