diff options
author | David Robillard <d@drobilla.net> | 2012-03-11 01:53:31 +0000 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2012-03-11 01:53:31 +0000 |
commit | d88dc1da7ed999d56bc61d86fb20d75d45846912 (patch) | |
tree | 0baae1caceb9b40e0990b6e7d646977feca5d8cb | |
parent | 7bc5413b66cd60395af7f045b34b16685851b3dc (diff) | |
download | ingen-d88dc1da7ed999d56bc61d86fb20d75d45846912.tar.gz ingen-d88dc1da7ed999d56bc61d86fb20d75d45846912.tar.bz2 ingen-d88dc1da7ed999d56bc61d86fb20d75d45846912.zip |
Implement state save/restore when Ingen is an LV2 plugin.
git-svn-id: http://svn.drobilla.net/lad/trunk/ingen@4047 a436a847-0d15-0410-975c-d299462d15a1
-rw-r--r-- | include/ingen/serialisation/Serialiser.hpp | 4 | ||||
-rw-r--r-- | src/serialisation/Serialiser.cpp | 18 | ||||
-rw-r--r-- | src/serialisation/serialisation.cpp | 2 | ||||
-rw-r--r-- | src/server/ingen_lv2.cpp | 112 | ||||
-rw-r--r-- | src/server/wscript | 2 | ||||
-rw-r--r-- | wscript | 2 |
6 files changed, 127 insertions, 13 deletions
diff --git a/include/ingen/serialisation/Serialiser.hpp b/include/ingen/serialisation/Serialiser.hpp index 111794d7..8d5805e1 100644 --- a/include/ingen/serialisation/Serialiser.hpp +++ b/include/ingen/serialisation/Serialiser.hpp @@ -48,7 +48,7 @@ namespace Serialisation { class Serialiser { public: - Serialiser(Shared::World& world, SharedPtr<Shared::Store> store); + Serialiser(Shared::World& world); virtual ~Serialiser(); typedef GraphObject::Properties Properties; @@ -57,7 +57,7 @@ public: const std::string& filename); virtual void write_bundle(SharedPtr<const Patch> patch, - const std::string& path); + const std::string& path); virtual std::string to_string(SharedPtr<const GraphObject> object, const std::string& base_uri, diff --git a/src/serialisation/Serialiser.cpp b/src/serialisation/Serialiser.cpp index 6e6db3ed..1e608806 100644 --- a/src/serialisation/Serialiser.cpp +++ b/src/serialisation/Serialiser.cpp @@ -70,9 +70,8 @@ namespace Ingen { namespace Serialisation { struct Serialiser::Impl { - Impl(Shared::World& world, SharedPtr<Shared::Store> store) + Impl(Shared::World& world) : _root_path("/") - , _store(store) , _world(world) {} @@ -119,8 +118,8 @@ struct Serialiser::Impl { }; -Serialiser::Serialiser(Shared::World& world, SharedPtr<Shared::Store> store) - : me(new Impl(world, store)) +Serialiser::Serialiser(Shared::World& world) + : me(new Impl(world)) {} Serialiser::~Serialiser() @@ -332,8 +331,7 @@ Serialiser::serialise(SharedPtr<const GraphObject> object) throw (std::logic_err SharedPtr<const Patch> patch = PtrCast<const Patch>(object); if (patch) { - const Sord::URI patch_id(me->_model->world(), ""); - me->serialise_patch(patch, patch_id); + me->serialise_patch(patch, me->path_rdf_node(patch->path())); return; } @@ -369,6 +367,10 @@ Serialiser::Impl::serialise_patch(SharedPtr<const Patch> patch, Sord::Curie(world, "rdf:type"), Sord::Curie(world, "lv2:Plugin")); + _model->add_statement(patch_id, + Sord::Curie(world, "lv2:extensionData"), + Sord::URI(world, "http://lv2plug.in/ns/ext/state#Interface")); + const URIs& uris = *_world.uris().get(); // Always write a symbol (required by Ingen) @@ -395,8 +397,8 @@ Serialiser::Impl::serialise_patch(SharedPtr<const Patch> patch, serialise_properties(patch.get(), Resource::INTERNAL, patch_id); - for (Store::const_iterator n = _store->children_begin(patch); - n != _store->children_end(patch); ++n) { + for (Store::const_iterator n = _world.store()->children_begin(patch); + n != _world.store()->children_end(patch); ++n) { if (n->first.parent() != patch->path()) continue; diff --git a/src/serialisation/serialisation.cpp b/src/serialisation/serialisation.cpp index 309c4271..aca47bdd 100644 --- a/src/serialisation/serialisation.cpp +++ b/src/serialisation/serialisation.cpp @@ -28,7 +28,7 @@ struct IngenSerialisationModule : public Shared::Module { world->set_parser(SharedPtr<Serialisation::Parser>( new Serialisation::Parser(*world))); world->set_serialiser(SharedPtr<Serialisation::Serialiser>( - new Serialisation::Serialiser(*world, world->store()))); + new Serialisation::Serialiser(*world))); } }; diff --git a/src/server/ingen_lv2.cpp b/src/server/ingen_lv2.cpp index 74bffd53..9275d555 100644 --- a/src/server/ingen_lv2.cpp +++ b/src/server/ingen_lv2.cpp @@ -27,10 +27,14 @@ #include <glibmm/timer.h> #include "lv2/lv2plug.in/ns/lv2core/lv2.h" +#include "lv2/lv2plug.in/ns/ext/state/state.h" +#include "lv2/lv2plug.in/ns/ext/urid/urid.h" #include "ingen/ServerInterface.hpp" #include "ingen/serialisation/Parser.hpp" +#include "ingen/serialisation/Serialiser.hpp" #include "ingen/shared/Configuration.hpp" +#include "ingen/shared/Store.hpp" #include "ingen/shared/World.hpp" #include "ingen/shared/runtime_paths.hpp" #include "raul/SharedPtr.hpp" @@ -46,6 +50,8 @@ #include "ServerInterfaceImpl.hpp" #include "ThreadManager.hpp" +#define NS_INGEN "http://drobilla.net/ns/ingen#" + /** Record of a patch in this Ingen LV2 bundle */ struct LV2Patch { LV2Patch(const std::string& u, const std::string& f); @@ -245,6 +251,7 @@ private: struct IngenPlugin { Ingen::Shared::World* world; MainThread* main; + LV2_URID_Map* map; }; static LV2_Handle @@ -275,6 +282,13 @@ ingen_instantiate(const LV2_Descriptor* descriptor, return NULL; } + plugin->map = NULL; + for (int i = 0; features[i]; ++i) { + if (!strcmp(features[i]->URI, LV2_URID_URI "#map")) { + plugin->map = (LV2_URID_Map*)features[i]->data; + } + } + SharedPtr<Server::Engine> engine(new Server::Engine(plugin->world)); plugin->world->set_local_engine(engine); plugin->main = new MainThread(engine); @@ -373,9 +387,105 @@ ingen_cleanup(LV2_Handle instance) free(instance); } -static const void* +static void +get_state_features(const LV2_Feature* const* features, + LV2_State_Map_Path** map, + LV2_State_Make_Path** make) +{ + for (int i = 0; features[i]; ++i) { + if (map && !strcmp(features[i]->URI, LV2_STATE__mapPath)) { + *map = (LV2_State_Map_Path*)features[i]->data; + } else if (make && !strcmp(features[i]->URI, LV2_STATE__makePath)) { + *make = (LV2_State_Make_Path*)features[i]->data; + } + } +} + +static void +ingen_save(LV2_Handle instance, + LV2_State_Store_Function store, + LV2_State_Handle handle, + uint32_t flags, + const LV2_Feature* const* features) +{ + IngenPlugin* plugin = (IngenPlugin*)instance; + + LV2_State_Map_Path* map_path = NULL; + LV2_State_Make_Path* make_path = NULL; + get_state_features(features, &map_path, &make_path); + if (!map_path || !make_path || !plugin->map) { + Raul::error << "Missing state:mapPath, state:makePath, or urid:Map." + << endl; + return; + } + + LV2_URID ingen_file = plugin->map->map(plugin->map->handle, NS_INGEN "file"); + LV2_URID atom_Path = plugin->map->map(plugin->map->handle, + "http://lv2plug.in/ns/ext/atom#Path"); + + char* real_path = make_path->path(make_path->handle, "patch.ttl"); + char* state_path = map_path->abstract_path(map_path->handle, real_path); + + Ingen::Shared::Store::iterator root = plugin->world->store()->find("/"); + plugin->world->serialiser()->to_file(root->second, real_path); + + store(handle, + ingen_file, + state_path, + strlen(state_path) + 1, + atom_Path, + LV2_STATE_IS_POD); + + free(state_path); + free(real_path); +} + +static void +ingen_restore(LV2_Handle instance, + LV2_State_Retrieve_Function retrieve, + LV2_State_Handle handle, + uint32_t flags, + const LV2_Feature* const* features) +{ + IngenPlugin* plugin = (IngenPlugin*)instance; + + LV2_State_Map_Path* map_path = NULL; + get_state_features(features, &map_path, NULL); + if (!map_path) { + Raul::error << "Missing state:mapPath" << endl; + return; + } + + LV2_URID ingen_file = plugin->map->map(plugin->map->handle, NS_INGEN "file"); + size_t size; + uint32_t type; + uint32_t valflags; + + const void* path = retrieve(handle, + ingen_file, + &size, &type, &valflags); + + if (!path) { + Raul::error << "Failed to restore ingen:file" << endl; + return; + } + + const char* state_path = (const char*)path; + char* real_path = map_path->absolute_path(map_path->handle, state_path); + + plugin->world->parser()->parse_file(plugin->world, + plugin->world->engine().get(), + real_path); + free(real_path); +} + +const void* ingen_extension_data(const char* uri) { + static const LV2_State_Interface state = { ingen_save, ingen_restore }; + if (!strcmp(uri, LV2_STATE__Interface)) { + return &state; + } return NULL; } diff --git a/src/server/wscript b/src/server/wscript index 2a5e687f..c9fae6e5 100644 --- a/src/server/wscript +++ b/src/server/wscript @@ -83,4 +83,4 @@ def build(bld): target = 'ingen_lv2', install_path = '${LV2DIR}/ingen.lv2/', use = 'libingen_server libingen_shared') - autowaf.use_lib(bld, obj, core_libs) + autowaf.use_lib(bld, obj, core_libs + ' LV2_STATE') @@ -89,6 +89,8 @@ def configure(conf): uselib_store='LV2_ATOM') autowaf.check_pkg(conf, 'lv2-lv2plug.in-ns-ext-midi', uselib_store='LV2_MIDI') + autowaf.check_pkg(conf, 'lv2-lv2plug.in-ns-ext-state', + uselib_store='LV2_STATE') autowaf.check_pkg(conf, 'lv2-lv2plug.in-ns-ext-contexts', uselib_store='LV2_CONTEXTS') autowaf.check_pkg(conf, 'lv2-lv2plug.in-ns-ext-event', |