forward port 2.X changes up to and including rev 6909
[ardour.git] / libs / ardour / automatable.cc
index 85f083ca370c8035b9c1e2c980ebafc9d6c21206..5ae4e96b4e1f87436e53a0356ba9ed350e6d22b6 100644 (file)
@@ -22,6 +22,9 @@
 #include <inttypes.h>
 #include <cstdio>
 #include <errno.h>
+
+#include <glibmm/miscutils.h>
+
 #include "pbd/error.h"
 #include "pbd/enumwriter.h"
 
@@ -49,6 +52,18 @@ Automatable::Automatable(Session& session)
 {
 }
 
+Automatable::Automatable (const Automatable& other)
+        : ControlSet (other)
+        , _a_session (other._a_session)
+        , _last_automation_snapshot (0)
+{
+        Glib::Mutex::Lock lm (other._control_lock);
+
+        for (Controls::const_iterator i = other._controls.begin(); i != other._controls.end(); ++i) {
+                boost::shared_ptr<Evoral::Control> ac (control_factory (i->first));
+               add_control (ac);
+        }
+}
 int
 Automatable::old_set_automation_state (const XMLNode& node)
 {
@@ -86,7 +101,7 @@ Automatable::load_automation (const string& path)
 {
        string fullpath;
 
-       if (path[0] == '/') { // legacy
+       if (Glib::path_is_absolute (path)) { // legacy
                fullpath = path;
        } else {
                fullpath = _a_session.automation_dir();
@@ -135,9 +150,17 @@ Automatable::add_control(boost::shared_ptr<Evoral::Control> ac)
 {
        Evoral::Parameter param = ac->parameter();
 
-       ControlSet::add_control(ac);
-       _can_automate_list.insert(param);
-       auto_state_changed(param); // sync everything up
+       boost::shared_ptr<AutomationList> al = boost::dynamic_pointer_cast<AutomationList> (ac->list ());
+       assert (al);
+       
+       al->automation_state_changed.connect_same_thread (
+               _list_connections, boost::bind (&Automatable::automation_list_automation_state_changed, this, ac->parameter(), _1)
+               );
+
+       ControlSet::add_control (ac);
+       _can_automate_list.insert (param);
+
+       automation_list_automation_state_changed (param, al->automation_state ()); // sync everything up
 }
 
 void
@@ -162,7 +185,7 @@ Automatable::describe_parameter (Evoral::Parameter param)
                /* ID's are zero-based, present them as 1-based */
                return (string_compose(_("Pan %1"), param.id() + 1));
        } else if (param.type() == MidiCCAutomation) {
-               return string_compose("%2 [%3]",
+               return string_compose("%1: %2 [%3]",
                                param.id() + 1, midi_name(param.id()), int(param.channel()) + 1);
        } else if (param.type() == MidiPgmChangeAutomation) {
                return string_compose("Program [%1]", int(param.channel()) + 1);
@@ -293,21 +316,16 @@ Automatable::set_parameter_automation_state (Evoral::Parameter param, AutoState
 }
 
 AutoState
-Automatable::get_parameter_automation_state (Evoral::Parameter param, bool lock)
+Automatable::get_parameter_automation_state (Evoral::Parameter param)
 {
        AutoState result = Off;
 
-       if (lock)
-               control_lock().lock();
-
        boost::shared_ptr<Evoral::Control> c = control(param);
        boost::shared_ptr<AutomationList> l = boost::dynamic_pointer_cast<AutomationList>(c->list());
 
-       if (c)
+       if (c) {
                result = l->automation_state();
-
-       if (lock)
-               control_lock().unlock();
+       }
 
        return result;
 }
@@ -376,7 +394,7 @@ Automatable::automation_snapshot (nframes_t now, bool force)
                        boost::shared_ptr<AutomationControl> c
                                        = boost::dynamic_pointer_cast<AutomationControl>(i->second);
                        if (c->automation_write()) {
-                               c->list()->rt_add (now, i->second->user_float());
+                               c->list()->rt_add (now, i->second->user_double());
                        }
                }
 
@@ -408,21 +426,39 @@ Automatable::control_factory(const Evoral::Parameter& param)
        boost::shared_ptr<AutomationList> list(new AutomationList(param));
        Evoral::Control* control = NULL;
        if (param.type() >= MidiCCAutomation && param.type() <= MidiChannelPressureAutomation) {
-               control = new MidiTrack::MidiControl((MidiTrack*)this, param);
+               MidiTrack* mt = dynamic_cast<MidiTrack*>(this);
+               if (mt) {
+                       control = new MidiTrack::MidiControl(mt, param);
+               } else {
+                       warning << "MidiCCAutomation for non-MidiTrack" << endl;
+               }
        } else if (param.type() == PluginAutomation) {
-               control = new PluginInsert::PluginControl((PluginInsert*)this, param);
+               PluginInsert* pi = dynamic_cast<PluginInsert*>(this);
+               if (pi) {
+                       control = new PluginInsert::PluginControl(pi, param);
+               } else {
+                       warning << "PluginAutomation for non-Plugin" << endl;
+               }
        } else if (param.type() == GainAutomation) {
-               control = new Amp::GainControl( X_("gaincontrol"), _a_session, (Amp*)this, param);
+               Amp* amp = dynamic_cast<Amp*>(this);
+               if (amp) {
+                       control = new Amp::GainControl(X_("gaincontrol"), _a_session, amp, param);
+               } else {
+                       warning << "GainAutomation for non-Amp" << endl;
+               }
        } else if (param.type() == PanAutomation) {
                Panner* me = dynamic_cast<Panner*>(this);
                if (me) {
                        control = new Panner::PanControllable(me->session(), X_("panner"), *me, param);
                } else {
-                       cerr << "ERROR: PanAutomation for non-Panner" << endl;
+                       warning << "PanAutomation for non-Panner" << endl;
                }
-       } else {
+       }
+
+       if (!control) {
                control = new AutomationControl(_a_session, param);
        }
+
        control->set_list(list);
        return boost::shared_ptr<Evoral::Control>(control);
 }
@@ -439,3 +475,9 @@ Automatable::automation_control (const Evoral::Parameter& id) const
        return boost::dynamic_pointer_cast<const AutomationControl>(Evoral::ControlSet::control(id));
 }
 
+void
+Automatable::clear_controls ()
+{
+       _control_connections.drop_connections ();
+       ControlSet::clear_controls ();
+}