Make automation record undo per pass rather than per touch.
authornick_m <mainsbridge@gmail.com>
Sat, 26 Sep 2015 14:57:52 +0000 (00:57 +1000)
committernick_m <mainsbridge@gmail.com>
Mon, 19 Oct 2015 13:53:28 +0000 (00:53 +1100)
gtk2_ardour/automation_controller.cc
libs/ardour/ardour/automation_control.h
libs/ardour/ardour/automation_list.h
libs/ardour/automatable.cc
libs/ardour/automation_control.cc
libs/ardour/automation_list.cc
libs/ardour/route.cc
libs/evoral/evoral/ControlList.hpp

index 1bce94dca2b464c9f024fd3f41bd67680891d607..691e0f3b58328c96bcc128b9a2d6720d2a757463 100644 (file)
@@ -196,7 +196,22 @@ void
 AutomationController::toggled ()
 {
        ArdourButton* but = dynamic_cast<ArdourButton*>(_widget);
+       const AutoState as = _controllable->automation_state ();
+
+       const bool to_list = _controllable->list () && _controllable->session().transport_rolling () && (as == Touch || as == Write);
+
        if (but) {
+               if (_controllable->session().transport_rolling()) {
+                       if (_controllable->automation_state() == Touch && _controllable->list()->in_new_write_pass ()) {
+                               _controllable->alist()->start_write_pass ( _controllable->session().audible_frame());
+                       }
+                       if (_controllable->list()) {
+                               _controllable->list()->set_in_write_pass(true, false, _controllable->session().audible_frame());
+                       }
+               }
+
+               _controllable->set_double (!but->get_active (), _controllable->session ().transport_frame (), to_list);
+
                const bool was_active = _controllable->get_value() >= 0.5;
                if (was_active && but->get_active()) {
                        _adjustment->set_value(0.0);
index 5d73e4aef959107d80613b5c96ac804a63eacdc1..c634e3474a7b437740e53341789f4de98c054eaf 100644 (file)
@@ -95,13 +95,13 @@ public:
        const ParameterDescriptor& desc() const { return _desc; }
 
        const ARDOUR::Session& session() const { return _session; }
+       void commit_transaction ();
 
 protected:
 
        ARDOUR::Session& _session;
 
        const ParameterDescriptor _desc;
-       XMLNode* _before; //used for undo of touch start/stop pairs.
 };
 
 
index bc47f2fe0672d520996b8cb6cdb0e6ebb6d16646..67ee6234bb1ddcb5fff810a1e1f115ad67d3ce31 100644 (file)
@@ -97,6 +97,9 @@ class LIBARDOUR_API AutomationList : public PBD::StatefulDestructible, public Ev
 
        static PBD::Signal1<void,AutomationList*> AutomationListCreated;
 
+       void start_write_pass (double when);
+       void write_pass_finished (double when, double thinning_factor=0.0);
+
        void start_touch (double when);
        void stop_touch (bool mark, double when);
         bool touching() const { return g_atomic_int_get (const_cast<gint*>(&_touching)); }
@@ -110,6 +113,7 @@ class LIBARDOUR_API AutomationList : public PBD::StatefulDestructible, public Ev
 
        bool operator!= (const AutomationList &) const;
 
+       XMLNode* before () { return _before; }
   private:
        void create_curve_if_necessary ();
        int deserialize_events (const XMLNode&);
@@ -121,6 +125,8 @@ class LIBARDOUR_API AutomationList : public PBD::StatefulDestructible, public Ev
        gint         _touching;
 
        bool operator== (const AutomationList&) const { /* not called */ abort(); return false; }
+       XMLNode* _before; //used for undo of touch start/stop pairs.
+
 };
 
 } // namespace
index 0b316890bc354eedd8163de49fac0dc0a788f071..1c72f202b23ce37cc1674713612ead1d78796b4b 100644 (file)
@@ -365,7 +365,7 @@ Automatable::transport_located (framepos_t now)
                         boost::shared_ptr<AutomationList> l
                                = boost::dynamic_pointer_cast<AutomationList>(c->list());
 
-                       if (l) {
+                       if (l && l->automation_state () == Write) {
                                l->start_write_pass (now);
                        }
                }
@@ -394,7 +394,12 @@ Automatable::transport_stopped (framepos_t now)
                   when the transport is re-started, a touch will magically
                   be happening without it ever have being started in the usual way.
                */
+               const bool list_did_write = !l->in_new_write_pass ();
+
                l->stop_touch (true, now);
