LV2 support.
[ardour.git] / libs / ardour / redirect.cc
index 18b16eaa73e4291c3189f8ddd47f0d32a0704490..b1e631015fc3fcedacb01d287ec69349bf21c4aa 100644 (file)
@@ -15,7 +15,6 @@
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
-    $Id$
 */
 
 #include <fstream>
@@ -28,6 +27,7 @@
 #include <sigc++/bind.h>
 
 #include <pbd/xml++.h>
+#include <pbd/enumwriter.h>
 
 #include <ardour/redirect.h>
 #include <ardour/session.h>
@@ -58,6 +58,7 @@ Redirect::Redirect (Session& s, const string& name, Placement p,
 
 Redirect::~Redirect ()
 {
+       notify_callbacks ();
 }
 
 boost::shared_ptr<Redirect>
@@ -96,115 +97,77 @@ Redirect::set_placement (Placement p, void *src)
        }
 }
 
-void
-Redirect::set_placement (const string& str, void *src)
-{
-       if (str == _("pre")) {
-               set_placement (PreFader, this);
-       } else if (str == _("post")) {
-               set_placement (PostFader, this);
-       } else {
-               error << string_compose(_("Redirect: unknown placement string \"%1\" (ignored)"), str) << endmsg;
-       }
-}
+/* NODE STRUCTURE 
+   
+    <Automation [optionally with visible="...." ]>
+       <parameter-N>
+         <AutomationList id=N>
+          <events>
+          X1 Y1
+          X2 Y2
+          ....
+          </events>
+       </parameter-N>
+    <Automation>
+*/
 
 int
-Redirect::load_automation (string path)
+Redirect::set_automation_state (const XMLNode& node)
 {
-       string fullpath;
+       Glib::Mutex::Lock lm (_automation_lock);
 
-       if (path[0] == '/') { // legacy
-               fullpath = path;
-       } else {
-               fullpath = _session.automation_dir();
-               fullpath += path;
-       }
-       ifstream in (fullpath.c_str());
+       parameter_automation.clear ();
 
-       if (!in) {
-               warning << string_compose(_("%1: cannot open %2 to load automation data (%3)"), _name, fullpath, strerror (errno)) << endmsg;
-               return 1;
-       }
+       XMLNodeList nlist = node.children();
+       XMLNodeIterator niter;
 
-       Glib::Mutex::Lock lm (_automation_lock);
-       set<uint32_t> tosave;
-       parameter_automation.clear ();
+       for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
+               uint32_t param;
 
-       while (in) {
-               double when;
-               double value;
-               uint32_t port;
+               if (sscanf ((*niter)->name().c_str(), "parameter-%" PRIu32, &param) != 1) {
+                       error << string_compose (_("%2: badly formatted node name in XML automation state, ignored"), _name) << endmsg;
+                       continue;
+               }
 
-               in >> port;     if (!in) break;
-               in >> when;  if (!in) goto bad;
-               in >> value; if (!in) goto bad;
-               
-               AutomationList& al = automation_list (port);
-               al.add (when, value);
-               tosave.insert (port);
-       }
-       
-#ifdef STATE_MANAGER
-       for (set<uint32_t>::iterator i = tosave.begin(); i != tosave.end(); ++i) {
-               automation_list (*i).save_state (_("loaded from disk"));
+               AutomationList& al = automation_list (param);
+               if (al.set_state (*(*niter)->children().front())) {
+                       goto bad;
+               }
        }
-#endif
-       
+
        return 0;
 
   bad:
-       error << string_compose(_("%1: cannot load automation data from %2"), _name, fullpath) << endmsg;
+       error << string_compose(_("%1: cannot load automation data from XML"), _name) << endmsg;
        parameter_automation.clear ();
        return -1;
 }
 
