diff options
-rw-r--r-- | utils/lv2_jack_host.c | 105 | ||||
-rw-r--r-- | wscript | 21 |
2 files changed, 116 insertions, 10 deletions
diff --git a/utils/lv2_jack_host.c b/utils/lv2_jack_host.c index bf5c6a2..6b99624 100644 --- a/utils/lv2_jack_host.c +++ b/utils/lv2_jack_host.c @@ -19,6 +19,7 @@ #define _XOPEN_SOURCE 500 #include <math.h> +#include <signal.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> @@ -35,6 +36,14 @@ #include "slv2-config.h" +#ifdef SLV2_JACK_SESSION +#include <jack/session.h> +#include <glib.h> + +GMutex* exit_mutex; +GCond* exit_cond; +#endif /* SLV2_JACK_SESSION */ + #define MIDI_BUFFER_SIZE 1024 enum PortType { @@ -162,7 +171,7 @@ create_port(struct JackHost* host, slv2_instance_connect_port(host->instance, port_index, port->ev_buffer); break; default: - // FIXME: check if port connection is optional and die if not + /* FIXME: check if port connection is optional and die if not */ slv2_instance_connect_port(host->instance, port_index, NULL); fprintf(stderr, "WARNING: Unknown port type, port not connected.\n"); } @@ -238,6 +247,46 @@ jack_process_cb(jack_nframes_t nframes, void* data) return 0; } +#ifdef SLV2_JACK_SESSION +void +jack_session_cb(jack_session_event_t* event, void* arg) +{ + struct JackHost* host = (struct JackHost*)arg; + + char cmd[256]; + snprintf(cmd, sizeof(cmd), "lv2_jack_host %s %s", + slv2_value_as_uri(slv2_plugin_get_uri(host->plugin)), + event->client_uuid); + + event->command_line = strdup(cmd); + jack_session_reply(host->jack_client, event); + + switch (event->type) { + case JackSessionSave: + break; + case JackSessionSaveAndQuit: + g_mutex_lock(exit_mutex); + g_cond_signal(exit_cond); + g_mutex_unlock(exit_mutex); + break; + case JackSessionSaveTemplate: + break; + } + + jack_session_event_free(event); +} +#endif /* SLV2_JACK_SESSION */ + +static void +signal_handler(int ignored) +{ +#ifdef SLV2_JACK_SESSION + g_mutex_lock(exit_mutex); + g_cond_signal(exit_cond); + g_mutex_unlock(exit_mutex); +#endif +} + int main(int argc, char** argv) { @@ -246,6 +295,17 @@ main(int argc, char** argv) host.num_ports = 0; host.ports = NULL; +#ifdef SLV2_JACK_SESSION + if (!g_thread_supported()) { + g_thread_init(NULL); + } + exit_mutex = g_mutex_new(); + exit_cond = g_cond_new(); +#endif + + signal(SIGINT, signal_handler); + signal(SIGTERM, signal_handler); + /* Find all installed plugins */ SLV2World world = slv2_world_new(); slv2_world_load_all(world); @@ -261,15 +321,19 @@ main(int argc, char** argv) host.optional = slv2_value_new_uri(world, SLV2_NAMESPACE_LV2 "connectionOptional"); - /* Find the plugin to run */ - const char* plugin_uri_str = (argc == 2) ? argv[1] : NULL; - if (!plugin_uri_str) { - fprintf(stderr, "\nYou must specify a plugin URI to load.\n"); - fprintf(stderr, "\nUse lv2_list to list installed plugins.\n"); +#ifdef SLV2_JACK_SESSION + if (argc != 2 && argc != 3) { + fprintf(stderr, "Usage: %s PLUGIN_URI [JACK_UUID]\n", argv[0]); +#else + if (argc != 2) { + fprintf(stderr, "Usage: %s PLUGIN_URI\n", argv[0]); +#endif slv2_world_free(world); return EXIT_FAILURE; } + const char* const plugin_uri_str = argv[1]; + printf("Plugin: %s\n", plugin_uri_str); SLV2Value plugin_uri = slv2_value_new_uri(world, plugin_uri_str); @@ -297,7 +361,17 @@ main(int argc, char** argv) /* Connect to JACK */ printf("JACK Name: %s\n\n", jack_name); - host.jack_client = jack_client_open(jack_name, JackNullOption, NULL); +#ifdef SLV2_JACK_SESSION + const char* const jack_uuid_str = (argc > 2) ? argv[2] : NULL; + if (jack_uuid_str) { + host.jack_client = jack_client_open(jack_name, JackSessionID, NULL, + jack_uuid_str); + } +#endif + + if (!host.jack_client) { + host.jack_client = jack_client_open(jack_name, JackNullOption, NULL); + } free(jack_name); slv2_value_free(name); @@ -312,6 +386,9 @@ main(int argc, char** argv) die("Failed to instantiate plugin.\n"); jack_set_process_callback(host.jack_client, &jack_process_cb, (void*)(&host)); +#ifdef SLV2_JACK_SESSION + jack_set_session_callback(host.jack_client, &jack_session_cb, (void*)(&host)); +#endif /* Create ports */ host.num_ports = slv2_plugin_get_num_ports(host.plugin); @@ -330,14 +407,21 @@ main(int argc, char** argv) jack_activate(host.jack_client); /* Run */ +#ifdef SLV2_JACK_SESSION + printf("\nPress Ctrl-C to quit: "); + fflush(stdout); + g_cond_wait(exit_cond, exit_mutex); +#else printf("\nPress enter to quit: "); + fflush(stdout); getc(stdin); +#endif printf("\n"); /* Deactivate JACK */ jack_deactivate(host.jack_client); - for (unsigned long i = 0; i < host.num_ports; ++i) { + for (uint32_t i = 0; i < host.num_ports; ++i) { if (host.ports[i].jack_port != NULL) { jack_port_unregister(host.jack_client, host.ports[i].jack_port); host.ports[i].jack_port = NULL; @@ -364,5 +448,10 @@ main(int argc, char** argv) slv2_plugins_free(world, plugins); slv2_world_free(world); +#ifdef SLV2_JACK_SESSION + g_mutex_free(exit_mutex); + g_cond_free(exit_cond); +#endif + return 0; } @@ -46,16 +46,21 @@ def options(opt): help="Do not build command line utilities") opt.add_option('--no-jack', action='store_true', default=False, dest='no_jack', help="Do not build JACK clients") + opt.add_option('--no-jack-session', action='store_true', default=False, + dest='no_jack_session', + help="Do not build JACK session support") opt.add_option('--no-swig', action='store_true', default=False, dest='no_swig', help="Do not build python bindings") - opt.add_option('--dyn-manifest', action='store_true', default=False, dest='dyn_manifest', + opt.add_option('--dyn-manifest', action='store_true', default=False, + dest='dyn_manifest', help="Build support for dynamic manifest extension [false]") opt.add_option('--test', action='store_true', default=False, dest='build_tests', help="Build unit tests") opt.add_option('--no-bash-completion', action='store_true', default=False, dest='no_bash_completion', help="Install bash completion script in /etc/bash_completion.d") - opt.add_option('--default-lv2-path', type='string', default='', dest='default_lv2_path', + opt.add_option('--default-lv2-path', type='string', default='', + dest='default_lv2_path', help="Default LV2 path to use if $LV2_PATH is unset (globs and ~ supported)") def configure(conf): @@ -75,12 +80,16 @@ def configure(conf): autowaf.check_pkg(conf, 'lv2core', uselib_store='LV2CORE', mandatory=True) autowaf.check_pkg(conf, 'glib-2.0', uselib_store='GLIB', atleast_version='2.0.0', mandatory=True) + autowaf.check_pkg(conf, 'gthread-2.0', uselib_store='GTHREAD', + atleast_version='2.0.0', mandatory=False) autowaf.check_pkg(conf, 'serd', uselib_store='SERD', atleast_version='0.1.0', mandatory=True) autowaf.check_pkg(conf, 'sord', uselib_store='SORD', atleast_version='0.1.0', mandatory=True) autowaf.check_pkg(conf, 'jack', uselib_store='JACK', atleast_version='0.107.0', mandatory=False) + autowaf.check_pkg(conf, 'jack', uselib_store='NEW_JACK', + atleast_version='0.120.0', mandatory=False) autowaf.check_header(conf, 'lv2/lv2plug.in/ns/lv2core/lv2.h') autowaf.check_header(conf, 'lv2/lv2plug.in/ns/extensions/ui/ui.h', @@ -89,6 +98,10 @@ def configure(conf): if conf.env['HAVE_UI_H']: autowaf.define(conf, 'SLV2_WITH_UI', 1) + if not Options.options.no_jack_session: + if conf.env['HAVE_NEW_JACK'] and conf.env['HAVE_GTHREAD']: + autowaf.define(conf, 'SLV2_JACK_SESSION', 1) + conf.env.append_value('CFLAGS', '-std=c99') autowaf.define(conf, 'SLV2_VERSION', SLV2_VERSION) if Options.options.dyn_manifest: @@ -146,6 +159,8 @@ def configure(conf): bool(conf.env['BUILD_UTILS'])) autowaf.display_msg(conf, "Jack clients", bool(conf.env['USE_JACK'])) + autowaf.display_msg(conf, "Jack session support", + bool(conf.env['SLV2_JACK_SESSION'])) autowaf.display_msg(conf, "Unit tests", bool(conf.env['BUILD_TESTS'])) autowaf.display_msg(conf, "Dynamic manifest support", @@ -243,6 +258,8 @@ def build(bld): obj.use = 'libslv2' obj.target = 'utils/lv2_jack_host' obj.install_path = '${BINDIR}' + if bld.env['SLV2_JACK_SESSION']: + autowaf.use_lib(bld, obj, 'GLIB GTHREAD') # Documentation autowaf.build_dox(bld, 'SLV2', SLV2_VERSION, top, out) |