Apply master-value to automation on disconnect.
authorRobin Gareus <robin@gareus.org>
Tue, 13 Jun 2017 18:57:01 +0000 (20:57 +0200)
committerRobin Gareus <robin@gareus.org>
Tue, 13 Jun 2017 18:57:37 +0000 (20:57 +0200)
libs/ardour/ardour/slavable_automation_control.h
libs/ardour/slavable_automation_control.cc
libs/evoral/evoral/ControlList.hpp
libs/evoral/src/ControlList.cpp

index 3cfc22405c88c4e1311784b1cef7173e9e18b18b..88114d24c60356f364438ad840e6ba7e10c9c4b7 100644 (file)
@@ -138,6 +138,7 @@ protected:
        bool masters_curve_multiply (framepos_t, framepos_t, float*, framecnt_t) const;
 
        virtual double reduce_by_masters_locked (double val, bool) const;
+       virtual double scale_automation_callback (double val, double ratio) const;
 
        virtual bool handle_master_change (boost::shared_ptr<AutomationControl>);
        virtual bool boolean_automation_run_locked (framepos_t start, pframes_t len);
index 53808c862a13ca56da92f936ed43a18bb6637b5b..a1fd18571ae08b7b2e607ab7d0d128279af62bc5 100644 (file)
@@ -314,6 +314,15 @@ SlavableAutomationControl::master_going_away (boost::weak_ptr<AutomationControl>
        }
 }
 
+double
+SlavableAutomationControl::scale_automation_callback (double value, double ratio) const
+{
+       /* derived classes can override this and e.g. add/subtract. */
+       value *= ratio;
+       value = std::max (lower(), std::min(upper(), value));
+       return value;
+}
+
 void
 SlavableAutomationControl::remove_master (boost::shared_ptr<AutomationControl> m)
 {
@@ -323,17 +332,20 @@ SlavableAutomationControl::remove_master (boost::shared_ptr<AutomationControl> m
        }
 
        pre_remove_master (m);
-       double new_val = AutomationControl::get_double();
-       const double old_val = new_val;
+
+       const double old_val = AutomationControl::get_double();
+
+       bool update_value = false;
+       double master_ratio = 0;
 
        {
                Glib::Threads::RWLock::WriterLock lm (master_lock);
 
                Masters::const_iterator mi = _masters.find (m->id ());
 
-               /* when un-assigning we apply the master-value permanently */
                if (mi != _masters.end()) {
-                       new_val *= mi->second.master_ratio ();
+                       master_ratio = mi->second.master_ratio ();
+                       update_value = true;
                }
 
                if (!_masters.erase (m->id())) {
@@ -341,8 +353,19 @@ SlavableAutomationControl::remove_master (boost::shared_ptr<AutomationControl> m
                }
        }
 
-       if (old_val != new_val) {
-               AutomationControl::set_double (new_val, Controllable::NoGroup);
+       if (update_value) {
+               /* when un-assigning we apply the master-value permanently */
+                       double new_val = old_val * master_ratio;
+
+                       if (old_val != new_val) {
+                               AutomationControl::set_double (new_val, Controllable::NoGroup);
+                       }
+
+                       /* ..and update automation */
+                       if (_list) {
+                               // do we need to freeze/thaw the list? probably no: iterators & positions don't change
+                               _list->y_transform (boost::bind (&SlavableAutomationControl::scale_automation_callback, this, _1, master_ratio));
+                       }
        }
 
        MasterStatusChange (); /* EMIT SIGNAL */
@@ -360,8 +383,10 @@ SlavableAutomationControl::clear_masters ()
                return;
        }
 
-       double new_val = AutomationControl::get_double();
-       const double old_val = new_val;
+       const double old_val = AutomationControl::get_double();
+
+       bool update_value = false;
+       double master_ratio = 0;
 
        /* null ptr means "all masters */
        pre_remove_master (boost::shared_ptr<AutomationControl>());
@@ -371,15 +396,26 @@ SlavableAutomationControl::clear_masters ()
                if (_masters.empty()) {
                        return;
                }
-               /* permanently apply masters value */
-               new_val *= get_masters_value_locked ();
-
+               master_ratio = get_masters_value_locked ();
+               update_value = true;
                _masters.clear ();
        }
 
-       if (old_val != new_val) {
-               AutomationControl::set_double (new_val, Controllable::NoGroup);
+       if (update_value) {
+               /* permanently apply masters value */
+                       double new_val = old_val * master_ratio;
+
+                       if (old_val != new_val) {
+                               AutomationControl::set_double (new_val, Controllable::NoGroup);
+                       }
+
+                       /* ..and update automation */
+                       if (_list) {
+                               // do we need to freeze/thaw the list? probably no: iterators & positions don't change
+                               _list->y_transform (boost::bind (&SlavableAutomationControl::scale_automation_callback, this, _1, master_ratio));
+                       }
        }
+
        MasterStatusChange (); /* EMIT SIGNAL */
 
        /* no need to update boolean masters records, since all MRs will have
index 2a80ad5bd4e16daff158e88e822dc0f4cb412434..515067de04a2698e57dd5113d83e083ee2230823 100644 (file)
@@ -123,6 +123,8 @@ public:
        void slide (iterator before, double distance);
        void shift (double before, double distance);
 
+       void y_transform (boost::function<double(double)> callback);
+
        /** add automation events
         * @param when absolute time in samples
         * @param value parameter value
index ce8ea89fc9d347aa657e7fa3e212e3556dbe26ca..92234a6ea7a84fdcd8f12e8c6cda80038fa62c1d 100644 (file)
@@ -250,6 +250,19 @@ ControlList::extend_to (double when)
        return true;
 }
 
+void
+ControlList::y_transform (boost::function<double(double)> callback)
+{
+       {
+               Glib::Threads::RWLock::WriterLock lm (_lock);
+               for (iterator i = _events.begin(); i != _events.end(); ++i) {
+                       (*i)->value = callback ((*i)->value);
+               }
+               mark_dirty ();
+       }
+       maybe_signal_changed ();
+}
+
 void
 ControlList::_x_scale (double factor)
 {