save/restore plugin state with track-template
authorRobin Gareus <robin@gareus.org>
Fri, 18 Dec 2015 13:27:15 +0000 (14:27 +0100)
committerRobin Gareus <robin@gareus.org>
Fri, 18 Dec 2015 13:27:15 +0000 (14:27 +0100)
libs/ardour/ardour/lv2_plugin.h
libs/ardour/ardour/plugin.h
libs/ardour/ardour/plugin_insert.h
libs/ardour/lv2_plugin.cc
libs/ardour/plugin_insert.cc
libs/ardour/route.cc

index 145b48a24be4bc56f268d0472a484c420c459eff..4cb23719ae62df1fc8d7482a9649c6b160e5e52a 100644 (file)
@@ -121,6 +121,7 @@ class LIBARDOUR_API LV2Plugin : public ARDOUR::Plugin, public ARDOUR::Workee
        get_scale_points(uint32_t port_index) const;
 
        void set_insert_id(PBD::ID id);
+       void set_state_dir (const std::string& d = "");
 
        int      set_state (const XMLNode& node, int version);
        bool     save_preset (std::string uri);
@@ -176,6 +177,7 @@ class LIBARDOUR_API LV2Plugin : public ARDOUR::Plugin, public ARDOUR::Workee
        framepos_t    _next_cycle_start;  ///< Expected start frame of next run cycle
        double        _next_cycle_speed;  ///< Expected start frame of next run cycle
        PBD::ID       _insert_id;
+       std::string   _plugin_state_dir;
        uint32_t      _patch_port_in_index;
        uint32_t      _patch_port_out_index;
        URIMap&       _uri_map;
index 063335ccc3f57d3620d9d58c2f306c0b0365d307..37079751a9997bdb5e2c555cc0eea0544e6c7fbf 100644 (file)
@@ -101,6 +101,7 @@ class LIBARDOUR_API Plugin : public PBD::StatefulDestructible, public Latent
        virtual int set_state (const XMLNode &, int version);
 
        virtual void set_insert_id (PBD::ID id) {}
+       virtual void set_state_dir (const std::string& d = "") {}
 
        virtual std::string unique_id() const = 0;
        virtual const char * label() const = 0;
index a37c9cae68287e213dc39862dbba0cce05d3a643..0873825c0253324f0e9bda79b43356d1403bd63b 100644 (file)
@@ -54,6 +54,7 @@ class LIBARDOUR_API PluginInsert : public Processor
        XMLNode& get_state(void);
        int set_state(const XMLNode&, int version);
        void update_id (PBD::ID);
+       void set_state_dir (const std::string& d = "");
 
        void run (BufferSet& in, framepos_t start_frame, framepos_t end_frame, pframes_t nframes, bool);
        void silence (framecnt_t nframes);
index 9cac6492b4ed0ea2e732e3529c3955c5b62099fc..3753bd80661453ee8e95f47f66654b12175837a5 100644 (file)
@@ -44,6 +44,7 @@
 #include "ardour/debug.h"
 #include "ardour/lv2_plugin.h"
 #include "ardour/session.h"
+#include "ardour/template_utils.h"
 #include "ardour/tempo.h"
 #include "ardour/types.h"
 #include "ardour/utils.h"
@@ -968,7 +969,11 @@ LV2Plugin::c_ui_type()
 const std::string
 LV2Plugin::plugin_dir() const
 {
-       return Glib::build_filename(_session.plugins_dir(), _insert_id.to_s());
+       if (!_plugin_state_dir.empty ()){
+               return Glib::build_filename(_plugin_state_dir, _insert_id.to_s());
+       } else {
+               return Glib::build_filename(_session.plugins_dir(), _insert_id.to_s());
+       }
 }
 
 /** Directory for files created by the plugin (except during save). */
@@ -1036,6 +1041,10 @@ LV2Plugin::add_state(XMLNode* root) const
                }
        }
 
+       if (!_plugin_state_dir.empty()) {
+               root->add_property("template-dir", _plugin_state_dir);
+       }
+
        if (_has_state_interface) {
                // Provisionally increment state version and create directory
                const std::string new_dir = state_dir(++_state_version);
@@ -1673,6 +1682,12 @@ LV2Plugin::set_insert_id(PBD::ID id)
        }
 }
 
+void
+LV2Plugin::set_state_dir (const std::string& d)
+{
+       _plugin_state_dir = d;
+}
+
 int
 LV2Plugin::set_state(const XMLNode& node, int version)
 {
@@ -1728,6 +1743,13 @@ LV2Plugin::set_state(const XMLNode& node, int version)
                set_parameter(port_id, atof(value));
        }
 
+       if ((prop = node.property("template-dir")) != 0) {
+               // portable templates, strip absolute path
+               set_state_dir (Glib::build_filename (
+                                       ARDOUR::user_route_template_directory (),
+                                       Glib::path_get_basename (prop->value ())));
+       }
+
        _state_version = 0;
        if ((prop = node.property("state-dir")) != 0) {
                if (sscanf(prop->value().c_str(), "state%u", &_state_version) != 1) {
@@ -1736,8 +1758,6 @@ LV2Plugin::set_state(const XMLNode& node, int version)
                                prop->value()) << endmsg;
                }
 
-               // TODO: special case track-templates
-               // (state must be saved with the template)
                std::string state_file = Glib::build_filename(
                        plugin_dir(),
                        Glib::build_filename(prop->value(), "state.ttl"));
@@ -1750,6 +1770,13 @@ LV2Plugin::set_state(const XMLNode& node, int version)
                _impl->state = state;
        }
 
+       if (!_plugin_state_dir.empty ()) {
+               // force save with session, next time (increment counter)
+               lilv_state_free (_impl->state);
+               _impl->state = NULL;
+               set_state_dir ("");
+       }
+
        latency_compute_run();
 #endif
 
index b56419096e3bd63f6af5bc7daf5b171a37a32c29..1c9c573e422f835bb0d066d572a0b76775faf762 100644 (file)
@@ -1190,6 +1190,13 @@ PluginInsert::update_id (PBD::ID id)
        }
 }
 
+void
+PluginInsert::set_state_dir (const std::string& d)
+{
+       // state() only saves the state of the first plugin
+       _plugins[0]->set_state_dir (d);
+}
+
 void
 PluginInsert::set_parameter_state_2X (const XMLNode& node, int version)
 {
index 78eca173974b0857a588acc6db0af6872088e238..e24919a3b3198beef8c4b58affa5ef5833949c7b 100644 (file)
@@ -4158,7 +4158,30 @@ Route::shift (framepos_t pos, framecnt_t frames)
 int
 Route::save_as_template (const string& path, const string& name)
 {
+       {
+               // would be nice to use foreach_processor()
+               Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
+               std::string state_dir = path.substr (0, path.find_last_of ('.')); // strip template_suffix
+               for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) {
+                       boost::shared_ptr<PluginInsert> pi  = boost::dynamic_pointer_cast<PluginInsert> (*i);
+                       if (pi) {
+                               pi->set_state_dir (state_dir);
+                       }
+               }
+       }
+
        XMLNode& node (state (false));
+
+       {
+               Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
+               for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) {
+                       boost::shared_ptr<PluginInsert> pi  = boost::dynamic_pointer_cast<PluginInsert> (*i);
+                       if (pi) {
+                               pi->set_state_dir ();
+                       }
+               }
+       }
+
        XMLTree tree;
 
        IO::set_name_in_state (*node.children().front(), name);