#include <unistd.h>
#include <fcntl.h>
#include <alsa/asoundlib.h>
+#include <time.h>
#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;
"-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"
/*
* 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,
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)
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'},
{"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'},
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,
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);
}
if (inputp) {
+ int need_timestamp = 0;
int read = 0;
int npfds;
struct pollfd *pfds;
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))
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));
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);
}