1 // gcc -o jack_midi_dump -Wall midi_dump.c -ljack -pthread
9 #include <jack/midiport.h>
10 #include <jack/ringbuffer.h>
22 static jack_port_t
* port
;
23 static jack_ringbuffer_t
*rb
= NULL
;
24 static pthread_mutex_t msg_thread_lock
= PTHREAD_MUTEX_INITIALIZER
;
25 static pthread_cond_t data_ready
= PTHREAD_COND_INITIALIZER
;
27 static int keeprunning
= 1;
28 static uint64_t monotonic_cnt
= 0;
31 #define MSG_BUFFER_SIZE 4096
34 uint8_t buffer
[MSG_BUFFER_SIZE
];
41 describe (midimsg
* event
)
43 if (event
->size
== 0) {
47 uint8_t type
= event
->buffer
[0] & 0xf0;
48 uint8_t channel
= event
->buffer
[0] & 0xf;
52 assert (event
->size
== 3);
53 printf (" note on (channel %2d): pitch %3d, velocity %3d", channel
, event
->buffer
[1], event
->buffer
[2]);
56 assert (event
->size
== 3);
57 printf (" note off (channel %2d): pitch %3d, velocity %3d", channel
, event
->buffer
[1], event
->buffer
[2]);
60 assert (event
->size
== 3);
61 printf (" control change (channel %2d): controller %3d, value %3d", channel
, event
->buffer
[1], event
->buffer
[2]);
69 process (jack_nframes_t frames
, void* arg
)
75 buffer
= jack_port_get_buffer (port
, frames
);
78 N
= jack_midi_get_event_count (buffer
);
79 for (i
= 0; i
< N
; ++i
) {
80 jack_midi_event_t event
;
82 r
= jack_midi_event_get (&event
, buffer
, i
);
84 if (r
!= 0) {continue;}
86 if (event
.size
> MSG_BUFFER_SIZE
) {
87 fprintf(stderr
, "Error: MIDI message was too large, skipping event. Max. allowed size: %d bytes\n", MSG_BUFFER_SIZE
);
89 else if (jack_ringbuffer_write_space (rb
) >= sizeof(midimsg
)) {
91 m
.tme_mon
= monotonic_cnt
;
92 m
.tme_rel
= event
.time
;
94 memcpy (m
.buffer
, event
.buffer
, event
.size
);
95 jack_ringbuffer_write (rb
, (void *) &m
, sizeof(midimsg
));
98 fprintf (stderr
, "Error: ringbuffer was full, skipping event.\n");
102 monotonic_cnt
+= frames
;
104 if (pthread_mutex_trylock (&msg_thread_lock
) == 0) {
105 pthread_cond_signal (&data_ready
);
106 pthread_mutex_unlock (&msg_thread_lock
);
112 static void wearedone(int sig
) {
113 fprintf(stderr
, "Shutting down\n");
115 /* main loop might be blocked by data_ready when jack server dies. */
116 if (pthread_mutex_trylock (&msg_thread_lock
) == 0) {
117 pthread_cond_signal (&data_ready
);
118 pthread_mutex_unlock (&msg_thread_lock
);
122 static void usage (int status
) {
123 printf ("jack_midi_dump - JACK MIDI Monitor.\n\n");
124 printf ("Usage: jack_midi_dump [ OPTIONS ] [CLIENT-NAME]\n\n");
126 -a use absolute timestamps relative to application start\n\
127 -h display this help and exit\n\
128 -r use relative timestamps to previous MIDI event\n\
131 This tool listens for MIDI events on a JACK MIDI port and prints\n\
132 the message to stdout.\n\
134 If no client name is given it defaults to 'midi-monitor'.\n\
136 See also: jackd(1)\n\
142 main (int argc
, char* argv
[])
144 jack_client_t
* client
;
145 char const default_name
[] = "midi-monitor";
146 char const * client_name
;
153 if (!strcmp (argv
[1], "-a")) { time_format
= 1; cn
= 2; }
154 else if (!strcmp (argv
[1], "-r")) { time_format
= 2; cn
= 2; }
155 else if (!strcmp (argv
[1], "-h")) { usage (EXIT_SUCCESS
); }
156 else if (argv
[1][0] == '-') { usage (EXIT_FAILURE
); }
160 client_name
= argv
[cn
];
162 client_name
= default_name
;
165 client
= jack_client_open (client_name
, JackNullOption
, NULL
);
166 if (client
== NULL
) {
167 fprintf (stderr
, "Could not create JACK client.\n");
171 rb
= jack_ringbuffer_create (RBSIZE
* sizeof(midimsg
));
173 jack_set_process_callback (client
, process
, 0);
175 port
= jack_port_register (client
, "input", JACK_DEFAULT_MIDI_TYPE
, JackPortIsInput
, 0);
177 fprintf (stderr
, "Could not register port.\n");
182 if (mlockall (MCL_CURRENT
| MCL_FUTURE
)) {
183 fprintf (stderr
, "Warning: Can not lock memory.\n");
187 r
= jack_activate (client
);
189 fprintf (stderr
, "Could not activate client.\n");
194 signal(SIGHUP
, wearedone
);
195 signal(SIGINT
, wearedone
);
198 pthread_mutex_lock (&msg_thread_lock
);
200 uint64_t prev_event
= 0;
201 while (keeprunning
) {
202 const int mqlen
= jack_ringbuffer_read_space (rb
) / sizeof(midimsg
);
204 for (i
=0; i
< mqlen
; ++i
) {
207 jack_ringbuffer_read(rb
, (char*) &m
, sizeof(midimsg
));
209 switch(time_format
) {
211 printf ("%7"PRId64
":", m
.tme_rel
+ m
.tme_mon
);
214 printf ("%+6"PRId64
":", m
.tme_rel
+ m
.tme_mon
- prev_event
);
217 printf ("%4d:", m
.tme_rel
);
220 for (j
= 0; j
< m
.size
&& j
< sizeof(m
.buffer
); ++j
) {
221 printf (" %02x", m
.buffer
[j
]);
226 prev_event
= m
.tme_rel
+ m
.tme_mon
;
229 pthread_cond_wait (&data_ready
, &msg_thread_lock
);
231 pthread_mutex_unlock (&msg_thread_lock
);
233 jack_deactivate (client
);
234 jack_client_close (client
);
235 jack_ringbuffer_free (rb
);