-int
-Redirect::save_automation (string path)
+XMLNode&
+Redirect::get_automation_state ()
 {
        Glib::Mutex::Lock lm (_automation_lock);
+       XMLNode* node = new XMLNode (X_("Automation"));
        string fullpath;
 
        if (parameter_automation.empty()) {
-               return 1;
-       }
-
-       fullpath = _session.automation_dir();
-       fullpath += path;
-
-       ofstream out (fullpath.c_str());
-
-       if (!out) {
-               error << string_compose(_("%1: cannot open %2 to store automation data (%3)"), _name, fullpath, strerror (errno)) << endmsg;
-               return -1;
+               return *node;
        }
 
-       AutomationList::const_iterator i;
        map<uint32_t,AutomationList*>::iterator li;
        
        for (li = parameter_automation.begin(); li != parameter_automation.end(); ++li) {
-               for (i = (*li).second->begin(); i != (*li).second->end(); ++i) {
-                       
-                       out << (*li).first << ' ' << (*i)->when << ' ' << (*i)->value << endl;
-                       
-                       if (!out) {
-                               break;
-                       }
-               }
+       
+               XMLNode* child;
                
-               if (i != (*li).second->end()) {
-                       unlink (fullpath.c_str());
-                       error << string_compose(_("%1: could not save automation state to %2"), _name, fullpath) << endmsg;
-                       return -1;
-               }
+               char buf[64];
+               stringstream str;
+               snprintf (buf, sizeof (buf), "parameter-%" PRIu32, li->first);
+               child = new XMLNode (buf);
+               child->add_child_nocopy (li->second->get_state ());
        }
 
-       if (li != parameter_automation.end()) {
-               unlink (fullpath.c_str());
-               error << string_compose(_("%1: could not save automation state to %2"), _name, fullpath) << endmsg;
-               return -1;
-       }
-
-       return 0;
+       return *node;
 }
 
 XMLNode&