+               if (list_did_write) {
+                       c->commit_transaction ();
+               }
                l->write_pass_finished (now, Config->get_automation_thinning_factor());
 
                if (l->automation_playback()) {
index 26ea53cbd2d1c22fd9a71107ef471601d5f6da3b..0e2355e708947ffdabd0ba6aa87520fe39cf6c47 100644 (file)
@@ -88,8 +88,6 @@ AutomationControl::set_automation_state (AutoState as)
                }
 
                if (as == Write) {
-                       /* get state for undo */
-                       _before = &alist ()->get_state ();
                        AutomationWatch::instance().add_automation_watch (shared_from_this());
                } else if (as == Touch) {
                        if (!touching()) {
@@ -127,7 +125,6 @@ AutomationControl::start_touch(double when)
                if (alist()->automation_state() == Touch) {
                        /* subtle. aligns the user value with the playback */
                        set_value (get_value ());
-                       _before = &alist ()->get_state ();
                        alist()->start_touch (when);
                        if (!_desc.toggled) {
                                AutomationWatch::instance().add_automation_watch (shared_from_this());
@@ -144,25 +141,25 @@ AutomationControl::stop_touch(bool mark, double when)
        if (touching()) {
                set_touching (false);
 
-               if (alist()->automation_state() == Write) {
-                       _session.begin_reversible_command (string_compose (_("write %1 automation"), name ()));
-                       _session.add_command (new MementoCommand<AutomationList> (*alist ().get (), _before, &alist ()->get_state ()));
-                       _session.commit_reversible_command ();
-               }
-
                if (alist()->automation_state() == Touch) {
                        alist()->stop_touch (mark, when);
                        if (!_desc.toggled) {
                                AutomationWatch::instance().remove_automation_watch (shared_from_this());
-                       }
 
-                       _session.begin_reversible_command (string_compose (_("touch %1 automation"), name ()));
-                       _session.add_command (new MementoCommand<AutomationList> (*alist ().get (), _before, &alist ()->get_state ()));
-                       _session.commit_reversible_command ();
+                       }
                }
        }
 }
 
+void
+AutomationControl::commit_transaction ()
+{
+       if (alist ()->before ()) {
+               _session.begin_reversible_command (string_compose (_("record %1 automation"), name ()));
+               _session.commit_reversible_command (new MementoCommand<AutomationList> (*alist ().get (), alist ()->before (), &alist ()->get_state ()));
+       }
+}
+
 double
 AutomationControl::internal_to_interface (double val) const
 {
index 91609f6acbe05aa2183255552657e4f3c561b1ce..afff85c1f83d63afbde9f665399ec89d96e10aa3 100644 (file)
@@ -50,6 +50,7 @@ static void dumpit (const AutomationList& al, string prefix = "")
 #endif
 AutomationList::AutomationList (const Evoral::Parameter& id, const Evoral::ParameterDescriptor& desc)
        : ControlList(id, desc)
+       , _before (0)
 {
        _state = Off;
        _style = Absolute;
@@ -63,6 +64,7 @@ AutomationList::AutomationList (const Evoral::Parameter& id, const Evoral::Param
 
 AutomationList::AutomationList (const Evoral::Parameter& id)
        : ControlList(id, ARDOUR::ParameterDescriptor(id))
+       , _before (0)
 {
        _state = Off;
        _style = Absolute;
@@ -77,6 +79,7 @@ AutomationList::AutomationList (const Evoral::Parameter& id)
 AutomationList::AutomationList (const AutomationList& other)
        : StatefulDestructible()
        , ControlList(other)
+       , _before (0)
 {
        _style = other._style;
        _state = other._state;
@@ -90,6 +93,7 @@ AutomationList::AutomationList (const AutomationList& other)
 
 AutomationList::AutomationList (const AutomationList& other, double start, double end)
        : ControlList(other, start, end)
+       , _before (0)
 {
        _style = other._style;
        _state = other._state;
@@ -106,6 +110,7 @@ AutomationList::AutomationList (const AutomationList& other, double start, doubl
  */
 AutomationList::AutomationList (const XMLNode& node, Evoral::Parameter id)
        : ControlList(id, ARDOUR::ParameterDescriptor(id))
+       , _before (0)
 {
        g_atomic_int_set (&_touching, 0);
        _state = Off;
@@ -186,6 +191,9 @@ AutomationList::set_automation_state (AutoState s)
 {
        if (s != _state) {
                _state = s;
+               if (s == Write) {
+                       _before = &get_state ();
+               }
                automation_state_changed (s); /* EMIT SIGNAL */
        }
 }
@@ -199,6 +207,22 @@ AutomationList::set_automation_style (AutoStyle s)
        }
 }
 
+void
+AutomationList::start_write_pass (double when)
+{
+       if (in_new_write_pass ()) {
+               _before = &get_state ();
+       }
+       ControlList::start_write_pass (when);
+}
+
+void
+AutomationList::write_pass_finished (double when, double thinning_factor)
+{
+       ControlList::write_pass_finished (when, thinning_factor);
+       _before = 0;
+}
+
 void
 AutomationList::start_touch (double when)
 {
index cb3f0d48c94fee50cabff6eca55f18bde90d7ea4..adbfefb829626ee1855c724051881884889d96ef 100644 (file)
@@ -3904,11 +3904,15 @@ Route::MuteControllable::set_superficial_value(bool muted)
           as currently MuteControllable can't be touching.
           bool to_list = _list && ((AutomationList*)_list.get())->automation_write();
        */
-       const AutoState as = ((AutomationList*)_list.get())->automation_state ();
-       bool to_list = _list && _session.transport_rolling () && (as == Touch || as == Write);
+       AutomationList* alist = (AutomationList*)_list.get();
+       const AutoState as = alist->automation_state ();
+       const bool to_list = _list && _session.transport_rolling () && (as == Touch || as == Write);
 
        if (to_list) {
-               _list->set_in_write_pass(true, false, _session.audible_frame ());
+               if (as == Touch && _list->in_new_write_pass ()) {
+                       alist->start_write_pass (_session.audible_frame ());
+               }
+               _list->set_in_write_pass (true, false, _session.audible_frame ());
        }
 
        Control::set_double (muted, _session.transport_frame(), to_list);
index 80096b65a43d093afbdfa15039134ff66ea6b56b..f1a4627a1cce14807bd141d30d5c20dfac12084f 100644 (file)
@@ -267,6 +267,7 @@ public:
         void write_pass_finished (double when, double thinning_factor=0.0);
         void set_in_write_pass (bool, bool add_point = false, double when = 0.0);
         bool in_write_pass () const;
+       bool in_new_write_pass () { return new_write_pass; }
 
        /** Emitted when mark_dirty() is called on this object */
        mutable PBD::Signal0<void> Dirty;