summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--utils/lv2_jack_host.c105
-rw-r--r--wscript21
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;
}
diff --git a/wscript b/wscript
index 00747de..bd339e7 100644
--- a/wscript
+++ b/wscript
@@ -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)