summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2011-02-17 10:30:08 +0000
committerDavid Robillard <d@drobilla.net>2011-02-17 10:30:08 +0000
commite668b8c846175f90cf22b456c5e5a4cc85410da4 (patch)
tree613d2e37d4ef359d2f572bfc4bfd43e6acff43c7
parent4c6269aeaf39f1a5c7473c22ff0417d50decfdc3 (diff)
downloadingen-e668b8c846175f90cf22b456c5e5a4cc85410da4.tar.gz
ingen-e668b8c846175f90cf22b456c5e5a4cc85410da4.tar.bz2
ingen-e668b8c846175f90cf22b456c5e5a4cc85410da4.zip
Jack session support for ingen.
git-svn-id: http://svn.drobilla.net/lad/trunk/ingen@2978 a436a847-0d15-0410-975c-d299462d15a1
-rw-r--r--src/engine/Engine.cpp4
-rw-r--r--src/engine/JackDriver.cpp71
-rw-r--r--src/engine/JackDriver.hpp13
-rw-r--r--src/engine/ingen_lv2.cpp11
-rw-r--r--src/gui/App.cpp7
-rw-r--r--src/gui/ThreadedLoader.cpp6
-rw-r--r--src/ingen/main.cpp8
-rw-r--r--src/module/World.cpp20
-rw-r--r--src/module/World.hpp5
-rw-r--r--src/serialisation/Parser.cpp67
-rw-r--r--src/serialisation/Parser.hpp10
-rw-r--r--src/shared/Configuration.cpp6
-rw-r--r--wscript10
13 files changed, 185 insertions, 53 deletions
diff --git a/src/engine/Engine.cpp b/src/engine/Engine.cpp
index 74c9b12b..8e0d7e0e 100644
--- a/src/engine/Engine.cpp
+++ b/src/engine/Engine.cpp
@@ -110,8 +110,8 @@ Engine::main()
{
Raul::Thread::get().set_context(THREAD_POST_PROCESS);
- // Loop until quit flag is set (by OSCReceiver)
- while ( ! _quit_flag) {
+ // Loop until quit flag is set
+ while (!_quit_flag) {
nanosleep(&main_rate, NULL);
main_iteration();
}
diff --git a/src/engine/JackDriver.cpp b/src/engine/JackDriver.cpp
index 638217fc..d83c319f 100644
--- a/src/engine/JackDriver.cpp
+++ b/src/engine/JackDriver.cpp
@@ -15,10 +15,17 @@
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include "ingen-config.h"
+
#include <cstdlib>
#include <string>
#include <jack/midiport.h>
+#ifdef INGEN_JACK_SESSION
+#include <jack/session.h>
+#include <boost/format.hpp>
+#include "serialisation/Serialiser.hpp"
+#endif
#include "raul/log.hpp"
#include "raul/List.hpp"
@@ -38,7 +45,6 @@
#include "ProcessSlave.hpp"
#include "QueuedEvent.hpp"
#include "ThreadManager.hpp"
-#include "ingen-config.h"
#include "module/World.hpp"
#include "shared/LV2Features.hpp"
#include "shared/LV2URIMap.hpp"
@@ -224,20 +230,30 @@ JackDriver::attach(const std::string& server_name,
{
assert(!_client);
if (!jack_client) {
- // Try supplied server name
- if (!server_name.empty()) {
+ #ifdef INGEN_JACK_SESSION
+ const std::string uuid = _engine.world()->jack_uuid();
+ if (!uuid.empty()) {
_client = jack_client_open(client_name.c_str(),
- JackServerName, NULL, server_name.c_str());
- if (_client)
- LOG(info) << "Connected to JACK server `" << server_name << "'" << endl;
+ JackSessionID, NULL,
+ uuid.c_str());
+ LOG(info) << "Connected to JACK server as client `"
+ << client_name.c_str() << "' UUID `" << uuid << "'" << endl;
}
+ #endif
+ // Try supplied server name
+ if (!_client && !server_name.empty()) {
+ if ((_client = jack_client_open(client_name.c_str(),
+ JackServerName, NULL,
+ server_name.c_str()))) {
+ LOG(info) << "Connected to JACK server `" << server_name << "'" << endl;
+ }
+ }
+
// Either server name not specified, or supplied server name does not exist
// Connect to default server
if (!_client) {
- _client = jack_client_open(client_name.c_str(), JackNullOption, NULL);
-
- if (_client)
+ if ((_client = jack_client_open(client_name.c_str(), JackNullOption, NULL)))
LOG(info) << "Connected to default JACK server" << endl;
}
@@ -260,6 +276,9 @@ JackDriver::attach(const std::string& server_name,
jack_set_thread_init_callback(_client, thread_init_cb, this);
jack_set_sample_rate_callback(_client, sample_rate_cb, this);
jack_set_buffer_size_callback(_client, block_length_cb, this);
+#ifdef INGEN_JACK_SESSION
+ jack_set_session_callback(_client, session_cb, this);
+#endif
for (Raul::List<JackPort*>::iterator i = _ports.begin(); i != _ports.end(); ++i)
(*i)->create();
@@ -524,4 +543,38 @@ JackDriver::_block_length_cb(jack_nframes_t nframes)
}
+#ifdef INGEN_JACK_SESSION
+void
+JackDriver::_session_cb(jack_session_event_t* event)
+{
+ LOG(info) << "Jack session save to " << event->session_dir << endl;
+
+ const string cmd = (boost::format("ingen -eg -n %1% -u %2% -l ${SESSION_DIR}")
+ % jack_get_client_name(_client)
+ % event->client_uuid).str();
+
+ SharedPtr<Serialisation::Serialiser> serialiser = _engine.world()->serialiser();
+ if (serialiser) {
+ SharedPtr<Patch> root(_engine.driver()->root_patch(), NullDeleter<Patch>);
+ serialiser->write_bundle(root, string("file://") + event->session_dir);
+ }
+
+ event->command_line = strdup(cmd.c_str());
+ jack_session_reply(_client, event);
+
+ switch (event->type) {
+ case JackSessionSave:
+ break;
+ case JackSessionSaveAndQuit:
+ LOG(warn) << "Jack session quit" << endl;
+ _engine.quit();
+ break;
+ case JackSessionSaveTemplate:
+ break;
+ }
+
+ jack_session_event_free(event);
+}
+#endif
+
} // namespace Ingen
diff --git a/src/engine/JackDriver.hpp b/src/engine/JackDriver.hpp
index 1d47a8fc..b10efad1 100644
--- a/src/engine/JackDriver.hpp
+++ b/src/engine/JackDriver.hpp
@@ -18,10 +18,15 @@
#ifndef INGEN_ENGINE_JACKAUDIODRIVER_HPP
#define INGEN_ENGINE_JACKAUDIODRIVER_HPP
+#include "ingen-config.h"
+
#include <string>
#include <jack/jack.h>
#include <jack/transport.h>
+#ifdef INGEN_JACK_SESSION
+#include <jack/session.h>
+#endif
#include "raul/AtomicInt.hpp"
#include "raul/List.hpp"
@@ -143,6 +148,11 @@ private:
inline static int sample_rate_cb(jack_nframes_t nframes, void* const jack_driver) {
return ((JackDriver*)jack_driver)->_sample_rate_cb(nframes);
}
+#ifdef INGEN_JACK_SESSION
+ inline static void session_cb(jack_session_event_t* event, void* jack_driver) {
+ ((JackDriver*)jack_driver)->_session_cb(event);
+ }
+#endif
// Non static callbacks (methods)
void _thread_init_cb();
@@ -150,6 +160,9 @@ private:
int _process_cb(jack_nframes_t nframes);
int _block_length_cb(jack_nframes_t nframes);
int _sample_rate_cb(jack_nframes_t nframes);
+#ifdef INGEN_JACK_SESSION
+ void _session_cb(jack_session_event_t* event);
+#endif
Engine& _engine;
Raul::Thread* _jack_thread;
diff --git a/src/engine/ingen_lv2.cpp b/src/engine/ingen_lv2.cpp
index 3b62eca9..8b9fd90d 100644
--- a/src/engine/ingen_lv2.cpp
+++ b/src/engine/ingen_lv2.cpp
@@ -293,9 +293,9 @@ ingen_instantiate(const LV2_Descriptor* descriptor,
interface->process(*engine->post_processor(), context, false);
engine->post_processor()->process();
- plugin->world->parser()->parse_document(plugin->world,
- plugin->world->engine().get(),
- patch->filename);
+ plugin->world->parser()->parse_file(plugin->world,
+ plugin->world->engine().get(),
+ patch->filename);
while (!interface->empty()) {
interface->process(*engine->post_processor(), context, false);
@@ -402,8 +402,9 @@ Lib::Lib()
Shared::bundle_file_path("manifest.ttl"))));
for (Records::iterator i = records.begin(); i != records.end(); ++i) {
- patches.push_back(SharedPtr<const LV2Patch>(
- new LV2Patch(i->uri.str(), i->filename)));
+ patches.push_back(
+ SharedPtr<const LV2Patch>(new LV2Patch(i->patch_uri.str(),
+ i->file_uri)));
}
ingen_world_free(world);
diff --git a/src/gui/App.cpp b/src/gui/App.cpp
index 9c9864cb..28e72a5f 100644
--- a/src/gui/App.cpp
+++ b/src/gui/App.cpp
@@ -261,7 +261,7 @@ App::activity_port_destroyed(Port* port)
bool
App::animate()
{
- for (ActivityPorts::iterator i = _activity_ports.begin(); i != _activity_ports.end() ; ) {
+ for (ActivityPorts::iterator i = _activity_ports.begin(); i != _activity_ports.end(); ) {
ActivityPorts::iterator next = i;
++next;
@@ -300,7 +300,10 @@ App::gtk_main_iteration()
return false;
if (_world->local_engine()) {
- _world->local_engine()->main_iteration();
+ if (!_world->local_engine()->main_iteration()) {
+ Gtk::Main::quit();
+ return false;
+ }
} else {
_enable_signal = false;
_client->emit_signals();
diff --git a/src/gui/ThreadedLoader.cpp b/src/gui/ThreadedLoader.cpp
index 10f1f8d6..2a9646e2 100644
--- a/src/gui/ThreadedLoader.cpp
+++ b/src/gui/ThreadedLoader.cpp
@@ -93,7 +93,8 @@ ThreadedLoader::load_patch(bool merge,
// Filthy hack to load deprecated patches based on file extension
if (document_uri.substr(document_uri.length()-3) == ".om") {
_events.push_back(sigc::hide_return(sigc::bind(
- sigc::mem_fun(_deprecated_loader, &DeprecatedLoader::load_patch),
+ sigc::mem_fun(_deprecated_loader,
+ &DeprecatedLoader::load_patch),
document_uri,
merge,
engine_parent,
@@ -102,7 +103,8 @@ ThreadedLoader::load_patch(bool merge,
false)));
} else {
_events.push_back(sigc::hide_return(sigc::bind(
- sigc::mem_fun(world->parser().get(), &Ingen::Serialisation::Parser::parse_document),
+ sigc::mem_fun(world->parser().get(),
+ &Ingen::Serialisation::Parser::parse_file),
App::instance().world(),
App::instance().world()->engine().get(),
document_uri,
diff --git a/src/ingen/main.cpp b/src/ingen/main.cpp
index fa638063..0a3129a6 100644
--- a/src/ingen/main.cpp
+++ b/src/ingen/main.cpp
@@ -108,6 +108,12 @@ main(int argc, char** argv)
Ingen::Shared::World* world = ingen_world_new(&conf, argc, argv);
+#if INGEN_JACK_SESSION
+ if (conf.option("uuid").get_string()) {
+ world->set_jack_uuid(conf.option("uuid").get_string());
+ }
+#endif
+
// Run engine
if (conf.option("engine").get_bool()) {
ingen_try(world->load("ingen_engine"),
@@ -190,7 +196,7 @@ main(int argc, char** argv)
engine_interface->load_plugins();
if (conf.option("gui").get_bool())
engine_interface->get("ingen:plugins");
- world->parser()->parse_document(
+ world->parser()->parse_file(
world, engine_interface.get(), uri, data_path, parent, symbol);
}
diff --git a/src/module/World.cpp b/src/module/World.cpp
index 4cdb9272..d8721f5f 100644
--- a/src/module/World.cpp
+++ b/src/module/World.cpp
@@ -176,6 +176,9 @@ struct WorldImpl : public boost::noncopyable {
#ifdef HAVE_SLV2
SLV2World slv2_world;
#endif
+#ifdef INGEN_JACK_SESSION
+ std::string jack_uuid;
+#endif
};
@@ -281,6 +284,23 @@ World::add_interface_factory(const std::string& scheme, InterfaceFactory factory
}
+#ifdef INGEN_JACK_SESSION
+
+void
+World::set_jack_uuid(const std::string& uuid)
+{
+ _impl->jack_uuid = uuid;
+}
+
+
+std::string
+World::jack_uuid()
+{
+ return _impl->jack_uuid;
+}
+
+#endif // INGEN_JACK_SESSION
+
} // namespace Shared
} // namespace Ingen
diff --git a/src/module/World.hpp b/src/module/World.hpp
index 1345f3da..a2eb5d40 100644
--- a/src/module/World.hpp
+++ b/src/module/World.hpp
@@ -106,6 +106,11 @@ public:
#ifdef HAVE_SLV2
virtual SLV2World slv2_world();
#endif
+
+#ifdef INGEN_JACK_SESSION
+ virtual void set_jack_uuid(const std::string& uuid);
+ virtual std::string jack_uuid();
+#endif
};
diff --git a/src/serialisation/Parser.cpp b/src/serialisation/Parser.cpp
index 5b04a426..1fd67498 100644
--- a/src/serialisation/Parser.cpp
+++ b/src/serialisation/Parser.cpp
@@ -19,6 +19,8 @@
#include <set>
+#include <boost/format.hpp>
+
#include <glibmm/convert.h>
#include <glibmm/fileutils.h>
#include <glibmm/miscutils.h>
@@ -126,37 +128,48 @@ Parser::find_patches(Ingen::Shared::World* world,
* @return whether or not load was successful.
*/
bool
-Parser::parse_document(Ingen::Shared::World* world,
- Ingen::Shared::CommonInterface* target,
- Glib::ustring document_uri,
- boost::optional<Raul::Path> data_path,
- boost::optional<Raul::Path> parent,
- boost::optional<Raul::Symbol> symbol,
- boost::optional<GraphObject::Properties> data)
+Parser::parse_file(Ingen::Shared::World* world,
+ Ingen::Shared::CommonInterface* target,
+ Glib::ustring file_uri,
+ boost::optional<Raul::Path> data_path,
+ boost::optional<Raul::Path> parent,
+ boost::optional<Raul::Symbol> symbol,
+ boost::optional<GraphObject::Properties> data)
{
- normalise_uri(document_uri);
-
- if (document_uri.substr(document_uri.length() - 4) != ".ttl") {
- if (document_uri[document_uri.length() - 1] != '/') {
- document_uri.append("/");
+ normalise_uri(file_uri);
+
+ const size_t colon = file_uri.find(":");
+ Glib::ustring file_path = file_uri;
+ if (colon != Glib::ustring::npos) {
+ const Glib::ustring scheme = file_uri.substr(0, colon);
+ if (scheme != "file") {
+ LOG(error) << (boost::format("Unsupported URI scheme `%1%'") % scheme) << endl;
+ return false;
+ }
+ if (file_uri.substr(0, 7) == "file://") {
+ file_path = file_uri.substr(7);
+ } else {
+ file_path = file_uri.substr(5);
}
}
-
- const std::string filename(Glib::filename_from_uri(document_uri));
- const size_t ext = filename.find(INGEN_BUNDLE_EXT);
- const size_t ext_len = strlen(INGEN_BUNDLE_EXT);
- if (ext == filename.length() - ext_len
- || ((ext == filename.length() - ext_len - 1)
- && filename[filename.length() - 1] == '/')) {
- std::string basename(Glib::path_get_basename(filename));
- basename = basename.substr(0, basename.find('.'));
- document_uri += basename + INGEN_PATCH_FILE_EXT;
+
+ std::string filename = Glib::filename_from_uri(file_uri);
+
+ if (file_uri.substr(file_uri.length() - 4) != ".ttl") {
+ // Not a Turtle file, maybe a bundle, check for manifest
+ if (file_uri[file_uri.length() - 1] != '/') {
+ file_uri.append("/");
+ }
+ Parser::PatchRecords records = find_patches(world, file_uri + "manifest.ttl");
+ if (!records.empty()) {
+ filename = Glib::filename_from_uri(records.front().file_uri);
+ }
}
- Sord::Model model(*world->rdf_world(), document_uri);
- model.load_file(document_uri);
+ Sord::Model model(*world->rdf_world(), filename);
+ model.load_file(filename);
- LOG(info) << "Parsing " << document_uri << endl;
+ LOG(info) << "Parsing " << file_uri << endl;
if (data_path)
LOG(info) << "Path: " << *data_path << endl;
if (parent)
@@ -165,11 +178,11 @@ Parser::parse_document(Ingen::Shared::World* world,
LOG(info) << "Symbol: " << *symbol << endl;
boost::optional<Path> parsed_path
- = parse(world, target, model, document_uri, data_path, parent, symbol, data);
+ = parse(world, target, model, filename, data_path, parent, symbol, data);
if (parsed_path) {
target->set_property(*parsed_path, "http://drobilla.net/ns/ingen#document",
- Atom(Atom::URI, document_uri.c_str()));
+ Atom(Atom::URI, file_uri.c_str()));
} else {
LOG(warn) << "Document URI lost" << endl;
}
diff --git a/src/serialisation/Parser.hpp b/src/serialisation/Parser.hpp
index 103cd9a0..d9b33956 100644
--- a/src/serialisation/Parser.hpp
+++ b/src/serialisation/Parser.hpp
@@ -43,7 +43,7 @@ public:
typedef Shared::GraphObject::Properties Properties;
- virtual bool parse_document(
+ virtual bool parse_file(
Ingen::Shared::World* world,
Shared::CommonInterface* target,
Glib::ustring document_uri,
@@ -73,9 +73,11 @@ public:
boost::optional<Properties> data=boost::optional<Properties>());
struct PatchRecord {
- PatchRecord(const Raul::URI& u, const Glib::ustring& f) : uri(u), filename(f) {}
- const Raul::URI uri;
- const Glib::ustring filename;
+ PatchRecord(const Raul::URI& u, const Glib::ustring& f)
+ : patch_uri(u), file_uri(f)
+ {}
+ const Raul::URI patch_uri;
+ const Glib::ustring file_uri;
};
typedef std::list<PatchRecord> PatchRecords;
diff --git a/src/shared/Configuration.cpp b/src/shared/Configuration.cpp
index 273fd6ac..d1845a44 100644
--- a/src/shared/Configuration.cpp
+++ b/src/shared/Configuration.cpp
@@ -1,5 +1,5 @@
/* This file is part of Ingen.
- * Copyright (C) 2010 David Robillard <http://drobilla.net>
+ * Copyright (C) 2010-2011 David Robillard <http://drobilla.net>
*
* Ingen is free software; you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
@@ -16,6 +16,7 @@
*/
#include "raul/Atom.hpp"
+
#include "Configuration.hpp"
using namespace Raul;
@@ -45,6 +46,9 @@ Configuration::Configuration()
.add("help", 'h', "Print this help message", Atom::BOOL, false)
.add("jack-client", 'n', "JACK client name", Atom::STRING, "ingen")
.add("jack-server", 's', "JACK server name", Atom::STRING, "")
+#ifdef INGEN_JACK_SESSION
+ .add("uuid", 'u', "JACK session UUID", Atom::STRING, "")
+#endif
.add("load", 'l', "Load patch", Atom::STRING, Atom())
.add("parallelism", 'p', "Number of concurrent process threads", Atom::INT, 1)
.add("path", 'L', "Target path for loaded patch", Atom::STRING, Atom())
diff --git a/wscript b/wscript
index 5eb6804e..2f9ce164 100644
--- a/wscript
+++ b/wscript
@@ -20,6 +20,9 @@ def options(opt):
help="Ingen data install directory [Default: PREFIX/share/ingen]")
opt.add_option('--module-dir', type='string', dest='moduledir',
help="Ingen module install directory [Default: PREFIX/lib/ingen]")
+ 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-osc', action='store_true', default=False, dest='no_osc',
help="Do not build OSC via liblo support, even if liblo exists")
opt.add_option('--no-http', action='store_true', default=False, dest='no_http',
@@ -44,6 +47,8 @@ def configure(conf):
atleast_version='2.14.0', mandatory=False)
autowaf.check_pkg(conf, 'jack', uselib_store='JACK',
atleast_version='0.109.0', mandatory=True)
+ autowaf.check_pkg(conf, 'jack', uselib_store='NEW_JACK',
+ atleast_version='0.120.0', mandatory=False)
autowaf.check_pkg(conf, 'slv2', uselib_store='SLV2',
atleast_version='0.6.0', mandatory=True)
autowaf.check_pkg(conf, 'raul', uselib_store='RAUL',
@@ -62,6 +67,9 @@ def configure(conf):
if not Options.options.no_osc:
autowaf.check_pkg(conf, 'liblo', uselib_store='LIBLO',
atleast_version='0.25', mandatory=False)
+ if not Options.options.no_jack_session:
+ if conf.env['HAVE_NEW_JACK']:
+ autowaf.define(conf, 'INGEN_JACK_SESSION', 1)
# Check for posix_memalign (OSX, amazingly, doesn't have it)
conf.check(function_name='posix_memalign',
@@ -99,6 +107,8 @@ def configure(conf):
conf.write_config_header('ingen-config.h', remove=False)
autowaf.display_msg(conf, "Jack", str(conf.env['HAVE_JACK'] == 1))
+ autowaf.display_msg(conf, "Jack session support",
+ str(conf.env['INGEN_JACK_SESSION'] == 1))
autowaf.display_msg(conf, "OSC", str(conf.env['HAVE_LIBLO'] == 1))
autowaf.display_msg(conf, "HTTP", str(conf.env['HAVE_SOUP'] == 1))
autowaf.display_msg(conf, "LV2", str(conf.env['HAVE_SLV2'] == 1))