diff --git a/amidi/amidi.c b/amidi/amidi.c index 90e7750..8e97cb8 100644 --- a/amidi/amidi.c +++ b/amidi/amidi.c @@ -36,11 +36,13 @@ #include #include #include +#include #include "aconfig.h" #include "version.h" #define NSEC_PER_SEC 1000000000L +static int do_print_timestamp = 0; static int do_device_list, do_rawmidi_list; static char *port_name = "default"; static char *send_file_name; @@ -80,6 +82,10 @@ static void usage(void) "-r, --receive=file write received data into a file\n" "-S, --send-hex=\"...\" send hexadecimal bytes\n" "-d, --dump print received data as hexadecimal bytes\n" + "-T, --timestamp=... adds a timestamp in front of each dumped message\n" + " realtime\n" + " monotonic\n" + " raw\n" "-t, --timeout=seconds exits when no data has been received\n" " for the specified duration\n" "-a, --active-sensing include active sensing bytes\n" @@ -356,7 +362,7 @@ static void parse_data(void) /* * prints MIDI commands, formatting them nicely */ -static void print_byte(unsigned char byte) +static void print_byte(unsigned char byte, struct timespec *ts) { static enum { STATE_UNKNOWN, @@ -426,7 +432,18 @@ static void print_byte(unsigned char byte) if (running_status) fputs("\n ", stdout); } - printf("%c%02X", newline ? '\n' : ' ', byte); + + if (newline) { + printf("\n"); + + /* Nanoseconds does not make a lot of sense for serial MIDI (the + * 31250 bps one) but I'm not sure about MIDI over USB. + */ + if (do_print_timestamp) + printf("%lld.%.9ld) ", (long long)ts->tv_sec, ts->tv_nsec); + } + + printf("%02X", byte); } static void sig_handler(int dummy) @@ -454,7 +471,7 @@ static void add_send_hex_data(const char *str) int main(int argc, char *argv[]) { - static const char short_options[] = "hVlLp:s:r:S::dt:aci:"; + static const char short_options[] = "hVlLp:s:r:S::dt:aci:T:"; static const struct option long_options[] = { {"help", 0, NULL, 'h'}, {"version", 0, NULL, 'V'}, @@ -465,6 +482,7 @@ int main(int argc, char *argv[]) {"receive", 1, NULL, 'r'}, {"send-hex", 2, NULL, 'S'}, {"dump", 0, NULL, 'd'}, + {"timestamp", 1, NULL, 'T'}, {"timeout", 1, NULL, 't'}, {"active-sensing", 0, NULL, 'a'}, {"clock", 0, NULL, 'c'}, @@ -475,6 +493,7 @@ int main(int argc, char *argv[]) int ignore_active_sensing = 1; int ignore_clock = 1; int do_send_hex = 0; + clockid_t cid = CLOCK_REALTIME; struct itimerspec itimerspec = { .it_interval = { 0, 0 } }; while ((c = getopt_long(argc, argv, short_options, @@ -509,6 +528,19 @@ int main(int argc, char *argv[]) case 'd': dump = 1; break; + case 'T': + do_print_timestamp = 1; + if (optarg == NULL) + error("Clock type missing"); + else if (strcasecmp(optarg, "realtime") == 0) + cid = CLOCK_REALTIME; + else if (strcasecmp(optarg, "monotonic") == 0) + cid = CLOCK_MONOTONIC; + else if (strcasecmp(optarg, "raw") == 0) + cid = CLOCK_MONOTONIC_RAW; + else + error("Clock type not known"); + break; case 't': if (optarg) timeout = atof(optarg); @@ -611,6 +643,7 @@ int main(int argc, char *argv[]) } if (inputp) { + int need_timestamp = 0; int read = 0; int npfds; struct pollfd *pfds; @@ -644,10 +677,12 @@ int main(int argc, char *argv[]) goto _exit; } } + for (;;) { unsigned char buf[256]; int i, length; unsigned short revents; + struct timespec ts; err = poll(pfds, npfds, -1); if (stop || (err < 0 && errno == EINTR)) @@ -657,6 +692,11 @@ int main(int argc, char *argv[]) break; } + if (clock_gettime(cid, &ts) < 0) { + error("clock_getres (%d) failed: %s", cid, strerror(errno)); + break; + } + err = snd_rawmidi_poll_descriptors_revents(input, &pfds[1], npfds - 1, &revents); if (err < 0) { error("cannot get poll events: %s", snd_strerror(errno)); @@ -688,14 +728,12 @@ int main(int argc, char *argv[]) continue; read += length; - if (receive_file != -1) { - ssize_t wlength = write(receive_file, buf, length); - if (wlength != length) - error("write error: %s", wlength < 0 ? strerror(errno) : "short"); - } + if (receive_file != -1) + write(receive_file, buf, length); if (dump) { for (i = 0; i < length; ++i) - print_byte(buf[i]); + print_byte(buf[i], &ts); + fflush(stdout); }