1 #ifdef _HAVE_JACK_
2 /*
3  * jackbackend.c
4  * JACK audio and MIDI backends.
5  *
6  * for Denemo, a gtk+ frontend to GNU Lilypond
7  * Copyright (C) 2011  Dominic Sacré
8  *
9  * This program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  */
14 
15 #include "audio/jackbackend.h"
16 #include "audio/midi.h"
17 #include "audio/fluid.h"
18 #include <jack/jack.h>
19 #include <jack/midiport.h>
20 #include <glib.h>
21 #include <string.h>
22 #include <assert.h>
23 
24 
25 typedef jack_default_audio_sample_t sample_t;
26 typedef jack_nframes_t nframes_t;
27 
28 
29 static char const *JACK_CLIENT_NAME = "denemo";
30 
31 static jack_client_t *client = NULL;
32 
33 static jack_port_t **audio_in_ports = NULL;
34 static jack_port_t **audio_out_ports = NULL;
35 static jack_port_t **midi_in_ports = NULL;
36 static jack_port_t **midi_out_ports = NULL;
37 
38 static size_t num_audio_in_ports;
39 static size_t num_audio_out_ports;
40 static size_t num_midi_in_ports;
41 static size_t num_midi_out_ports;
42 
43 static gboolean audio_initialized = FALSE;
44 static gboolean midi_initialized = FALSE;
45 
46 static nframes_t playback_frame = 0;
47 
48 static gboolean reset_audio = FALSE;
49 static gboolean reset_midi = FALSE;
50 
51 
52 static double
nframes_to_seconds(nframes_t nframes)53 nframes_to_seconds (nframes_t nframes)
54 {
55   return nframes / (double) jack_get_sample_rate (client);
56 }
57 
58 static nframes_t
seconds_to_nframes(double seconds)59 seconds_to_nframes (double seconds)
60 {
61   return (nframes_t) (jack_get_sample_rate (client) * seconds);
62 }
63 
64 
65 static void
process_audio(nframes_t nframes)66 process_audio (nframes_t nframes)
67 {
68   size_t i;
69   sample_t *port_buffers[num_audio_out_ports];
70 
71   for (i = 0; i < num_audio_out_ports; ++i)
72     {
73       port_buffers[i] = jack_port_get_buffer (audio_out_ports[i], nframes);
74       //memset(port_buffers[i], 0, nframes * sizeof(sample_t));
75       jack_midi_clear_buffer (port_buffers[i]);
76     }
77 
78 #ifdef _HAVE_FLUIDSYNTH_
79   if (reset_audio)
80     {
81       fluidsynth_all_notes_off ();
82       reset_audio = FALSE;
83       return;
84     }
85 
86   unsigned char event_data[3];
87   size_t event_length;
88   double event_time;
89 
90   double until_time = nframes_to_seconds (playback_frame + nframes);
91 
92   while (read_event_from_queue (AUDIO_BACKEND, event_data, &event_length, &event_time, until_time))
93     {
94       // FIXME: we can't pass an exact frame/time to fluidsynth, can we...?
95       fluidsynth_feed_midi (event_data, event_length);
96     }
97 
98 
99   assert (num_audio_out_ports >= 2);
100 
101   fluidsynth_render_audio (nframes, port_buffers[0], port_buffers[1]);
102 #endif
103 }
104 
105 
106 static void
process_midi_input(nframes_t nframes)107 process_midi_input (nframes_t nframes)
108 {
109   size_t i, n;
110   jack_midi_event_t ev;
111 
112   for (i = 0; i < num_midi_in_ports; ++i)
113     {
114       void *port_buffer = jack_port_get_buffer (midi_in_ports[i], nframes);
115 
116       size_t num_events = jack_midi_get_event_count (port_buffer);
117 
118       for (n = 0; n < num_events; ++n)
119         {
120           jack_midi_event_get (&ev, port_buffer, n);
121 
122           input_midi_event (MIDI_BACKEND, i, ev.buffer);
123         }
124     }
125 }
126 
127 
128 static void
process_midi_output(nframes_t nframes)129 process_midi_output (nframes_t nframes)
130 {
131   size_t i;
132   void *port_buffers[num_midi_out_ports];
133 
134   for (i = 0; i < num_midi_out_ports; ++i)
135     {
136       port_buffers[i] = jack_port_get_buffer (midi_out_ports[i], nframes);
137       jack_midi_clear_buffer (port_buffers[i]);
138     }
139 
140   if (reset_midi)
141     {
142       // send all-notes-off on all ports and on all channels
143       for (i = 0; i < num_midi_out_ports; ++i)
144         {
145           int n;
146           for (n = 0; n < 16; ++n)
147             {
148               unsigned char event_data[] = { MIDI_CONTROL_CHANGE | n, 123, 0 };
149 
150               jack_midi_event_write (port_buffers[i], 0, event_data, sizeof (event_data));
151             }
152         }
153 
154       reset_midi = FALSE;
155 
156       return;
157     }
158 
159   unsigned char event_data[3];
160   size_t event_length;
161   double event_time;
162 
163   double until_time = nframes_to_seconds (playback_frame + nframes);
164 
165   while (read_event_from_queue (MIDI_BACKEND, event_data, &event_length, &event_time, until_time))
166     {
167       nframes_t frame;
168       if (event_time == 0.0)
169         {
170           frame = 0;
171         }
172       else
173         {
174           frame = seconds_to_nframes (event_time) - playback_frame;
175         }
176 
177       // FIXME: use correct port
178       jack_midi_event_write (port_buffers[0], frame, event_data, event_length);
179     }
180 }
181 
182 
183 
184 
185 static int
process_callback(nframes_t nframes,void * arg)186 process_callback (nframes_t nframes, void *arg)
187 {
188   if (g_atomic_int_get (&audio_initialized))
189     {
190       process_audio (nframes);
191     }
192   if (g_atomic_int_get (&midi_initialized))
193     {
194       process_midi_input (nframes);
195       process_midi_output (nframes);
196     }
197 
198   if (is_playing ())
199     {
200       playback_frame += nframes;
201 
202       update_playback_time (TIMEBASE_PRIO_AUDIO, nframes_to_seconds (playback_frame));
203     }
204 
205   return 0;
206 }
207 
208 
209 static void
shutdown_callback(void * arg)210 shutdown_callback (void *arg)
211 {
212   g_warning ("*** shut down by JACK! ***");
213 
214   g_atomic_int_set (&audio_initialized, FALSE);
215   g_atomic_int_set (&midi_initialized, FALSE);
216 }
217 
218 
219 
220 static int
initialize_client(char const * name)221 initialize_client (char const *name)
222 {
223   if (client)
224     {
225       // already initialized
226       return 0;
227     }
228 
229   if ((client = jack_client_open (name, JackNullOption, NULL)) == NULL)
230     {
231       g_warning ("Can't connect to jack server");
232       return -1;
233     }
234 
235   jack_set_process_callback (client, &process_callback, NULL);
236   jack_on_shutdown (client, &shutdown_callback, NULL);
237 
238   if (jack_activate (client))
239     {
240       g_warning ("Can't activate jack client");
241       return -1;
242     }
243 
244   return 0;
245 }
246 
247 
248 static int
destroy_client()249 destroy_client ()
250 {
251   if (g_atomic_int_get (&audio_initialized) || g_atomic_int_get (&midi_initialized))
252     {
253       // don't destroy client if someone's still using it
254       return 0;
255     }
256 
257   if (client)
258     {
259       jack_deactivate (client);
260       jack_client_close (client);
261       client = NULL;
262     }
263 
264   return 0;
265 }
266 
267 
268 static int
unregister_audio_ports()269 unregister_audio_ports ()
270 {
271   jack_port_t **p;
272 
273   for (p = audio_in_ports; *p != NULL; ++p)
274     {
275       jack_port_unregister (client, *p);
276     }
277 
278   for (p = audio_out_ports; *p != NULL; ++p)
279     {
280       jack_port_unregister (client, *p);
281     }
282 
283   g_free (audio_in_ports);
284   g_free (audio_out_ports);
285 
286   audio_in_ports = NULL;
287   audio_out_ports = NULL;
288 
289   return 0;
290 }
291 
292 
293 static int
register_audio_ports(int num_in_ports,char const * in_portnames[],int num_out_ports,char const * out_portnames[])294 register_audio_ports (int num_in_ports, char const *in_portnames[], int num_out_ports, char const *out_portnames[])
295 {
296   int n;
297 
298   // allocate one more item as an end-of-array marker
299   audio_in_ports = g_new0 (jack_port_t *, num_in_ports + 1);
300   audio_out_ports = g_new0 (jack_port_t *, num_out_ports + 1);
301   num_audio_in_ports = num_in_ports;
302   num_audio_out_ports = num_out_ports;
303 
304   for (n = 0; n < num_in_ports; ++n)
305     {
306       audio_in_ports[n] = jack_port_register (client, in_portnames[n], JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
307       if (audio_in_ports[n] == NULL)
308         {
309           goto err;
310         }
311     }
312   for (n = 0; n < num_out_ports; ++n)
313     {
314       audio_out_ports[n] = jack_port_register (client, out_portnames[n], JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
315       if (audio_out_ports[n] == NULL)
316         {
317           goto err;
318         }
319     }
320 
321   return 0;
322 
323 err:
324   unregister_audio_ports ();
325 
326   return -1;
327 }
328 
329 
330 static int
connect_audio_ports(char const * connect_ports_l,char const * connect_ports_r)331 connect_audio_ports (char const *connect_ports_l, char const *connect_ports_r)
332 {
333   if (jack_connect (client, jack_port_name (audio_out_ports[0]), connect_ports_l))
334     {
335       return -1;
336     }
337 
338   if (jack_connect (client, jack_port_name (audio_out_ports[1]), connect_ports_r))
339     {
340       return -1;
341     }
342 
343   return 0;
344 }
345 
346 
347 static int
unregister_midi_ports()348 unregister_midi_ports ()
349 {
350   jack_port_t **p;
351 
352   for (p = midi_in_ports; *p != NULL; ++p)
353     {
354       jack_port_unregister (client, *p);
355     }
356 
357   for (p = midi_out_ports; *p != NULL; ++p)
358     {
359       jack_port_unregister (client, *p);
360     }
361 
362   g_free (midi_in_ports);
363   g_free (midi_out_ports);
364 
365   midi_in_ports = NULL;
366   midi_out_ports = NULL;
367 
368   return 0;
369 }
370 
371 
372 static int
register_midi_ports(int num_in_ports,char const * in_portnames[],int num_out_ports,char const * out_portnames[])373 register_midi_ports (int num_in_ports, char const *in_portnames[], int num_out_ports, char const *out_portnames[])
374 {
375   int n;
376 
377   // allocate one more item as an end-of-array marker
378   midi_in_ports = g_new0 (jack_port_t *, num_in_ports + 1);
379   midi_out_ports = g_new0 (jack_port_t *, num_out_ports + 1);
380   num_midi_in_ports = num_in_ports;
381   num_midi_out_ports = num_out_ports;
382 
383   for (n = 0; n < num_in_ports; ++n)
384     {
385       midi_in_ports[n] = jack_port_register (client, in_portnames[n], JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0);
386       if (midi_in_ports[n] == NULL)
387         {
388           goto err;
389         }
390     }
391   for (n = 0; n < num_out_ports; ++n)
392     {
393       midi_out_ports[n] = jack_port_register (client, out_portnames[n], JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0);
394       if (midi_out_ports[n] == NULL)
395         {
396           goto err;
397         }
398     }
399 
400   return 0;
401 
402 err:
403   unregister_midi_ports ();
404 
405   return -1;
406 }
407 
408 
409 static int
connect_midi_ports(char const * connect_input_port,char const * connect_output_port)410 connect_midi_ports (char const *connect_input_port, char const *connect_output_port)
411 {
412   int ret = 0;
413 
414   if (strlen (connect_input_port))
415     {
416       if (jack_connect (client, connect_input_port, jack_port_name (midi_in_ports[0])))
417         {
418           ret = -1;
419         }
420     }
421 
422   if (strlen (connect_output_port))
423     {
424       if (jack_connect (client, jack_port_name (midi_out_ports[0]), connect_output_port))
425         {
426           ret = -1;
427         }
428     }
429 
430   return ret;
431 }
432 
433 
434 static int
jack_audio_initialize(DenemoPrefs * config)435 jack_audio_initialize (DenemoPrefs * config)
436 {
437   g_message ("Initializing JACK audio backend");
438 
439   if (initialize_client (JACK_CLIENT_NAME))
440     {
441       return -1;
442     }
443 
444 #ifdef _HAVE_FLUIDSYNTH_
445   if (fluidsynth_init (config, jack_get_sample_rate (client)))
446     {
447       return -1;
448     }
449 #endif
450 
451   // mono input, stereo output
452   char const *in_portnames[] = { "in_1" };
453   char const *out_portnames[] = { "out_1", "out_2" };
454 
455   if (register_audio_ports (1, in_portnames, 2, out_portnames))
456     {
457       return -1;
458     }
459 
460   if (connect_audio_ports (config->jack_connect_ports_l->str, config->jack_connect_ports_r->str))
461     {
462       g_warning ("Could not connect audio output ports");
463     }
464 
465   g_atomic_int_set (&audio_initialized, TRUE);
466 
467   return 0;
468 }
469 
470 
471 static int
jack_audio_destroy()472 jack_audio_destroy ()
473 {
474   g_message ("Destroying JACK audio backend");
475 
476   if (g_atomic_int_get (&audio_initialized))
477     {
478       g_atomic_int_set (&audio_initialized, FALSE);
479 
480       unregister_audio_ports ();
481     }
482 
483   destroy_client ();
484 
485 #ifdef _HAVE_FLUIDSYNTH_
486   fluidsynth_shutdown ();
487 #endif
488 
489   return 0;
490 }
491 
492 
493 static int
jack_audio_reconfigure(DenemoPrefs * config)494 jack_audio_reconfigure (DenemoPrefs * config)
495 {
496   jack_audio_destroy ();
497   return jack_audio_initialize (config);
498 }
499 
500 
501 static int
jack_audio_start_playing()502 jack_audio_start_playing ()
503 {
504   playback_frame = seconds_to_nframes (get_playback_time ());
505   return 0;
506 }
507 
508 
509 static int
jack_audio_stop_playing()510 jack_audio_stop_playing ()
511 {
512   reset_audio = TRUE;
513   return 0;
514 }
515 
516 
517 static int
jack_audio_panic()518 jack_audio_panic ()
519 {
520   reset_audio = TRUE;
521   return 0;
522 }
523 
524 
525 
526 static int
jack_midi_initialize(DenemoPrefs * config)527 jack_midi_initialize (DenemoPrefs * config)
528 {
529   g_message ("Initializing JACK MIDI backend");
530 
531   if (initialize_client (JACK_CLIENT_NAME))
532     {
533       return -1;
534     }
535 
536   // FIXME: get port names from config
537   char const *in_portnames[] = { "midi_in_1" };
538   char const *out_portnames[] = { "midi_out_1" };
539 
540   if (register_midi_ports (1, in_portnames, 1, out_portnames))
541     {
542       return -1;
543     }
544 
545   if (connect_midi_ports (config->jack_connect_midi_in_port->str, config->jack_connect_midi_out_port->str))
546     {
547       g_warning ("Could not connect MIDI port(s)");
548     }
549 
550   g_atomic_int_set (&midi_initialized, TRUE);
551 
552   return 0;
553 }
554 
555 
556 static int
jack_midi_destroy()557 jack_midi_destroy ()
558 {
559   g_message ("Destroying JACK MIDI backend");
560 
561   if (g_atomic_int_get (&midi_initialized))
562     {
563       g_atomic_int_set (&midi_initialized, FALSE);
564 
565       unregister_midi_ports ();
566     }
567 
568   destroy_client ();
569 
570   return 0;
571 }
572 
573 
574 static int
jack_midi_reconfigure(DenemoPrefs * config)575 jack_midi_reconfigure (DenemoPrefs * config)
576 {
577   g_message ("Reconfiguring JACK MIDI backend");
578 
579   jack_midi_destroy ();
580   jack_midi_initialize (config);
581 
582   return 0;
583 }
584 
585 
586 static int
jack_midi_start_playing()587 jack_midi_start_playing ()
588 {
589   playback_frame = seconds_to_nframes (get_playback_time ());
590   return 0;
591 }
592 
593 
594 static int
jack_midi_stop_playing()595 jack_midi_stop_playing ()
596 {
597   reset_midi = TRUE;
598   return 0;
599 }
600 
601 
602 static int
jack_midi_panic()603 jack_midi_panic ()
604 {
605   reset_midi = TRUE;
606   return 0;
607 }
608 
609 
610 backend_t jack_audio_backend = {
611   jack_audio_initialize,
612   jack_audio_destroy,
613   jack_audio_reconfigure,
614   jack_audio_start_playing,
615   jack_audio_stop_playing,
616   jack_audio_panic,
617 };
618 
619 backend_t jack_midi_backend = {
620   jack_midi_initialize,
621   jack_midi_destroy,
622   jack_midi_reconfigure,
623   jack_midi_start_playing,
624   jack_midi_stop_playing,
625   jack_midi_panic,
626 };
627 
628 #endif //_HAVE_JACK_
629