summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2012-03-11 01:53:31 +0000
committerDavid Robillard <d@drobilla.net>2012-03-11 01:53:31 +0000
commitd88dc1da7ed999d56bc61d86fb20d75d45846912 (patch)
tree0baae1caceb9b40e0990b6e7d646977feca5d8cb
parent7bc5413b66cd60395af7f045b34b16685851b3dc (diff)
downloadingen-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.hpp4
-rw-r--r--src/serialisation/Serialiser.cpp18
-rw-r--r--src/serialisation/serialisation.cpp2
-rw-r--r--src/server/ingen_lv2.cpp112
-rw-r--r--src/server/wscript2
-rw-r--r--wscript2
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')
diff --git a/wscript b/wscript
index 6e8b153f..467cae09 100644
--- a/wscript
+++ b/wscript
@@ -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',