memops: Provide function for S32 to float conversion
[jack2.git] / example-clients / midi_dump.c
blob503af59df520ed5649d379038b9fe28dec6cfbb3
1 // gcc -o jack_midi_dump -Wall midi_dump.c -ljack -pthread
3 #include <stdio.h>
4 #include <string.h>
5 #include <unistd.h>
6 #include <assert.h>
7 #include <inttypes.h>
8 #include <jack/jack.h>
9 #include <jack/midiport.h>
10 #include <jack/ringbuffer.h>
12 #ifdef __MINGW32__
13 #include <pthread.h>
14 #endif
16 #ifndef WIN32
17 #include <signal.h>
18 #include <pthread.h>
19 #include <sys/mman.h>
20 #endif
22 #ifndef MAX
23 #define MAX(a,b) ( (a) < (b) ? (b) : (a) )
24 #endif
26 static jack_port_t* port;
27 static jack_ringbuffer_t *rb = NULL;
28 static pthread_mutex_t msg_thread_lock = PTHREAD_MUTEX_INITIALIZER;
29 static pthread_cond_t data_ready = PTHREAD_COND_INITIALIZER;
31 static int keeprunning = 1;
32 static uint64_t monotonic_cnt = 0;
34 #define RBSIZE 512
36 typedef struct {
37 uint8_t buffer[128];
38 uint32_t size;
39 uint32_t tme_rel;
40 uint64_t tme_mon;
41 } midimsg;
43 static void
44 describe (midimsg* event)
46 if (event->size == 0) {
47 return;
50 uint8_t type = event->buffer[0] & 0xf0;
51 uint8_t channel = event->buffer[0] & 0xf;
53 switch (type) {
54 case 0x90:
55 assert (event->size == 3);
56 printf (" note on (channel %2d): pitch %3d, velocity %3d", channel, event->buffer[1], event->buffer[2]);
57 break;
58 case 0x80:
59 assert (event->size == 3);
60 printf (" note off (channel %2d): pitch %3d, velocity %3d", channel, event->buffer[1], event->buffer[2]);
61 break;
62 case 0xb0:
63 assert (event->size == 3);
64 printf (" control change (channel %2d): controller %3d, value %3d", channel, event->buffer[1], event->buffer[2]);
65 break;
66 default:
67 break;
71 int
72 process (jack_nframes_t frames, void* arg)
74 void* buffer;
75 jack_nframes_t N;
76 jack_nframes_t i;
78 buffer = jack_port_get_buffer (port, frames);
79 assert (buffer);
81 N = jack_midi_get_event_count (buffer);
82 for (i = 0; i < N; ++i) {
83 jack_midi_event_t event;
84 int r;
86 r = jack_midi_event_get (&event, buffer, i);
88 if (r == 0 && jack_ringbuffer_write_space (rb) >= sizeof(midimsg)) {
89 midimsg m;
90 m.tme_mon = monotonic_cnt;
91 m.tme_rel = event.time;
92 m.size = event.size;
93 memcpy (m.buffer, event.buffer, MAX(sizeof(m.buffer), event.size));
94 jack_ringbuffer_write (rb, (void *) &m, sizeof(midimsg));
99 monotonic_cnt += frames;
101 if (pthread_mutex_trylock (&msg_thread_lock) == 0) {
102 pthread_cond_signal (&data_ready);
103 pthread_mutex_unlock (&msg_thread_lock);
106 return 0;
109 static void wearedone(int sig) {
110 keeprunning = 0;
113 static void usage (int status) {
114 printf ("jack_midi_dump - JACK MIDI Monitor.\n\n");
115 printf ("Usage: jack_midi_dump [ OPTIONS ] [CLIENT-NAME]\n\n");
116 printf ("Options:\n\
117 -a use absoute timestamps relative to application start\n\
118 -h display this help and exit\n\
119 -r use relative timestamps to previous MIDI event\n\
120 \n");
121 printf ("\n\
122 This tool listens for MIDI events on a JACK MIDI port and prints\n\
123 the message to stdout.\n\
125 If no client name is given it defaults to 'midi-monitor'.\n\
127 See also: jackd(1)\n\
128 \n");
129 exit (status);
133 main (int argc, char* argv[])
135 jack_client_t* client;
136 char const default_name[] = "midi-monitor";
137 char const * client_name;
138 int time_format = 0;
139 int r;
141 int cn = 1;
143 if (argc > 1) {
144 if (!strcmp (argv[1], "-a")) { time_format = 1; cn = 2; }
145 else if (!strcmp (argv[1], "-r")) { time_format = 2; cn = 2; }
146 else if (!strcmp (argv[1], "-h")) { usage (EXIT_SUCCESS); }
147 else if (argv[1][0] == '-') { usage (EXIT_FAILURE); }
150 if (argc > cn) {
151 client_name = argv[cn];
152 } else {
153 client_name = default_name;
156 client = jack_client_open (client_name, JackNullOption, NULL);
157 if (client == NULL) {
158 fprintf (stderr, "Could not create JACK client.\n");
159 exit (EXIT_FAILURE);
162 rb = jack_ringbuffer_create (RBSIZE * sizeof(midimsg));
164 jack_set_process_callback (client, process, 0);
166 port = jack_port_register (client, "input", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0);
167 if (port == NULL) {
168 fprintf (stderr, "Could not register port.\n");
169 exit (EXIT_FAILURE);
172 #ifndef WIN32
173 if (mlockall (MCL_CURRENT | MCL_FUTURE)) {
174 fprintf (stderr, "Warning: Can not lock memory.\n");
176 #endif
178 r = jack_activate (client);
179 if (r != 0) {
180 fprintf (stderr, "Could not activate client.\n");
181 exit (EXIT_FAILURE);
184 #ifndef WIN32
185 signal(SIGHUP, wearedone);
186 signal(SIGINT, wearedone);
187 #endif
189 pthread_mutex_lock (&msg_thread_lock);
191 uint64_t prev_event = 0;
192 while (keeprunning) {
193 const int mqlen = jack_ringbuffer_read_space (rb) / sizeof(midimsg);
194 int i;
195 for (i=0; i < mqlen; ++i) {
196 size_t j;
197 midimsg m;
198 jack_ringbuffer_read(rb, (char*) &m, sizeof(midimsg));
200 switch(time_format) {
201 case 1:
202 printf ("%7"PRId64":", m.tme_rel + m.tme_mon);
203 break;
204 case 2:
205 printf ("%+6"PRId64":", m.tme_rel + m.tme_mon - prev_event);
206 break;
207 default:
208 printf ("%4d:", m.tme_rel);
209 break;
211 for (j = 0; j < m.size && j < sizeof(m.buffer); ++j) {
212 printf (" %02x", m.buffer[j]);
215 describe (&m);
216 printf("\n");
217 prev_event = m.tme_rel + m.tme_mon;
219 fflush (stdout);
220 pthread_cond_wait (&data_ready, &msg_thread_lock);
222 pthread_mutex_unlock (&msg_thread_lock);
224 jack_deactivate (client);
225 jack_client_close (client);
226 jack_ringbuffer_free (rb);
228 return 0;