diff options
author | David Robillard <d@drobilla.net> | 2011-02-17 10:30:08 +0000 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2011-02-17 10:30:08 +0000 |
commit | e668b8c846175f90cf22b456c5e5a4cc85410da4 (patch) | |
tree | 613d2e37d4ef359d2f572bfc4bfd43e6acff43c7 | |
parent | 4c6269aeaf39f1a5c7473c22ff0417d50decfdc3 (diff) | |
download | ingen-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.cpp | 4 | ||||
-rw-r--r-- | src/engine/JackDriver.cpp | 71 | ||||
-rw-r--r-- | src/engine/JackDriver.hpp | 13 | ||||
-rw-r--r-- | src/engine/ingen_lv2.cpp | 11 | ||||
-rw-r--r-- | src/gui/App.cpp | 7 | ||||
-rw-r--r-- | src/gui/ThreadedLoader.cpp | 6 | ||||
-rw-r--r-- | src/ingen/main.cpp | 8 | ||||
-rw-r--r-- | src/module/World.cpp | 20 | ||||
-rw-r--r-- | src/module/World.hpp | 5 | ||||
-rw-r--r-- | src/serialisation/Parser.cpp | 67 | ||||
-rw-r--r-- | src/serialisation/Parser.hpp | 10 | ||||
-rw-r--r-- | src/shared/Configuration.cpp | 6 | ||||
-rw-r--r-- | wscript | 10 |
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()) @@ -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)) |