jack2 codebase
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

234 lines
5.4KB

  1. // gcc -o jack_midi_dump -Wall midi_dump.c -ljack -pthread
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <unistd.h>
  5. #include <assert.h>
  6. #include <inttypes.h>
  7. #include <jack/jack.h>
  8. #include <jack/midiport.h>
  9. #include <jack/ringbuffer.h>
  10. #ifdef __MINGW32__
  11. #include <pthread.h>
  12. #endif
  13. #ifndef WIN32
  14. #include <signal.h>
  15. #include <pthread.h>
  16. #include <sys/mman.h>
  17. #endif
  18. static jack_port_t* port;
  19. static jack_ringbuffer_t *rb = NULL;
  20. static pthread_mutex_t msg_thread_lock = PTHREAD_MUTEX_INITIALIZER;
  21. static pthread_cond_t data_ready = PTHREAD_COND_INITIALIZER;
  22. static int keeprunning = 1;
  23. static uint64_t monotonic_cnt = 0;
  24. #define RBSIZE 100
  25. #define MSG_BUFFER_SIZE 4096
  26. typedef struct {
  27. uint8_t buffer[MSG_BUFFER_SIZE];
  28. uint32_t size;
  29. uint32_t tme_rel;
  30. uint64_t tme_mon;
  31. } midimsg;
  32. static void
  33. describe (midimsg* event)
  34. {
  35. if (event->size == 0) {
  36. return;
  37. }
  38. uint8_t type = event->buffer[0] & 0xf0;
  39. uint8_t channel = event->buffer[0] & 0xf;
  40. switch (type) {
  41. case 0x90:
  42. assert (event->size == 3);
  43. printf (" note on (channel %2d): pitch %3d, velocity %3d", channel, event->buffer[1], event->buffer[2]);
  44. break;
  45. case 0x80:
  46. assert (event->size == 3);
  47. printf (" note off (channel %2d): pitch %3d, velocity %3d", channel, event->buffer[1], event->buffer[2]);
  48. break;
  49. case 0xb0:
  50. assert (event->size == 3);
  51. printf (" control change (channel %2d): controller %3d, value %3d", channel, event->buffer[1], event->buffer[2]);
  52. break;
  53. default:
  54. break;
  55. }
  56. }
  57. int
  58. process (jack_nframes_t frames, void* arg)
  59. {
  60. void* buffer;
  61. jack_nframes_t N;
  62. jack_nframes_t i;
  63. buffer = jack_port_get_buffer (port, frames);
  64. assert (buffer);
  65. N = jack_midi_get_event_count (buffer);
  66. for (i = 0; i < N; ++i) {
  67. jack_midi_event_t event;
  68. int r;
  69. r = jack_midi_event_get (&event, buffer, i);
  70. if (r != 0) {continue;}
  71. if (event.size > MSG_BUFFER_SIZE) {
  72. fprintf(stderr, "Error: MIDI message was too large, skipping event. Max. allowed size: %d bytes\n", MSG_BUFFER_SIZE);
  73. }
  74. else if (jack_ringbuffer_write_space (rb) >= sizeof(midimsg)) {
  75. midimsg m;
  76. m.tme_mon = monotonic_cnt;
  77. m.tme_rel = event.time;
  78. m.size = event.size;
  79. memcpy (m.buffer, event.buffer, event.size);
  80. jack_ringbuffer_write (rb, (void *) &m, sizeof(midimsg));
  81. }
  82. else {
  83. fprintf (stderr, "Error: ringbuffer was full, skipping event.\n");
  84. }
  85. }
  86. monotonic_cnt += frames;
  87. if (pthread_mutex_trylock (&msg_thread_lock) == 0) {
  88. pthread_cond_signal (&data_ready);
  89. pthread_mutex_unlock (&msg_thread_lock);
  90. }
  91. return 0;
  92. }
  93. static void wearedone(int sig) {
  94. fprintf(stderr, "Shutting down\n");
  95. keeprunning = 0;
  96. }
  97. static void usage (int status) {
  98. printf ("jack_midi_dump - JACK MIDI Monitor.\n\n");
  99. printf ("Usage: jack_midi_dump [ OPTIONS ] [CLIENT-NAME]\n\n");
  100. printf ("Options:\n\
  101. -a use absoute timestamps relative to application start\n\
  102. -h display this help and exit\n\
  103. -r use relative timestamps to previous MIDI event\n\
  104. \n");
  105. printf ("\n\
  106. This tool listens for MIDI events on a JACK MIDI port and prints\n\
  107. the message to stdout.\n\
  108. \n\
  109. If no client name is given it defaults to 'midi-monitor'.\n\
  110. \n\
  111. See also: jackd(1)\n\
  112. \n");
  113. exit (status);
  114. }
  115. int
  116. main (int argc, char* argv[])
  117. {
  118. jack_client_t* client;
  119. char const default_name[] = "midi-monitor";
  120. char const * client_name;
  121. int time_format = 0;
  122. int r;
  123. int cn = 1;
  124. if (argc > 1) {
  125. if (!strcmp (argv[1], "-a")) { time_format = 1; cn = 2; }
  126. else if (!strcmp (argv[1], "-r")) { time_format = 2; cn = 2; }
  127. else if (!strcmp (argv[1], "-h")) { usage (EXIT_SUCCESS); }
  128. else if (argv[1][0] == '-') { usage (EXIT_FAILURE); }
  129. }
  130. if (argc > cn) {
  131. client_name = argv[cn];
  132. } else {
  133. client_name = default_name;
  134. }
  135. client = jack_client_open (client_name, JackNullOption, NULL);
  136. if (client == NULL) {
  137. fprintf (stderr, "Could not create JACK client.\n");
  138. exit (EXIT_FAILURE);
  139. }
  140. rb = jack_ringbuffer_create (RBSIZE * sizeof(midimsg));
  141. jack_set_process_callback (client, process, 0);
  142. port = jack_port_register (client, "input", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0);
  143. if (port == NULL) {
  144. fprintf (stderr, "Could not register port.\n");
  145. exit (EXIT_FAILURE);
  146. }
  147. #ifndef WIN32
  148. if (mlockall (MCL_CURRENT | MCL_FUTURE)) {
  149. fprintf (stderr, "Warning: Can not lock memory.\n");
  150. }
  151. #endif
  152. r = jack_activate (client);
  153. if (r != 0) {
  154. fprintf (stderr, "Could not activate client.\n");
  155. exit (EXIT_FAILURE);
  156. }
  157. #ifndef WIN32
  158. signal(SIGHUP, wearedone);
  159. signal(SIGINT, wearedone);
  160. #endif
  161. pthread_mutex_lock (&msg_thread_lock);
  162. uint64_t prev_event = 0;
  163. while (keeprunning) {
  164. const int mqlen = jack_ringbuffer_read_space (rb) / sizeof(midimsg);
  165. int i;
  166. for (i=0; i < mqlen; ++i) {
  167. size_t j;
  168. midimsg m;
  169. jack_ringbuffer_read(rb, (char*) &m, sizeof(midimsg));
  170. switch(time_format) {
  171. case 1:
  172. printf ("%7"PRId64":", m.tme_rel + m.tme_mon);
  173. break;
  174. case 2:
  175. printf ("%+6"PRId64":", m.tme_rel + m.tme_mon - prev_event);
  176. break;
  177. default:
  178. printf ("%4d:", m.tme_rel);
  179. break;
  180. }
  181. for (j = 0; j < m.size && j < sizeof(m.buffer); ++j) {
  182. printf (" %02x", m.buffer[j]);
  183. }
  184. describe (&m);
  185. printf("\n");
  186. prev_event = m.tme_rel + m.tme_mon;
  187. }
  188. fflush (stdout);
  189. pthread_cond_wait (&data_ready, &msg_thread_lock);
  190. }
  191. pthread_mutex_unlock (&msg_thread_lock);
  192. jack_deactivate (client);
  193. jack_client_close (client);
  194. jack_ringbuffer_free (rb);
  195. return 0;
  196. }