diff --git a/example-clients/midi_dump.c b/example-clients/midi_dump.c index 451c8262..3785a445 100644 --- a/example-clients/midi_dump.c +++ b/example-clients/midi_dump.c @@ -1,51 +1,65 @@ +// gcc -o jack_midi_dump -Wall midi_dump.c -ljack -pthread + #include #include #include #include #include #include +#include #ifndef WIN32 #include +#include +#include +#endif + +#ifndef MAX +#define MAX(a,b) ( (a) < (b) ? (b) : (a) ) #endif static jack_port_t* port; +static jack_ringbuffer_t *rb = NULL; +static pthread_mutex_t msg_thread_lock = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t data_ready = PTHREAD_COND_INITIALIZER; static int keeprunning = 1; -static int time_format = 0; - static uint64_t monotonic_cnt = 0; -static uint64_t prev_event = 0; -static void -describe (jack_midi_event_t* event, char* buffer, size_t buflen) -{ - assert (buflen > 0); +#define RBSIZE 512 - buffer[0] = '\0'; +typedef struct { + uint8_t buffer[128]; + uint32_t size; + uint32_t tme_rel; + uint64_t tme_mon; +} midimsg; +static void +describe (midimsg* event) +{ if (event->size == 0) { return; } - int type = event->buffer[0] & 0xf0; - int channel = event->buffer[0] & 0xf; + uint8_t type = event->buffer[0] & 0xf0; + uint8_t channel = event->buffer[0] & 0xf; switch (type) { - case 0x90: - assert (event->size == 3); - snprintf (buffer, buflen, "note on (channel %d): pitch %d, velocity %d", channel, event->buffer[1], event->buffer[2]); - break; - case 0x80: - assert (event->size == 3); - snprintf (buffer, buflen, "note off (channel %d): pitch %d, velocity %d", channel, event->buffer[1], event->buffer[2]); - break; - case 0xb0: - assert (event->size == 3); - snprintf (buffer, buflen, "control change (channel %d): controller %d, value %d", channel, event->buffer[1], event->buffer[2]); - break; - default: - break; + case 0x90: + assert (event->size == 3); + printf (" note on (channel %2d): pitch %3d, velocity %3d", channel, event->buffer[1], event->buffer[2]); + break; + case 0x80: + assert (event->size == 3); + printf (" note off (channel %2d): pitch %3d, velocity %3d", channel, event->buffer[1], event->buffer[2]); + break; + case 0xb0: + assert (event->size == 3); + printf (" control change (channel %2d): controller %3d, value %3d", channel, event->buffer[1], event->buffer[2]); + break; + default: + break; } } @@ -55,7 +69,6 @@ process (jack_nframes_t frames, void* arg) void* buffer; jack_nframes_t N; jack_nframes_t i; - char description[256]; buffer = jack_port_get_buffer (port, frames); assert (buffer); @@ -66,34 +79,25 @@ process (jack_nframes_t frames, void* arg) int r; r = jack_midi_event_get (&event, buffer, i); - if (r == 0) { - size_t j; - switch(time_format) { - case 1: - printf ("%7"PRId64":", event.time + monotonic_cnt); - break; - case 2: - printf ("%+6"PRId64":", event.time + monotonic_cnt - prev_event); - break; - default: - printf ("%4d:", event.time); - break; - } - for (j = 0; j < event.size; ++j) { - printf (" %x", event.buffer[j]); - } - - describe (&event, description, sizeof (description)); - printf (" %s", description); + if (r == 0 && jack_ringbuffer_write_space (rb) >= sizeof(midimsg)) { + midimsg m; + m.tme_mon = monotonic_cnt; + m.tme_rel = event.time; + m.size = event.size; + memcpy (m.buffer, event.buffer, MAX(sizeof(m.buffer), event.size)); + jack_ringbuffer_write (rb, (void *) &m, sizeof(midimsg)); - printf ("\n"); - prev_event = event.time + monotonic_cnt; } } monotonic_cnt += frames; + if (pthread_mutex_trylock (&msg_thread_lock) == 0) { + pthread_cond_signal (&data_ready); + pthread_mutex_unlock (&msg_thread_lock); + } + return 0; } @@ -113,14 +117,11 @@ static void usage (int status) { This tool listens for MIDI events on a JACK MIDI port and prints\n\ the message to stdout.\n\ \n\ -Note that this tool is not realtime-safe. The events are printed\n\ -directly from the process() callback!\n\ -\n\ If no client name is given it defaults to 'midi-monitor'.\n\ \n\ See also: jackd(1)\n\ \n"); - exit (status); + exit (status); } int @@ -129,6 +130,7 @@ main (int argc, char* argv[]) jack_client_t* client; char const default_name[] = "midi-monitor"; char const * client_name; + int time_format = 0; int r; int cn = 1; @@ -152,6 +154,8 @@ main (int argc, char* argv[]) exit (EXIT_FAILURE); } + rb = jack_ringbuffer_create (RBSIZE * sizeof(midimsg)); + jack_set_process_callback (client, process, 0); port = jack_port_register (client, "input", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0); @@ -160,6 +164,12 @@ main (int argc, char* argv[]) exit (EXIT_FAILURE); } +#ifndef WIN32 + if (mlockall (MCL_CURRENT | MCL_FUTURE)) { + fprintf (stderr, "Warning: Can not lock memory.\n"); + } +#endif + r = jack_activate (client); if (r != 0) { fprintf (stderr, "Could not activate client.\n"); @@ -171,17 +181,44 @@ main (int argc, char* argv[]) signal(SIGINT, wearedone); #endif - /* run until interrupted */ + pthread_mutex_lock (&msg_thread_lock); + + uint64_t prev_event = 0; while (keeprunning) { - #ifdef WIN32 - Sleep(1000); - #else - sleep(1); - #endif - }; + const int mqlen = jack_ringbuffer_read_space (rb) / sizeof(midimsg); + int i; + for (i=0; i < mqlen; ++i) { + size_t j; + midimsg m; + jack_ringbuffer_read(rb, (char*) &m, sizeof(midimsg)); + + switch(time_format) { + case 1: + printf ("%7"PRId64":", m.tme_rel + m.tme_mon); + break; + case 2: + printf ("%+6"PRId64":", m.tme_rel + m.tme_mon - prev_event); + break; + default: + printf ("%4d:", m.tme_rel); + break; + } + for (j = 0; j < m.size && j < sizeof(m.buffer); ++j) { + printf (" %02x", m.buffer[j]); + } + + describe (&m); + printf("\n"); + prev_event = m.tme_rel + m.tme_mon; + } + fflush (stdout); + pthread_cond_wait (&data_ready, &msg_thread_lock); + } + pthread_mutex_unlock (&msg_thread_lock); jack_deactivate (client); jack_client_close (client); + jack_ringbuffer_free (rb); return 0; }