@@ -216,12 +179,11 @@ Redirect::get_state (void)
 XMLNode&
 Redirect::state (bool full_state)
 {
-       char buf[64];
        XMLNode* node = new XMLNode (state_node_name);
        stringstream sstr;
 
        node->add_property("active", active() ? "yes" : "no");  
-       node->add_property("placement", placement_as_string (placement()));
+       node->add_property("placement", enum_2_string (_placement));
        node->add_child_nocopy (IO::state (full_state));
 
        if (_extra_xml){
@@ -230,65 +192,24 @@ Redirect::state (bool full_state)
        
        if (full_state) {
 
-               string path;
-               string legal_name;
+               XMLNode& automation = get_automation_state(); 
                
-               path = _session.snap_name();
-               path += "-redirect-";
-               id().print (buf, sizeof (buf));
-               path += buf;
-               path += ".automation";
-               
-               /* XXX we didn't ask for a state save, we asked for the current state.
-                  FIX ME!
-               */
-               
-               switch (save_automation (path)) {
-               case -1:
-                       error << string_compose(_("Could not get state from Redirect (%1).  Problem with save_automation"), _name) << endmsg;
-                       break;
-                       
-               case 0:
-                       XMLNode *aevents = node->add_child("Automation");
-                       
-                       for (set<uint32_t>::iterator x = visible_parameter_automation.begin(); x != visible_parameter_automation.end(); ++x) {
-                               if (x != visible_parameter_automation.begin()) {
-                                       sstr << ' ';
-                               }
-                               sstr << *x;
+               for (set<uint32_t>::iterator x = visible_parameter_automation.begin(); x != visible_parameter_automation.end(); ++x) {
+                       if (x != visible_parameter_automation.begin()) {
+                               sstr << ' ';
                        }
-                       
-                       aevents->add_property ("path", path);
-                       aevents->add_property ("visible", sstr.str());
-                       break;
+                       sstr << *x;
                }
-       }
 
-       return *node;
-}
+               automation.add_property ("visible", sstr.str());
 
-void
-Redirect::what_has_automation (set<uint32_t>& s) const
-{
-       Glib::Mutex::Lock lm (_automation_lock);
-       map<uint32_t,AutomationList*>::const_iterator li;
-       
-       for (li = parameter_automation.begin(); li != parameter_automation.end(); ++li) {
-               s.insert  ((*li).first);
+               node->add_child_nocopy (automation);
        }
-}
 
-void
-Redirect::what_has_visible_automation (set<uint32_t>& s) const
-{
-       Glib::Mutex::Lock lm (_automation_lock);
-       set<uint32_t>::const_iterator li;
-       
-       for (li = visible_parameter_automation.begin(); li != visible_parameter_automation.end(); ++li) {
-               s.insert  (*li);
-       }
+       return *node;
 }
 
+
 int
 Redirect::set_state (const XMLNode& node)
 {
@@ -310,14 +231,15 @@ Redirect::set_state (const XMLNode& node)
                        IO::set_state (**niter);
                        have_io = true;
 
-               } else if ((*niter)->name() == "Automation") {
+               } else if ((*niter)->name() == X_("Automation")) {
+
 
                        XMLProperty *prop;
                        
                        if ((prop = (*niter)->property ("path")) != 0) {
-                               load_automation (prop->value());
+                               old_set_automation_state (*(*niter));
                        } else {
-                               warning << string_compose(_("%1: Automation node has no path property"), _name) << endmsg;
+                               set_automation_state (*(*niter));
                        }
 
                        if ((prop = (*niter)->property ("visible")) != 0) {
@@ -352,8 +274,11 @@ Redirect::set_state (const XMLNode& node)
        }
 
        if (_active != (prop->value() == "yes")) {
-               _active = !_active;
-               active_changed (this, this); /* EMIT_SIGNAL */
+               if (!(_session.state_of_the_state() & Session::Loading) || 
+                   !Session::get_disable_all_loaded_plugins()) {
+                       _active = !_active;
+                       active_changed (this, this); /* EMIT_SIGNAL */
+               }
        }
        
        if ((prop = node.property ("placement")) == 0) {
@@ -361,11 +286,120 @@ Redirect::set_state (const XMLNode& node)
                return -1;
        }
 
-       set_placement (prop->value(), this);
+       /* hack to handle older sessions before we only used EnumWriter */
+
+       string pstr;
+
+       if (prop->value() == "pre") {
+               pstr = "PreFader";
+       } else if (prop->value() == "post") {
+               pstr = "PostFader";
+       } else {
+               pstr = prop->value();
+       }
+
+       Placement p = Placement (string_2_enum (pstr, p));
+       set_placement (p, this);
+
+       return 0;
+}
+
+int
+Redirect::old_set_automation_state (const XMLNode& node)
+{
+       const XMLProperty *prop;
+                       
+       if ((prop = node.property ("path")) != 0) {
+               load_automation (prop->value());
+       } else {
+               warning << string_compose(_("%1: Automation node has no path property"), _name) << endmsg;
+       }
+       
+       if ((prop = node.property ("visible")) != 0) {
+               uint32_t what;
+               stringstream sstr;
+               
+               visible_parameter_automation.clear ();
+               
+               sstr << prop->value();
+               while (1) {
+                       sstr >> what;
+                       if (sstr.fail()) {
+                               break;
+                       }
+                       mark_automation_visible (what, true);
+               }
+       }
+
+       return 0;
+}
+
+int
+Redirect::load_automation (string path)
+{
+       string fullpath;
+
+       if (path[0] == '/') { // legacy
+               fullpath = path;
+       } else {
+               fullpath = _session.automation_dir();
+               fullpath += path;
+       }
+       ifstream in (fullpath.c_str());
+
+       if (!in) {
+               warning << string_compose(_("%1: cannot open %2 to load automation data (%3)"), _name, fullpath, strerror (errno)) << endmsg;
+               return 1;
+       }
+
+       Glib::Mutex::Lock lm (_automation_lock);
+       set<uint32_t> tosave;
+       parameter_automation.clear ();
+
+       while (in) {
+               double when;
+               double value;
+               uint32_t port;
 
+               in >> port;     if (!in) break;
+               in >> when;  if (!in) goto bad;
+               in >> value; if (!in) goto bad;
+               
+               AutomationList& al = automation_list (port);
+               al.add (when, value);
+               tosave.insert (port);
+       }
+       
        return 0;
+
+  bad:
+       error << string_compose(_("%1: cannot load automation data from %2"), _name, fullpath) << endmsg;
+       parameter_automation.clear ();
+       return -1;
 }
 
+
+void
+Redirect::what_has_automation (set<uint32_t>& s) const
+{
+       Glib::Mutex::Lock lm (_automation_lock);
+       map<uint32_t,AutomationList*>::const_iterator li;
+       
+       for (li = parameter_automation.begin(); li != parameter_automation.end(); ++li) {
+               s.insert  ((*li).first);
+       }
+}
+
+void
+Redirect::what_has_visible_automation (set<uint32_t>& s) const
+{
+       Glib::Mutex::Lock lm (_automation_lock);
+       set<uint32_t>::const_iterator li;
+       
+       for (li = visible_parameter_automation.begin(); li != visible_parameter_automation.end(); ++li) {
+               s.insert  (*li);
+       }
+}
 AutomationList&
 Redirect::automation_list (uint32_t parameter)
 {
@@ -438,37 +472,10 @@ Redirect::find_next_event (nframes_t now, nframes_t end, ControlEvent& next_even
        return next_event.when != max_frames;
 }
 
-void
-Redirect::store_state (RedirectState& state) const
-{
-       state.active = _active;
-}
-
-Change
-Redirect::restore_state (StateManager::State& state)
-{
-       RedirectState* rstate = dynamic_cast<RedirectState*> (&state);
-       set_active (rstate->active, this);
-       return Change (0);
-}
-
-StateManager::State*
-Redirect::state_factory (std::string why) const
-{
-       RedirectState* state = new RedirectState (why);
-
-       store_state (*state);
-
-       return state;
-}
-
 void
 Redirect::set_active (bool yn, void* src)
 {
        _active = yn; 
-#ifdef STATE_MANAGER
-       save_state (_("active_changed"));
-#endif
        active_changed (this, src); 
        _session.set_dirty ();
 }