diff options
-rw-r--r-- | ingen/Node.hpp | 1 | ||||
-rw-r--r-- | ingen/URIs.hpp | 1 | ||||
-rw-r--r-- | src/Serialiser.cpp | 16 | ||||
-rw-r--r-- | src/URIs.cpp | 1 | ||||
-rw-r--r-- | src/gui/GraphBox.cpp | 31 | ||||
-rw-r--r-- | src/gui/GraphBox.hpp | 2 | ||||
-rw-r--r-- | src/server/BlockImpl.hpp | 2 | ||||
-rw-r--r-- | src/server/GraphPlugin.hpp | 3 | ||||
-rw-r--r-- | src/server/InternalBlock.cpp | 2 | ||||
-rw-r--r-- | src/server/InternalPlugin.cpp | 3 | ||||
-rw-r--r-- | src/server/InternalPlugin.hpp | 3 | ||||
-rw-r--r-- | src/server/LV2Block.cpp | 103 | ||||
-rw-r--r-- | src/server/LV2Block.hpp | 9 | ||||
-rw-r--r-- | src/server/LV2Plugin.cpp | 5 | ||||
-rw-r--r-- | src/server/LV2Plugin.hpp | 3 | ||||
-rw-r--r-- | src/server/PluginImpl.hpp | 3 | ||||
-rw-r--r-- | src/server/events/CreateBlock.cpp | 22 |
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); } } |