diff options
author | David Robillard <d@drobilla.net> | 2016-10-06 15:51:11 -0400 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2016-10-06 15:51:11 -0400 |
commit | 77f6e9e63ce9ad329b43c92e8a9556aff8e78f2f (patch) | |
tree | 50dca5900274ca2f95c3d06069b7fe0bd285e46b /src/server | |
parent | a513af4218d0a62a45960d04ff6ddeecb8d3d4f5 (diff) | |
download | ingen-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.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 |
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); } } |