Update copyright years
[gmidimonitor.git] / jack.c
blob71025fd11ed6720cb8b85888e0e1cca0b5525b62
1 /* -*- Mode: C ; c-basic-offset: 2 -*- */
2 /*****************************************************************************
4 * This file is part of gmidimonitor
6 * Copyright (C) 2007,2008 Nedko Arnaudov <nedko@arnaudov.name>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; version 2 of the License
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21 *****************************************************************************/
23 #include <jack/jack.h>
24 #include <jack/midiport.h>
25 #include <gtk/gtk.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <assert.h>
30 #include "config.h"
32 #include "common.h"
33 #include "jack.h"
34 #include "memory_atomic.h"
35 //#define LOG_LEVEL LOG_LEVEL_DEBUG
36 #include "log.h"
37 #include "list.h"
38 #include "glade.h"
39 #include "gm.h"
40 #include "sysex.h"
42 #include "jack_compat.h"
44 jack_client_t * g_jack_client;
45 jack_port_t * g_jack_input_port;
46 rtsafe_memory_handle g_memory;
48 struct jack_midi_event_buffer
50 struct list_head siblings;
51 size_t buffer_size;
52 unsigned char buffer[0];
55 pthread_mutex_t g_jack_midi_mutex;
56 //pthread_cond_t g_jack_midi_cond;
58 /* transfer from jack process callback to main thread */
59 /* new events are being put at list begining */
60 struct list_head g_jack_midi_events_pending;
62 /* temporary storage used by jack process callback in case g_jack_midi_events_pending is locked by main thread */
63 /* new events are being put at list begining */
64 struct list_head g_jack_midi_events_pending_rt;
66 pthread_t g_jack_midi_tid; /* jack_midi_thread id */
68 gboolean g_jack_midi_thread_exit; /* whther jack_midi_thread shoud exit */
70 int
71 jack_process(jack_nframes_t nframes, void * context)
73 int ret;
74 void * port_buf;
75 jack_midi_event_t in_event;
76 jack_nframes_t event_count;
77 jack_position_t pos;
78 jack_nframes_t i;
79 struct jack_midi_event_buffer * event_buffer;
81 port_buf = jack_port_get_buffer(g_jack_input_port, nframes);
82 event_count = jack_midi_get_event_count(port_buf);
83 jack_transport_query(g_jack_client, &pos);
85 for (i = 0 ; i < event_count; i++)
87 jack_midi_event_get(&in_event, port_buf, i);
89 LOG_DEBUG("midi event with size %u received. (jack_process)", (unsigned int)in_event.size);
91 /* allocate memory for buffer copy */
92 event_buffer = rtsafe_memory_allocate(g_memory, sizeof(struct jack_midi_event_buffer) + in_event.size);
93 if (event_buffer == NULL)
95 LOG_ERROR("Ignored midi event with size %u because memory allocation failed.", (unsigned int)in_event.size);
96 continue;
99 /* copy buffer data */
100 memcpy(event_buffer->buffer, in_event.buffer, in_event.size);
101 event_buffer->buffer_size = in_event.size;
103 /* Add event buffer to g_jack_midi_events_pending_rt list */
104 list_add(&event_buffer->siblings, &g_jack_midi_events_pending_rt);
107 ret = pthread_mutex_trylock(&g_jack_midi_mutex);
108 if (ret == 0)
110 /* We are lucky and we got the lock */
111 LOG_DEBUG("Lucky");
113 /* Move pending events in g_jack_midi_events_pending_rt to begining of g_jack_midi_events_pending */
114 list_splice_init(&g_jack_midi_events_pending_rt, &g_jack_midi_events_pending);
116 /* wakeup jack_midi_thread */
117 //ret = pthread_cond_broadcast(&g_jack_midi_cond);
118 //LOG_DEBUG("pthread_cond_broadcast() result is %d", ret);
119 ret = pthread_mutex_unlock(&g_jack_midi_mutex);
120 //LOG_DEBUG("pthread_mutex_unlock() result is %d", ret);
122 else
124 /* We are not lucky, jack_midi_thread has locked the mutex */
125 LOG_DEBUG("Not lucky (%d)", ret);
128 return 0;
131 gboolean
132 jack_midi_decode(
133 guint8 * buffer,
134 size_t buffer_size,
135 GString * msg_str_ptr,
136 GString * channel_str_ptr)
138 size_t i;
139 unsigned int channel;
140 unsigned int note;
141 unsigned int velocity;
142 const char * note_name;
143 unsigned int octave;
144 unsigned int controller;
145 unsigned int value;
146 const char * controller_name;
147 signed int pitch;
148 const char * drum_name;
150 if (buffer_size == 1 && buffer[0] == 0xFE)
152 g_string_sprintf(msg_str_ptr, "Active sensing");
153 return FALSE; /* disable */
156 if (buffer_size == 1 && buffer[0] == 0xF8)
158 g_string_sprintf(msg_str_ptr, "Timing Clock");
159 return FALSE; /* disable */
162 if (buffer_size == 3 && (buffer[0] >> 4) == 0x08)
164 channel = (buffer[0] & 0x0F) + 1; /* 1 .. 16 */
165 assert(channel >= 1 && channel <= 16);
167 if (channel == 10)
169 return FALSE; /* ignore note off for drums */
172 note = buffer[1];
173 if (note > 127)
175 goto unknown_event;
178 velocity = buffer[2];
179 if (velocity > 127)
181 goto unknown_event;
184 note_name = g_note_names[note % 12];
185 octave = note / 12 - 1;
187 g_string_sprintf(channel_str_ptr, "%u", channel);
189 g_string_sprintf(
190 msg_str_ptr,
191 "Note off, %s, octave %d, velocity %u",
192 note_name,
193 octave,
194 velocity);
196 return TRUE;
199 if (buffer_size == 3 && (buffer[0] >> 4) == 0x09)
201 channel = (buffer[0] & 0x0F) + 1; /* 1 .. 16 */
202 assert(channel >= 1 && channel <= 16);
204 note = buffer[1];
205 if (note > 127)
207 goto unknown_event;
210 velocity = buffer[2];
211 if (velocity > 127)
213 goto unknown_event;
216 note_name = g_note_names[note % 12];
217 octave = note / 12 - 1;
219 g_string_sprintf(channel_str_ptr, "%u", channel);
221 if (channel == 10)
223 drum_name = gm_get_drum_name(note);
225 else
227 drum_name = NULL;
230 if (drum_name != NULL)
232 if (velocity == 0)
234 return FALSE; /* ignore note off for drums */
237 g_string_sprintf(
238 msg_str_ptr,
239 "Drum: %s (%s, octave %d, velocity %u)",
240 drum_name,
241 note_name,
242 octave,
243 velocity);
245 else
247 g_string_sprintf(
248 msg_str_ptr,
249 "Note on, %s, octave %d, velocity %u",
250 note_name,
251 octave,
252 velocity);
255 return TRUE;
258 if (buffer_size == 3 && (buffer[0] >> 4) == 0x0A)
260 channel = (buffer[0] & 0x0F) + 1; /* 1 .. 16 */
261 assert(channel >= 1 && channel <= 16);
263 note = buffer[1];
264 if (note > 127)
266 goto unknown_event;
269 velocity = buffer[2];
270 if (velocity > 127)
272 goto unknown_event;
275 note_name = g_note_names[note % 12];
276 octave = note / 12 - 1;
278 g_string_sprintf(channel_str_ptr, "%u", channel);
280 g_string_sprintf(
281 msg_str_ptr,
282 "Polyphonic Key Pressure (Aftertouch), %s, octave %d, velocity %u",
283 note_name,
284 octave,
285 velocity);
287 return TRUE;
290 if (buffer_size == 3 && (buffer[0] >> 4) == 0x0B)
292 channel = (buffer[0] & 0x0F) + 1; /* 1 .. 16 */
293 assert(channel >= 1 && channel <= 16);
295 controller = buffer[1];
296 if (controller > 127)
298 goto unknown_event;
301 value = buffer[2];
302 if (value > 127)
304 goto unknown_event;
307 g_string_sprintf(channel_str_ptr, "%u", channel);
309 controller_name = gm_get_controller_name(controller);
311 if (controller_name != NULL)
313 g_string_sprintf(
314 msg_str_ptr,
315 "CC %s (%u), value %u",
316 controller_name,
317 controller,
318 value);
320 else
322 g_string_sprintf(
323 msg_str_ptr,
324 "CC %u, value %u",
325 controller,
326 value);
329 return TRUE;
332 if (buffer_size == 2 && (buffer[0] >> 4) == 0x0C)
334 channel = (buffer[0] & 0x0F) + 1; /* 1 .. 16 */
335 assert(channel >= 1 && channel <= 16);
337 value = buffer[1];
338 if (value > 127)
340 goto unknown_event;
343 g_string_sprintf(channel_str_ptr, "%u", channel);
345 g_string_sprintf(
346 msg_str_ptr,
347 "Program change, %d (%s)",
348 value,
349 gm_get_instrument_name(value));
351 return TRUE;
354 if (buffer_size == 3 && (buffer[0] >> 4) == 0x0E && buffer[1] <= 127 && buffer[1] <= 127)
356 channel = (buffer[0] & 0x0F) + 1; /* 1 .. 16 */
357 assert(channel >= 1 && channel <= 16);
359 pitch = buffer[1];
360 pitch |= (unsigned int)buffer[2] << 7;
361 pitch -= 0x2000;
363 g_string_sprintf(channel_str_ptr, "%u", channel);
365 g_string_sprintf(
366 msg_str_ptr,
367 "Pitchwheel, %d",
368 pitch);
370 return TRUE;
373 if (buffer_size > 0 && buffer[0] == 0xF0)
375 decode_sysex(buffer, buffer_size, msg_str_ptr);
376 return TRUE;
379 if (buffer_size == 1 && buffer[0] == 0xFF)
381 g_string_sprintf(
382 msg_str_ptr,
383 "Reset");
385 return TRUE;
388 unknown_event:
389 g_string_sprintf(
390 msg_str_ptr,
391 "unknown midi event with size %u bytes:",
392 (unsigned int)buffer_size);
394 for (i = 0 ; i < buffer_size ; i++)
396 g_string_append_printf(
397 msg_str_ptr,
398 " %02X",
399 (unsigned int)(buffer[i]));
402 return TRUE;
405 /* The JACK MIDI input handling thread */
406 void *
407 jack_midi_thread(void * context_ptr)
409 struct jack_midi_event_buffer * event_buffer;
410 struct list_head * node_ptr;
411 GtkListStore * list_store_ptr;
412 GtkWidget * child_ptr;
413 GtkTreeIter iter;
414 GString * time_str_ptr;
415 GString * msg_str_ptr;
416 GString * channel_str_ptr;
418 LOG_DEBUG("jack_midi_thread started");
420 child_ptr = get_glade_widget_child(g_main_window_ptr, "list");
422 list_store_ptr = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(child_ptr)));
424 loop:
425 pthread_mutex_lock(&g_jack_midi_mutex);
427 if (g_jack_midi_thread_exit)
429 pthread_mutex_unlock(&g_jack_midi_mutex);
431 LOG_DEBUG("jack_midi_thread exiting");
432 return NULL;
435 rtsafe_memory_sleepy(g_memory);
437 //LOG_DEBUG("checking events...");
439 while (!list_empty(&g_jack_midi_events_pending))
441 node_ptr = g_jack_midi_events_pending.prev;
443 list_del(node_ptr);
445 event_buffer = list_entry(node_ptr, struct jack_midi_event_buffer, siblings);
447 if (g_midi_ignore)
449 goto deallocate_event;
452 LOG_DEBUG("midi event with size %u received.", (unsigned int)event_buffer->buffer_size);
454 time_str_ptr = g_string_new("");
455 channel_str_ptr = g_string_new("");
456 msg_str_ptr = g_string_new("");
458 if (!jack_midi_decode(
459 event_buffer->buffer,
460 event_buffer->buffer_size,
461 msg_str_ptr,
462 channel_str_ptr))
464 /* ignoring specific event */
465 goto deallocate_strings;
468 /* get GTK thread lock */
469 gdk_threads_enter();
471 if (g_row_count >= MAX_LIST_SIZE)
473 gtk_tree_model_get_iter_first(
474 GTK_TREE_MODEL(list_store_ptr),
475 &iter);
477 gtk_list_store_remove(
478 list_store_ptr,
479 &iter);
482 /* Append an empty row to the list store. Iter will point to the new row */
483 gtk_list_store_append(list_store_ptr, &iter);
485 gtk_list_store_set(
486 list_store_ptr,
487 &iter,
488 COL_TIME, time_str_ptr->str,
489 COL_CHANNEL, channel_str_ptr->str,
490 COL_MESSAGE, msg_str_ptr->str,
491 -1);
493 gtk_tree_view_scroll_to_cell(
494 GTK_TREE_VIEW(child_ptr),
495 gtk_tree_model_get_path(
496 gtk_tree_view_get_model(GTK_TREE_VIEW(child_ptr)),
497 &iter),
498 NULL,
499 TRUE,
500 0.0,
501 1.0);
503 /* Force update of scroll position. */
504 /* Is it a bug that it does not update automagically ? */
505 gtk_container_check_resize(GTK_CONTAINER(child_ptr));
507 g_row_count++;
509 /* release GTK thread lock */
510 gdk_threads_leave();
512 deallocate_strings:
513 g_string_free(channel_str_ptr, TRUE);
514 g_string_free(msg_str_ptr, TRUE);
515 g_string_free(time_str_ptr, TRUE);
517 deallocate_event:
518 rtsafe_memory_deallocate(event_buffer);
521 pthread_mutex_unlock(&g_jack_midi_mutex);
523 //LOG_DEBUG("waiting for more events...");
525 //pthread_cond_wait(&g_jack_midi_cond, &g_jack_midi_mutex);
526 usleep(10000);
528 goto loop;
531 void
532 jack_destroy_pending_events()
534 struct jack_midi_event_buffer * event_buffer;
535 struct list_head * node_ptr;
537 while (!list_empty(&g_jack_midi_events_pending))
539 LOG_DEBUG("Destroying pending event");
540 node_ptr = g_jack_midi_events_pending.next;
542 list_del(node_ptr);
544 event_buffer = list_entry(node_ptr, struct jack_midi_event_buffer, siblings);
546 rtsafe_memory_deallocate(event_buffer);
549 while (!list_empty(&g_jack_midi_events_pending_rt))
551 LOG_DEBUG("Destroying realtime pending event");
552 node_ptr = g_jack_midi_events_pending_rt.next;
554 list_del(node_ptr);
556 event_buffer = list_entry(node_ptr, struct jack_midi_event_buffer, siblings);
558 rtsafe_memory_deallocate(event_buffer);
562 gboolean
563 jack_init(const char * name)
565 int ret;
567 LOG_DEBUG("jack_init(\"%s\") called.", name);
569 if (!rtsafe_memory_init(
570 100 * 1024,
571 100,
572 1000,
573 &g_memory))
575 LOG_ERROR("RT-safe memory initialization failed.");
576 goto fail;
579 INIT_LIST_HEAD(&g_jack_midi_events_pending);
580 INIT_LIST_HEAD(&g_jack_midi_events_pending_rt);
582 ret = pthread_mutex_init(&g_jack_midi_mutex, NULL);
583 if (ret != 0)
585 LOG_ERROR("Cannot initialize mutex.");
586 goto fail_uninit_memory;
589 /* ret = pthread_cond_init(&g_jack_midi_cond, NULL); */
590 /* if (ret != 0) */
591 /* { */
592 /* LOG_ERROR("Cannot initialize condition (variable)."); */
593 /* goto fail_uninit_mutex; */
594 /* } */
596 g_jack_midi_thread_exit = FALSE;
598 ret = pthread_create(&g_jack_midi_tid, NULL, jack_midi_thread, NULL);
599 if (ret != 0)
601 LOG_ERROR("Cannot start JACK MIDI thread.");
602 goto fail_uninit_cond;
605 g_jack_client = jack_client_new(name);
606 if (g_jack_client == NULL)
608 LOG_ERROR("Cannot create JACK client.");
609 goto fail_stop_thread;
612 ret = jack_set_process_callback(g_jack_client, jack_process, 0);
613 if (ret != 0)
615 LOG_ERROR("Cannot set JACK process callback.");
616 goto fail_close;
619 g_jack_input_port = jack_port_register(g_jack_client, "midi_in", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0);
620 if (g_jack_input_port == NULL)
622 LOG_ERROR("Failed to create input JACK MIDI port");
623 goto fail_close;
626 ret = jack_activate(g_jack_client);
627 if (ret != 0)
629 LOG_ERROR("Cannot activate JACK client.");
630 goto fail_close;
633 return TRUE;
635 fail_close:
636 jack_client_close(g_jack_client);
638 fail_stop_thread:
639 jack_destroy_pending_events();
641 /* Tell jack_midi_thread to exit */
642 pthread_mutex_lock(&g_jack_midi_mutex);
643 g_jack_midi_thread_exit = TRUE;
644 pthread_mutex_unlock(&g_jack_midi_mutex);
646 /* wakeup jack_midi_thread */
647 /* pthread_cond_broadcast(&g_jack_midi_cond); */
649 /* wait thread to finish */
650 pthread_join(g_jack_midi_tid, NULL);
652 fail_uninit_cond:
653 /* pthread_cond_destroy(&g_jack_midi_cond); */
655 /* fail_uninit_mutex: */
656 pthread_mutex_destroy(&g_jack_midi_mutex);
658 fail_uninit_memory:
659 rtsafe_memory_uninit(g_memory);
661 fail:
662 return FALSE;
665 void
666 jack_uninit()
668 LOG_DEBUG("jack_uninit() called.");
670 jack_deactivate(g_jack_client);
672 jack_client_close(g_jack_client);
674 /* Tell jack_midi_thread to exit */
675 pthread_mutex_lock(&g_jack_midi_mutex);
676 g_jack_midi_thread_exit = TRUE;
677 pthread_mutex_unlock(&g_jack_midi_mutex);
679 /* wakeup jack_midi_thread */
680 /* pthread_cond_broadcast(&g_jack_midi_cond); */
682 /* wait thread to finish */
683 pthread_join(g_jack_midi_tid, NULL);
685 jack_destroy_pending_events();
687 /* pthread_cond_destroy(&g_jack_midi_cond); */
689 pthread_mutex_destroy(&g_jack_midi_mutex);
691 rtsafe_memory_uninit(g_memory);