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