summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ingen/Node.hpp1
-rw-r--r--ingen/URIs.hpp1
-rw-r--r--src/Serialiser.cpp16
-rw-r--r--src/URIs.cpp1
-rw-r--r--src/gui/GraphBox.cpp31
-rw-r--r--src/gui/GraphBox.hpp2
-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
17 files changed, 150 insertions, 60 deletions
diff --git a/ingen/Node.hpp b/ingen/Node.hpp
index fb5fc985..d6253cc4 100644
--- a/ingen/Node.hpp
+++ b/ingen/Node.hpp
@@ -69,6 +69,7 @@ public:
// Plugin blocks only
virtual LilvInstance* instance() { return NULL; }
+ virtual bool save_state(const std::string& dir) const { return false; }
// All objects
virtual GraphType graph_type() const = 0;
diff --git a/ingen/URIs.hpp b/ingen/URIs.hpp
index 6a691ba2..44f1056e 100644
--- a/ingen/URIs.hpp
+++ b/ingen/URIs.hpp
@@ -203,6 +203,7 @@ public:
const Quark rdfs_seeAlso;
const Quark rsz_minimumSize;
const Quark state_loadDefaultState;
+ const Quark state_state;
const Quark time_Position;
const Quark time_bar;
const Quark time_barBeat;
diff --git a/src/Serialiser.cpp b/src/Serialiser.cpp
index 37bd20c0..da88559c 100644
--- a/src/Serialiser.cpp
+++ b/src/Serialiser.cpp
@@ -445,9 +445,23 @@ Serialiser::Impl::serialise_block(SPtr<const Node> block,
Sord::URI(_model->world(), uris.lv2_prototype),
class_id);
- const Node::Properties props = block->properties();
+ // Serialise properties, but remove possibly stale state:state (set again below)
+ Node::Properties props = block->properties();
+ props.erase(uris.state_state);
serialise_properties(block_id, props);
+ if (_base_uri.substr(0, 5) == "file:") {
+ const std::string base = Glib::filename_from_uri(_base_uri);
+ const std::string graph_dir = Glib::path_get_dirname(base);
+ const std::string state_dir = Glib::build_filename(graph_dir, block->symbol());
+ const std::string state_file = Glib::build_filename(state_dir, "state.ttl");
+ if (block->save_state(state_dir)) {
+ _model->add_statement(block_id,
+ Sord::URI(_model->world(), uris.state_state),
+ Sord::URI(_model->world(), Glib::filename_to_uri(state_file)));
+ }
+ }
+
for (uint32_t i = 0; i < block->num_ports(); ++i) {
Node* const p = block->port(i);
const Sord::Node port_id = path_rdf_node(p->path());
diff --git a/src/URIs.cpp b/src/URIs.cpp
index 7eedd208..1c0a6b23 100644
--- a/src/URIs.cpp
+++ b/src/URIs.cpp
@@ -186,6 +186,7 @@ URIs::URIs(Forge& f, URIMap* map, LilvWorld* lworld)
, rdfs_seeAlso (forge, map, lworld, NS_RDFS "seeAlso")
, rsz_minimumSize (forge, map, lworld, LV2_RESIZE_PORT__minimumSize)
, state_loadDefaultState(forge, map, lworld, LV2_STATE__loadDefaultState)
+ , state_state (forge, map, lworld, LV2_STATE__state)
, time_Position (forge, map, lworld, LV2_TIME__Position)
, time_bar (forge, map, lworld, LV2_TIME__bar)
, time_barBeat (forge, map, lworld, LV2_TIME__barBeat)
diff --git a/src/gui/GraphBox.cpp b/src/gui/GraphBox.cpp
index 692e378a..6423c016 100644
--- a/src/gui/GraphBox.cpp
+++ b/src/gui/GraphBox.cpp
@@ -493,11 +493,7 @@ GraphBox::event_save()
if (!document.is_valid() || document.type() != _app->uris().forge.URI) {
event_save_as();
} else {
- _app->loader()->save_graph(_graph, document.ptr<char>());
- _status_bar->push(
- (boost::format("Saved %1% to %2%") % _graph->path().c_str()
- % document.ptr<char>()).str(),
- STATUS_CONTEXT_GRAPH);
+ save_graph(Raul::URI(document.ptr<char>()));
}
}
@@ -528,6 +524,24 @@ GraphBox::confirm(const Glib::ustring& message,
}
void
+GraphBox::save_graph(const Raul::URI& uri)
+{
+ if (_app->interface()->uri().substr(0, 3) == "tcp") {
+ _status_bar->push(
+ (boost::format("Saved %1% to %2% on client")
+ % _graph->path() % uri).str(),
+ STATUS_CONTEXT_GRAPH);
+ _app->loader()->save_graph(_graph, uri);
+ } else {
+ _status_bar->push(
+ (boost::format("Saved %1% to %2% on server")
+ % _graph->path() % uri).str(),
+ STATUS_CONTEXT_GRAPH);
+ _app->interface()->copy(_graph->uri(), uri);
+ }
+}
+
+void
GraphBox::event_save_as()
{
const URIs& uris = _app->uris();
@@ -613,14 +627,11 @@ GraphBox::event_save_as()
if (confirmed) {
const Glib::ustring uri = Glib::filename_to_uri(filename);
- _app->loader()->save_graph(_graph, uri);
+ save_graph(Raul::URI(uri));
+
const_cast<GraphModel*>(_graph.get())->set_property(
uris.ingen_file,
_app->forge().alloc_uri(uri.c_str()));
- _status_bar->push(
- (boost::format("Saved %1% to %2%") % _graph->path().c_str()
- % filename).str(),
- STATUS_CONTEXT_GRAPH);
}
_app->world()->conf().set(
diff --git a/src/gui/GraphBox.hpp b/src/gui/GraphBox.hpp
index 3ffd1f91..20e0a764 100644
--- a/src/gui/GraphBox.hpp
+++ b/src/gui/GraphBox.hpp
@@ -106,6 +106,8 @@ private:
bool confirm(const Glib::ustring& message,
const Glib::ustring& secondary_text="");
+ void save_graph(const Raul::URI& uri);
+
void event_import();
void event_save();
void event_save_as();
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);
}
}