Replace "get_glade_widget_child" call with "gtk_builder_get_object"
[gmidimonitor.git] / jack.c
blob6bac44d8886ffd17473e78dab43a64da22ffed87
1 /* -*- Mode: C ; c-basic-offset: 2 -*- */
2 /*****************************************************************************
4 * This file is part of gmidimonitor
6 * Copyright (C) 2007,2008,2011 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 "gm.h"
39 #include "sysex.h"
41 #include "jack_compat.h"
43 extern GtkBuilder * g_builder;
45 jack_client_t * g_jack_client;
46 jack_port_t * g_jack_input_port;
47 rtsafe_memory_handle g_memory;
49 struct jack_midi_event_buffer
51 struct list_head siblings;
52 size_t buffer_size;
53 unsigned char buffer[0];
56 pthread_mutex_t g_jack_midi_mutex;
57 //pthread_cond_t g_jack_midi_cond;
59 /* transfer from jack process callback to main thread */
60 /* new events are being put at list begining */
61 struct list_head g_jack_midi_events_pending;
63 /* temporary storage used by jack process callback in case g_jack_midi_events_pending is locked by main thread */
64 /* new events are being put at list begining */
65 struct list_head g_jack_midi_events_pending_rt;
67 pthread_t g_jack_midi_tid; /* jack_midi_thread id */
69 gboolean g_jack_midi_thread_exit; /* whther jack_midi_thread shoud exit */
71 int
72 jack_process(jack_nframes_t nframes, void * context)
74 int ret;
75 void * port_buf;
76 jack_midi_event_t in_event;
77 jack_nframes_t event_count;
78 jack_position_t pos;
79 jack_nframes_t i;
80 struct jack_midi_event_buffer * event_buffer;
82 port_buf = jack_port_get_buffer(g_jack_input_port, nframes);
83 event_count = jack_midi_get_event_count(port_buf);
84 jack_transport_query(g_jack_client, &pos);
86 for (i = 0 ; i < event_count; i++)
88 jack_midi_event_get(&in_event, port_buf, i);
90 LOG_DEBUG("midi event with size %u received. (jack_process)", (unsigned int)in_event.size);
92 /* allocate memory for buffer copy */
93 event_buffer = rtsafe_memory_allocate(g_memory, sizeof(struct jack_midi_event_buffer) + in_event.size);
94 if (event_buffer == NULL)
96 LOG_ERROR("Ignored midi event with size %u because memory allocation failed.", (unsigned int)in_event.size);
97 continue;
100 /* copy buffer data */
101 memcpy(event_buffer->buffer, in_event.buffer, in_event.size);
102 event_buffer->buffer_size = in_event.size;
104 /* Add event buffer to g_jack_midi_events_pending_rt list */
105 list_add(&event_buffer->siblings, &g_jack_midi_events_pending_rt);
108 ret = pthread_mutex_trylock(&g_jack_midi_mutex);
109 if (ret == 0)
111 /* We are lucky and we got the lock */
112 LOG_DEBUG("Lucky");
114 /* Move pending events in g_jack_midi_events_pending_rt to begining of g_jack_midi_events_pending */
115 list_splice_init(&g_jack_midi_events_pending_rt, &g_jack_midi_events_pending);
117 /* wakeup jack_midi_thread */
118 //ret = pthread_cond_broadcast(&g_jack_midi_cond);
119 //LOG_DEBUG("pthread_cond_broadcast() result is %d", ret);
120 ret = pthread_mutex_unlock(&g_jack_midi_mutex);
121 //LOG_DEBUG("pthread_mutex_unlock() result is %d", ret);
123 else
125 /* We are not lucky, jack_midi_thread has locked the mutex */
126 LOG_DEBUG("Not lucky (%d)", ret);
129 return 0;
132 gboolean
133 jack_midi_decode(
134 guint8 * buffer,
135 size_t buffer_size,
136 GString * msg_str_ptr,
137 GString * channel_str_ptr)
139 size_t i;
140 unsigned int channel;
141 unsigned int note;
142 unsigned int velocity;
143 const char * note_name;
144 unsigned int octave;
145 unsigned int controller;
146 unsigned int value;
147 const char * controller_name;
148 signed int pitch;
149 const char * drum_name;
151 if (buffer_size == 1 && buffer[0] == 0xFE)
153 g_string_sprintf(msg_str_ptr, "Active sensing");
154 return FALSE; /* disable */
157 if (buffer_size == 1 && buffer[0] == 0xF8)
159 g_string_sprintf(msg_str_ptr, "Timing Clock");
160 return FALSE; /* disable */
163 if (buffer_size == 3 && (buffer[0] >> 4) == 0x08)
165 channel = (buffer[0] & 0x0F) + 1; /* 1 .. 16 */
166 assert(channel >= 1 && channel <= 16);
168 if (channel == 10)
170 return FALSE; /* ignore note off for drums */
173 note = buffer[1];
174 if (note > 127)
176 goto unknown_event;
179 velocity = buffer[2];
180 if (velocity > 127)
182 goto unknown_event;
185 note_name = g_note_names[note % 12];
186 octave = note / 12 - 1;
188 g_string_sprintf(channel_str_ptr, "%u", channel);
190 g_string_sprintf(
191 msg_str_ptr,
192 "Note off, %s, octave %d, velocity %u",
193 note_name,
194 octave,
195 velocity);
197 return TRUE;
200 if (buffer_size == 3 && (buffer[0] >> 4) == 0x09)
202 channel = (buffer[0] & 0x0F) + 1; /* 1 .. 16 */
203 assert(channel >= 1 && channel <= 16);
205 note = buffer[1];
206 if (note > 127)
208 goto unknown_event;
211 velocity = buffer[2];
212 if (velocity > 127)
214 goto unknown_event;
217 note_name = g_note_names[note % 12];
218 octave = note / 12 - 1;
220 g_string_sprintf(channel_str_ptr, "%u", channel);
222 if (channel == 10)
224 drum_name = gm_get_drum_name(note);
226 else
228 drum_name = NULL;
231 if (drum_name != NULL)
233 if (velocity == 0)
235 return FALSE; /* ignore note off for drums */
238 g_string_sprintf(
239 msg_str_ptr,
240 "Drum: %s (%s, octave %d, velocity %u)",
241 drum_name,
242 note_name,
243 octave,
244 velocity);
246 else
248 g_string_sprintf(
249 msg_str_ptr,
250 "Note on, %s, octave %d, velocity %u",
251 note_name,
252 octave,
253 velocity);
256 return TRUE;
259 if (buffer_size == 3 && (buffer[0] >> 4) == 0x0A)
261 channel = (buffer[0] & 0x0F) + 1; /* 1 .. 16 */
262 assert(channel >= 1 && channel <= 16);
264 note = buffer[1];
265 if (note > 127)
267 goto unknown_event;
270 velocity = buffer[2];
271 if (velocity > 127)
273 goto unknown_event;
276 note_name = g_note_names[note % 12];
277 octave = note / 12 - 1;
279 g_string_sprintf(channel_str_ptr, "%u", channel);
281 g_string_sprintf(
282 msg_str_ptr,
283 "Polyphonic Key Pressure (Aftertouch), %s, octave %d, velocity %u",
284 note_name,
285 octave,
286 velocity);
288 return TRUE;
291 if (buffer_size == 3 && (buffer[0] >> 4) == 0x0B)
293 channel = (buffer[0] & 0x0F) + 1; /* 1 .. 16 */
294 assert(channel >= 1 && channel <= 16);
296 controller = buffer[1];
297 if (controller > 127)
299 goto unknown_event;
302 value = buffer[2];
303 if (value > 127)
305 goto unknown_event;
308 g_string_sprintf(channel_str_ptr, "%u", channel);
310 controller_name = gm_get_controller_name(controller);
312 if (controller_name != NULL)
314 g_string_sprintf(
315 msg_str_ptr,
316 "CC %s (%u), value %u",
317 controller_name,
318 controller,
319 value);
321 else
323 g_string_sprintf(
324 msg_str_ptr,
325 "CC %u, value %u",
326 controller,
327 value);
330 return TRUE;
333 if (buffer_size == 2 && (buffer[0] >> 4) == 0x0C)
335 channel = (buffer[0] & 0x0F) + 1; /* 1 .. 16 */
336 assert(channel >= 1 && channel <= 16);
338 value = buffer[1];
339 if (value > 127)
341 goto unknown_event;
344 g_string_sprintf(channel_str_ptr, "%u", channel);
346 g_string_sprintf(
347 msg_str_ptr,
348 "Program change, %d (%s)",
349 value,
350 gm_get_instrument_name(value));
352 return TRUE;
355 if (buffer_size == 3 && (buffer[0] >> 4) == 0x0E && buffer[1] <= 127 && buffer[2] <= 127)
357 channel = (buffer[0] & 0x0F) + 1; /* 1 .. 16 */
358 assert(channel >= 1 && channel <= 16);
360 pitch = buffer[1];
361 pitch |= (unsigned int)buffer[2] << 7;
362 pitch -= 0x2000;
364 g_string_sprintf(channel_str_ptr, "%u", channel);
366 g_string_sprintf(
367 msg_str_ptr,
368 "Pitchwheel, %d",
369 pitch);
371 return TRUE;
374 if (buffer_size > 0 && buffer[0] == 0xF0)
376 decode_sysex(buffer, buffer_size, msg_str_ptr);
377 return TRUE;
380 if (buffer_size == 1 && buffer[0] == 0xFF)
382 g_string_sprintf(
383 msg_str_ptr,
384 "Reset");
386 return TRUE;
389 unknown_event:
390 g_string_sprintf(
391 msg_str_ptr,
392 "unknown midi event with size %u bytes:",
393 (unsigned int)buffer_size);
395 for (i = 0 ; i < buffer_size ; i++)
397 g_string_append_printf(
398 msg_str_ptr,
399 " %02X",
400 (unsigned int)(buffer[i]));
403 return TRUE;
406 /* The JACK MIDI input handling thread */
407 void *
408 jack_midi_thread(void * context_ptr)
410 struct jack_midi_event_buffer * event_buffer;
411 struct list_head * node_ptr;
412 GtkListStore * list_store_ptr;
413 GtkWidget * child_ptr;
414 GtkTreeIter iter;
415 GString * time_str_ptr;
416 GString * msg_str_ptr;
417 GString * channel_str_ptr;
419 LOG_DEBUG("jack_midi_thread started");
421 child_ptr = GTK_WIDGET (gtk_builder_get_object (g_builder, "list"));
423 list_store_ptr = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(child_ptr)));
425 loop:
426 pthread_mutex_lock(&g_jack_midi_mutex);
428 if (g_jack_midi_thread_exit)
430 pthread_mutex_unlock(&g_jack_midi_mutex);
432 LOG_DEBUG("jack_midi_thread exiting");
433 return NULL;
436 rtsafe_memory_sleepy(g_memory);
438 //LOG_DEBUG("checking events...");
440 while (!list_empty(&g_jack_midi_events_pending))
442 node_ptr = g_jack_midi_events_pending.prev;
444 list_del(node_ptr);
446 event_buffer = list_entry(node_ptr, struct jack_midi_event_buffer, siblings);
448 if (g_midi_ignore)
450 goto deallocate_event;
453 LOG_DEBUG("midi event with size %u received.", (unsigned int)event_buffer->buffer_size);
455 time_str_ptr = g_string_new("");
456 channel_str_ptr = g_string_new("");
457 msg_str_ptr = g_string_new("");
459 if (!jack_midi_decode(
460 event_buffer->buffer,
461 event_buffer->buffer_size,
462 msg_str_ptr,
463 channel_str_ptr))
465 /* ignoring specific event */
466 goto deallocate_strings;
469 /* get GTK thread lock */
470 gdk_threads_enter();
472 if (g_row_count >= MAX_LIST_SIZE)
474 gtk_tree_model_get_iter_first(
475 GTK_TREE_MODEL(list_store_ptr),
476 &iter);
478 gtk_list_store_remove(
479 list_store_ptr,
480 &iter);
483 /* Append an empty row to the list store. Iter will point to the new row */
484 gtk_list_store_append(list_store_ptr, &iter);
486 gtk_list_store_set(
487 list_store_ptr,
488 &iter,
489 COL_TIME, time_str_ptr->str,
490 COL_CHANNEL, channel_str_ptr->str,
491 COL_MESSAGE, msg_str_ptr->str,
492 -1);
494 gtk_tree_view_scroll_to_cell(
495 GTK_TREE_VIEW(child_ptr),
496 gtk_tree_model_get_path(
497 gtk_tree_view_get_model(GTK_TREE_VIEW(child_ptr)),
498 &iter),
499 NULL,
500 TRUE,
501 0.0,
502 1.0);
504 /* Force update of scroll position. */
505 /* Is it a bug that it does not update automagically ? */
506 gtk_container_check_resize(GTK_CONTAINER(child_ptr));
508 g_row_count++;
510 /* release GTK thread lock */
511 gdk_threads_leave();
513 deallocate_strings:
514 g_string_free(channel_str_ptr, TRUE);
515 g_string_free(msg_str_ptr, TRUE);
516 g_string_free(time_str_ptr, TRUE);
518 deallocate_event:
519 rtsafe_memory_deallocate(event_buffer);
522 pthread_mutex_unlock(&g_jack_midi_mutex);
524 //LOG_DEBUG("waiting for more events...");
526 //pthread_cond_wait(&g_jack_midi_cond, &g_jack_midi_mutex);
527 usleep(10000);
529 goto loop;
532 void
533 jack_destroy_pending_events()
535 struct jack_midi_event_buffer * event_buffer;
536 struct list_head * node_ptr;
538 while (!list_empty(&g_jack_midi_events_pending))
540 LOG_DEBUG("Destroying pending event");
541 node_ptr = g_jack_midi_events_pending.next;
543 list_del(node_ptr);
545 event_buffer = list_entry(node_ptr, struct jack_midi_event_buffer, siblings);
547 rtsafe_memory_deallocate(event_buffer);
550 while (!list_empty(&g_jack_midi_events_pending_rt))
552 LOG_DEBUG("Destroying realtime pending event");
553 node_ptr = g_jack_midi_events_pending_rt.next;
555 list_del(node_ptr);
557 event_buffer = list_entry(node_ptr, struct jack_midi_event_buffer, siblings);
559 rtsafe_memory_deallocate(event_buffer);
563 gboolean
564 jack_init(const char * name)
566 int ret;
568 LOG_DEBUG("jack_init(\"%s\") called.", name);
570 if (!rtsafe_memory_init(
571 100 * 1024,
572 100,
573 1000,
574 &g_memory))
576 LOG_ERROR("RT-safe memory initialization failed.");
577 goto fail;
580 INIT_LIST_HEAD(&g_jack_midi_events_pending);
581 INIT_LIST_HEAD(&g_jack_midi_events_pending_rt);
583 ret = pthread_mutex_init(&g_jack_midi_mutex, NULL);
584 if (ret != 0)
586 LOG_ERROR("Cannot initialize mutex.");
587 goto fail_uninit_memory;
590 /* ret = pthread_cond_init(&g_jack_midi_cond, NULL); */
591 /* if (ret != 0) */
592 /* { */
593 /* LOG_ERROR("Cannot initialize condition (variable)."); */
594 /* goto fail_uninit_mutex; */
595 /* } */
597 g_jack_midi_thread_exit = FALSE;
599 ret = pthread_create(&g_jack_midi_tid, NULL, jack_midi_thread, NULL);
600 if (ret != 0)
602 LOG_ERROR("Cannot start JACK MIDI thread.");
603 goto fail_uninit_cond;
606 g_jack_client = jack_client_open(name, JackNoStartServer, NULL);
607 if (g_jack_client == NULL)
609 LOG_ERROR("Cannot create JACK client.");
610 goto fail_stop_thread;
613 ret = jack_set_process_callback(g_jack_client, jack_process, 0);
614 if (ret != 0)
616 LOG_ERROR("Cannot set JACK process callback.");
617 goto fail_close;
620 g_jack_input_port = jack_port_register(g_jack_client, "midi_in", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0);
621 if (g_jack_input_port == NULL)
623 LOG_ERROR("Failed to create input JACK MIDI port");
624 goto fail_close;
627 ret = jack_activate(g_jack_client);
628 if (ret != 0)
630 LOG_ERROR("Cannot activate JACK client.");
631 goto fail_close;
634 return TRUE;
636 fail_close:
637 jack_client_close(g_jack_client);
639 fail_stop_thread:
640 jack_destroy_pending_events();
642 /* Tell jack_midi_thread to exit */
643 pthread_mutex_lock(&g_jack_midi_mutex);
644 g_jack_midi_thread_exit = TRUE;
645 pthread_mutex_unlock(&g_jack_midi_mutex);
647 /* wakeup jack_midi_thread */
648 /* pthread_cond_broadcast(&g_jack_midi_cond); */
650 /* wait thread to finish */
651 pthread_join(g_jack_midi_tid, NULL);
653 fail_uninit_cond:
654 /* pthread_cond_destroy(&g_jack_midi_cond); */
656 /* fail_uninit_mutex: */
657 pthread_mutex_destroy(&g_jack_midi_mutex);
659 fail_uninit_memory:
660 rtsafe_memory_uninit(g_memory);
662 fail:
663 return FALSE;
666 void
667 jack_uninit()
669 LOG_DEBUG("jack_uninit() called.");
671 jack_deactivate(g_jack_client);
673 jack_client_close(g_jack_client);
675 /* Tell jack_midi_thread to exit */
676 pthread_mutex_lock(&g_jack_midi_mutex);
677 g_jack_midi_thread_exit = TRUE;
678 pthread_mutex_unlock(&g_jack_midi_mutex);
680 /* wakeup jack_midi_thread */
681 /* pthread_cond_broadcast(&g_jack_midi_cond); */
683 /* wait thread to finish */
684 pthread_join(g_jack_midi_tid, NULL);
686 jack_destroy_pending_events();
688 /* pthread_cond_destroy(&g_jack_midi_cond); */
690 pthread_mutex_destroy(&g_jack_midi_mutex);
692 rtsafe_memory_uninit(g_memory);