summaryrefslogtreecommitdiffstats
path: root/src/server
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2016-10-06 15:51:11 -0400
committerDavid Robillard <d@drobilla.net>2016-10-06 15:51:11 -0400
commit77f6e9e63ce9ad329b43c92e8a9556aff8e78f2f (patch)
tree50dca5900274ca2f95c3d06069b7fe0bd285e46b /src/server
parenta513af4218d0a62a45960d04ff6ddeecb8d3d4f5 (diff)
downloadingen-77f6e9e63ce9ad329b43c92e8a9556aff8e78f2f.tar.gz
ingen-77f6e9e63ce9ad329b43c92e8a9556aff8e78f2f.tar.bz2
ingen-77f6e9e63ce9ad329b43c92e8a9556aff8e78f2f.zip
Add plugin state saving
This only works with a server-side save, so the GUI now uses that if the server is not running remotely, where "remotely" is defined as "via TCP". This isn't perfect, since running ingen via TCP locally is a perfectly valid thing to do, but it will do for now.
Diffstat (limited to 'src/server')
-rw-r--r--src/server/BlockImpl.hpp2
-rw-r--r--src/server/GraphPlugin.hpp3
-rw-r--r--src/server/InternalBlock.cpp2
-rw-r--r--src/server/InternalPlugin.cpp3
-rw-r--r--src/server/InternalPlugin.hpp3
-rw-r--r--src/server/LV2Block.cpp103
-rw-r--r--src/server/LV2Block.hpp9
-rw-r--r--src/server/LV2Plugin.cpp5
-rw-r--r--src/server/LV2Plugin.hpp3
-rw-r--r--src/server/PluginImpl.hpp3
-rw-r--r--src/server/events/CreateBlock.cpp22
11 files changed, 109 insertions, 49 deletions
diff --git a/src/server/BlockImpl.hpp b/src/server/BlockImpl.hpp
index 2d7211ab..8f937dc5 100644
--- a/src/server/BlockImpl.hpp
+++ b/src/server/BlockImpl.hpp
@@ -103,7 +103,7 @@ public:
virtual LilvState* load_preset(const Raul::URI& uri) { return NULL; }
/** Restore `state`. */
- virtual void apply_state(Worker* worker, LilvState* state) {}
+ virtual void apply_state(Worker* worker, const LilvState* state) {}
/** Save current state as preset. */
virtual boost::optional<Resource>
diff --git a/src/server/GraphPlugin.hpp b/src/server/GraphPlugin.hpp
index 7d365383..9100b058 100644
--- a/src/server/GraphPlugin.hpp
+++ b/src/server/GraphPlugin.hpp
@@ -43,7 +43,8 @@ public:
const Raul::Symbol& symbol,
bool polyphonic,
GraphImpl* parent,
- Engine& engine)
+ Engine& engine,
+ const LilvState* state)
{
return NULL;
}
diff --git a/src/server/InternalBlock.cpp b/src/server/InternalBlock.cpp
index e26bdc10..ffb5163f 100644
--- a/src/server/InternalBlock.cpp
+++ b/src/server/InternalBlock.cpp
@@ -39,7 +39,7 @@ InternalBlock::duplicate(Engine& engine,
BufferFactory& bufs = *engine.buffer_factory();
BlockImpl* copy = reinterpret_cast<InternalPlugin*>(_plugin)->instantiate(
- bufs, symbol, _polyphonic, parent_graph(), engine);
+ bufs, symbol, _polyphonic, parent_graph(), engine, NULL);
for (size_t i = 0; i < num_ports(); ++i) {
const Atom& value = port_impl(i)->value();
diff --git a/src/server/InternalPlugin.cpp b/src/server/InternalPlugin.cpp
index 3d065fe3..1d397f14 100644
--- a/src/server/InternalPlugin.cpp
+++ b/src/server/InternalPlugin.cpp
@@ -46,7 +46,8 @@ InternalPlugin::instantiate(BufferFactory& bufs,
const Raul::Symbol& symbol,
bool polyphonic,
GraphImpl* parent,
- Engine& engine)
+ Engine& engine,
+ const LilvState* state)
{
const SampleCount srate = engine.driver()->sample_rate();
diff --git a/src/server/InternalPlugin.hpp b/src/server/InternalPlugin.hpp
index bcbfe71a..d95afa1a 100644
--- a/src/server/InternalPlugin.hpp
+++ b/src/server/InternalPlugin.hpp
@@ -43,7 +43,8 @@ public:
const Raul::Symbol& symbol,
bool polyphonic,
GraphImpl* parent,
- Engine& engine);
+ Engine& engine,
+ const LilvState* state);
const Raul::Symbol symbol() const { return _symbol; }
diff --git a/src/server/LV2Block.cpp b/src/server/LV2Block.cpp
index 309b68da..c20abfda 100644
--- a/src/server/LV2Block.cpp
+++ b/src/server/LV2Block.cpp
@@ -75,20 +75,6 @@ LV2Block::~LV2Block()
delete _instances;
}
-void
-LV2Block::load_default_state(Worker* worker)
-{
- const LilvPlugin* lplug = _lv2_plugin->lilv_plugin();
- const LilvNode* uri_node = lilv_plugin_get_uri(lplug);
- const Raul::URI uri(lilv_node_as_string(uri_node));
-
- LilvState* default_state = load_preset(_lv2_plugin->uri());
- if (default_state) {
- apply_state(worker, default_state);
- lilv_state_free(default_state);
- }
-}
-
SPtr<LilvInstance>
LV2Block::make_instance(URIs& uris,
SampleRate rate,
@@ -229,7 +215,7 @@ LV2Block::apply_poly(RunContext& context, Raul::Maid& maid, uint32_t poly)
* value is false, this object may not be used.
*/
bool
-LV2Block::instantiate(BufferFactory& bufs)
+LV2Block::instantiate(BufferFactory& bufs, const LilvState* state)
{
const Ingen::URIs& uris = bufs.uris();
Ingen::World* world = bufs.engine().world();
@@ -446,7 +432,20 @@ LV2Block::instantiate(BufferFactory& bufs)
}
}
- load_default_state(NULL);
+ // Load initial state if no state is explicitly given
+ LilvState* default_state = NULL;
+ if (!state) {
+ state = default_state = load_preset(_lv2_plugin->uri());
+ }
+
+ // Apply state
+ if (state) {
+ apply_state(NULL, state);
+ }
+
+ if (default_state) {
+ lilv_state_free(default_state);
+ }
// FIXME: Polyphony + worker?
if (lilv_plugin_has_feature(plug, uris.work_schedule)) {
@@ -458,6 +457,38 @@ LV2Block::instantiate(BufferFactory& bufs)
return ret;
}
+bool
+LV2Block::save_state(const std::string& dir) const
+{
+ World* world = _lv2_plugin->world();
+ LilvWorld* lworld = world->lilv_world();
+
+ LilvState* state = lilv_state_new_from_instance(
+ _lv2_plugin->lilv_plugin(), const_cast<LV2Block*>(this)->instance(0),
+ &world->uri_map().urid_map_feature()->urid_map,
+ NULL, dir.c_str(), dir.c_str(), dir.c_str(), NULL, NULL,
+ LV2_STATE_IS_POD|LV2_STATE_IS_PORTABLE, NULL);
+
+ if (!state) {
+ return false;
+ } else if (lilv_state_get_num_properties(state) == 0) {
+ lilv_state_free(state);
+ return false;
+ }
+
+ lilv_state_save(lworld,
+ &world->uri_map().urid_map_feature()->urid_map,
+ &world->uri_map().urid_unmap_feature()->urid_unmap,
+ state,
+ NULL,
+ dir.c_str(),
+ "state.ttl");
+
+ lilv_state_free(state);
+
+ return true;
+}
+
BlockImpl*
LV2Block::duplicate(Engine& engine,
const Raul::Symbol& symbol,
@@ -465,9 +496,15 @@ LV2Block::duplicate(Engine& engine,
{
const SampleRate rate = engine.driver()->sample_rate();
+ // Get current state
+ LilvState* state = lilv_state_new_from_instance(
+ _lv2_plugin->lilv_plugin(), instance(0),
+ &engine.world()->uri_map().urid_map_feature()->urid_map,
+ NULL, NULL, NULL, NULL, NULL, NULL, LV2_STATE_IS_NATIVE, NULL);
+
// Duplicate and instantiate block
LV2Block* dup = new LV2Block(_lv2_plugin, symbol, _polyphonic, parent, rate);
- if (!dup->instantiate(*engine.buffer_factory())) {
+ if (!dup->instantiate(*engine.buffer_factory(), state)) {
delete dup;
return NULL;
}
@@ -482,19 +519,6 @@ LV2Block::duplicate(Engine& engine,
dup->port_impl(p)->set_properties(port_impl(p)->properties());
}
- // Copy internal plugin state
- for (uint32_t v = 0; v < _polyphony; ++v) {
- LilvState* state = lilv_state_new_from_instance(
- _lv2_plugin->lilv_plugin(), instance(v),
- &engine.world()->uri_map().urid_map_feature()->urid_map,
- NULL, NULL, NULL, NULL, NULL, NULL, LV2_STATE_IS_NATIVE, NULL);
- if (state) {
- lilv_state_restore(state, dup->instance(v),
- NULL, NULL, LV2_STATE_IS_NATIVE, NULL);
- lilv_state_free(state);
- }
- }
-
return dup;
}
@@ -593,8 +617,25 @@ LV2Block::load_preset(const Raul::URI& uri)
return state;
}
+LilvState*
+LV2Block::load_state(World* world, const std::string& path)
+{
+ LilvWorld* lworld = world->lilv_world();
+ const std::string uri = Glib::filename_to_uri(path);
+ LilvNode* subject = lilv_new_uri(lworld, uri.c_str());
+
+ LilvState* state = lilv_state_new_from_file(
+ lworld,
+ &world->uri_map().urid_map_feature()->urid_map,
+ subject,
+ path.c_str());
+
+ lilv_node_free(subject);
+ return state;
+}
+
void
-LV2Block::apply_state(Worker* worker, LilvState* state)
+LV2Block::apply_state(Worker* worker, const LilvState* state)
{
World* world = parent_graph()->engine().world();
SPtr<LV2_Feature> sched;
diff --git a/src/server/LV2Block.hpp b/src/server/LV2Block.hpp
index b8438d9e..b6be8ccf 100644
--- a/src/server/LV2Block.hpp
+++ b/src/server/LV2Block.hpp
@@ -48,9 +48,10 @@ public:
~LV2Block();
- bool instantiate(BufferFactory& bufs);
+ bool instantiate(BufferFactory& bufs, const LilvState* state);
LilvInstance* instance() { return instance(0); }
+ bool save_state(const std::string& dir) const;
BlockImpl* duplicate(Engine& engine,
const Raul::Symbol& symbol,
@@ -69,7 +70,7 @@ public:
LilvState* load_preset(const Raul::URI& uri);
- void apply_state(Worker* worker, LilvState* state);
+ void apply_state(Worker* worker, const LilvState* state);
boost::optional<Resource> save_preset(const Raul::URI& bundle,
const Properties& props);
@@ -79,14 +80,14 @@ public:
BufferRef buf,
SampleCount offset);
+ static LilvState* load_state(World* world, const std::string& path);
+
protected:
SPtr<LilvInstance> make_instance(URIs& uris,
SampleRate rate,
uint32_t voice,
bool preparing);
- void load_default_state(Worker* worker);
-
inline LilvInstance* instance(uint32_t voice) {
return (LilvInstance*)(*_instances)[voice].get();
}
diff --git a/src/server/LV2Plugin.cpp b/src/server/LV2Plugin.cpp
index f8a0ecd8..8e820b8e 100644
--- a/src/server/LV2Plugin.cpp
+++ b/src/server/LV2Plugin.cpp
@@ -90,12 +90,13 @@ LV2Plugin::instantiate(BufferFactory& bufs,
const Raul::Symbol& symbol,
bool polyphonic,
GraphImpl* parent,
- Engine& engine)
+ Engine& engine,
+ const LilvState* state)
{
LV2Block* b = new LV2Block(
this, symbol, polyphonic, parent, engine.driver()->sample_rate());
- if (!b->instantiate(bufs)) {
+ if (!b->instantiate(bufs, state)) {
delete b;
return NULL;
} else {
diff --git a/src/server/LV2Plugin.hpp b/src/server/LV2Plugin.hpp
index aa10d90a..f490bbfd 100644
--- a/src/server/LV2Plugin.hpp
+++ b/src/server/LV2Plugin.hpp
@@ -45,7 +45,8 @@ public:
const Raul::Symbol& symbol,
bool polyphonic,
GraphImpl* parent,
- Engine& engine);
+ Engine& engine,
+ const LilvState* state);
const Raul::Symbol symbol() const;
diff --git a/src/server/PluginImpl.hpp b/src/server/PluginImpl.hpp
index 29daba7b..9728bf36 100644
--- a/src/server/PluginImpl.hpp
+++ b/src/server/PluginImpl.hpp
@@ -58,7 +58,8 @@ public:
const Raul::Symbol& symbol,
bool polyphonic,
GraphImpl* parent,
- Engine& engine) = 0;
+ Engine& engine,
+ const LilvState* state) = 0;
virtual const Raul::Symbol symbol() const = 0;
diff --git a/src/server/events/CreateBlock.cpp b/src/server/events/CreateBlock.cpp
index 231df4e2..a43a8bf0 100644
--- a/src/server/events/CreateBlock.cpp
+++ b/src/server/events/CreateBlock.cpp
@@ -29,6 +29,7 @@
#include "PluginImpl.hpp"
#include "PortImpl.hpp"
#include "PreProcessContext.hpp"
+#include "LV2Block.hpp"
namespace Ingen {
namespace Server {
@@ -118,11 +119,22 @@ CreateBlock::pre_process(PreProcessContext& ctx)
PluginImpl* const plugin = _engine.block_factory()->plugin(prototype);
if (!plugin) {
return Event::pre_process_done(Status::PROTOTYPE_NOT_FOUND, prototype);
- } else if (!(_block = plugin->instantiate(*_engine.buffer_factory(),
- Raul::Symbol(_path.symbol()),
- polyphonic,
- _graph,
- _engine))) {
+ }
+
+ // Load state from directory if given in properties
+ LilvState* state = NULL;
+ Resource::Properties::iterator s = _properties.find(uris.state_state);
+ if (s != _properties.end() && s->second.type() == uris.forge.Path) {
+ state = LV2Block::load_state(_engine.world(), s->second.ptr<char>());
+ }
+
+ // Instantiate plugin
+ if (!(_block = plugin->instantiate(*_engine.buffer_factory(),
+ Raul::Symbol(_path.symbol()),
+ polyphonic,
+ _graph,
+ _engine,
+ state))) {
return Event::pre_process_done(Status::CREATION_FAILED, _path);
}
}