Add support for Latch Automation
authorRobin Gareus <robin@gareus.org>
Tue, 25 Jul 2017 14:09:47 +0000 (16:09 +0200)
committerPaul Davis <paul@linuxaudiosystems.com>
Mon, 18 Sep 2017 15:40:52 +0000 (11:40 -0400)
libs/ardour/ardour/automation_list.h
libs/ardour/ardour/pannable.h
libs/ardour/ardour/types.h
libs/ardour/automatable.cc
libs/ardour/automation_control.cc
libs/ardour/enums.cc
libs/ardour/luabindings.cc
libs/ardour/panner_shell.cc
libs/ardour/utils.cc

index 359d98856c846cebbf08f6631a137afcc1f08e3e..4601740af1fb7727306935c31fbabfd053d2ad0d 100644 (file)
@@ -89,10 +89,10 @@ public:
        PBD::Signal1<void, AutoState> automation_state_changed;
 
        bool automation_playback() const {
-               return (_state & Play) || ((_state & Touch) && !touching());
+               return (_state & Play) || ((_state & (Touch | Latch)) && !touching());
        }
        bool automation_write () const {
-               return ((_state & Write) || ((_state & Touch) && touching()));
+               return ((_state & Write) || ((_state & (Touch | Latch)) && touching()));
        }
 
        PBD::Signal0<void> StateChanged;
@@ -106,7 +106,7 @@ public:
        void stop_touch (double when);
        bool touching() const { return g_atomic_int_get (const_cast<gint*>(&_touching)); }
        bool writing() const { return _state == Write; }
-       bool touch_enabled() const { return _state == Touch; }
+       bool touch_enabled() const { return _state & (Touch | Latch); }
 
        XMLNode& get_state ();
        int set_state (const XMLNode &, int version);
index cd88a250cfb6bdc92076d219a644087de6a5086e..f96670afecdbf2bcb5bab9d03d01f3dc9937a1d1 100644 (file)
@@ -58,19 +58,19 @@ class LIBARDOUR_API Pannable : public PBD::Stateful, public Automatable, public
        PBD::Signal1<void, AutoState> automation_state_changed;
 
        bool automation_playback() const {
-               return (_auto_state & Play) || ((_auto_state & Touch) && !touching());
+               return (_auto_state & Play) || ((_auto_state & (Touch | Latch)) && !touching());
        }
        bool automation_write () const {
-               return ((_auto_state & Write) || ((_auto_state & Touch) && touching()));
+               return ((_auto_state & Write) || ((_auto_state & (Touch | Latch)) && touching()));
        }
 
        std::string value_as_string (boost::shared_ptr<const AutomationControl>) const;
 
        void start_touch (double when);
        void stop_touch (double when);
-        bool touching() const { return g_atomic_int_get (const_cast<gint*>(&_touching)); }
+       bool touching() const { return g_atomic_int_get (const_cast<gint*>(&_touching)); }
        bool writing() const { return _auto_state == Write; }
-       bool touch_enabled() const { return _auto_state == Touch; }
+       bool touch_enabled() const { return _auto_state & (Touch | Latch); }
 
        XMLNode& get_state ();
        XMLNode& state (bool full_state);
index 854fb04066691349cf574531cb075b1b08c59b3d..8358d78e9ad5299dc5809e63e331f03a0fdaf129 100644 (file)
@@ -163,10 +163,11 @@ namespace ARDOUR {
        };
 
        enum AutoState {
-               Off = 0x0,
-               Write = 0x1,
-               Touch = 0x2,
-               Play = 0x4
+               Off   = 0x00,
+               Write = 0x01,
+               Touch = 0x02,
+               Play  = 0x04,
+               Latch = 0x08
        };
 
        std::string auto_state_to_string (AutoState);
index 57c8205717ced5f8baf970b99d1b1e8c467c82a2..8025386d1f11e4e06fd5befb127184798df8f581 100644 (file)
@@ -329,6 +329,8 @@ Automatable::protect_automation ()
                case Write:
                        l->set_automation_state (Off);
                        break;
+               case Latch:
+                       // no break
                case Touch:
                        l->set_automation_state (Play);
                        break;
@@ -408,6 +410,7 @@ Automatable::non_realtime_transport_stop (framepos_t now, bool /*flush_processor
                */
                const bool list_did_write = !l->in_new_write_pass ();
 
+               c->stop_touch (now);
                l->stop_touch (now);
 
                c->commit_transaction (list_did_write);
index 7deeac422185e37c44684c5b680d917431d6aae6..02bcbf4f659d88e7d734b4ee1f2151f51540dd46 100644 (file)
@@ -253,7 +253,7 @@ AutomationControl::set_automation_state (AutoState as)
 
                if (as == Write) {
                        AutomationWatch::instance().add_automation_watch (shared_from_this());
-               } else if (as == Touch) {
+               } else if (as & (Touch | Latch)) {
                        if (alist()->empty()) {
                                Control::set_double (val, _session.current_start_frame (), true);
                                Control::set_double (val, _session.current_end_frame (), true);
@@ -283,7 +283,7 @@ AutomationControl::start_touch (double when)
                return;
        }
 
-       if (alist()->automation_state() == Touch) {
+       if (alist()->automation_state() & (Touch | Latch)) {
                /* subtle. aligns the user value with the playback and
                 * use take actual value (incl masters).
                 *
@@ -306,9 +306,13 @@ AutomationControl::stop_touch (double when)
                return;
        }
 
+       if (alist()->automation_state() == Latch && _session.transport_rolling ()) {
+               return;
+       }
+
        set_touching (false);
 
-       if (alist()->automation_state() == Touch) {
+       if (alist()->automation_state() & (Touch | Latch)) {
                alist()->stop_touch (when);
                if (!_desc.toggled) {
                        AutomationWatch::instance().remove_automation_watch (shared_from_this());
index bd7c2dd39b425ebf09fb91f9ebd807f676a3018f..eee20f811d1f951c84abd1e5f2b0d7b8112e9bb4 100644 (file)
@@ -177,6 +177,7 @@ setup_enum_writer ()
        REGISTER_ENUM (Write);
        REGISTER_ENUM (Touch);
        REGISTER_ENUM (Play);
+       REGISTER_ENUM (Latch);
        REGISTER_BITS (_AutoState);
 
        REGISTER_ENUM (CaptureTime);
index 4575e9fbecf98b36d508497bec37d04d95133164..8b5c6a2a341667956cd630e185eae7338c76fea4 100644 (file)
@@ -1704,6 +1704,7 @@ LuaBindings::common (lua_State* L)
                .addConst ("Write", ARDOUR::AutoState(Write))
                .addConst ("Touch", ARDOUR::AutoState(Touch))
                .addConst ("Play", ARDOUR::AutoState(Play))
+               .addConst ("Latch", ARDOUR::AutoState(Latch))
                .endNamespace ()
 
                .beginNamespace ("AutomationType")
index a3b7de287ae67166102dc4fd8d4b773cfed9cbc6..e53c1d346c11673974893adf82007cb00b9271b7 100644 (file)
@@ -382,7 +382,7 @@ PannerShell::run (BufferSet& inbufs, BufferSet& outbufs, framepos_t start_frame,
 
        // If we shouldn't play automation defer to distribute_no_automation
 
-       if (!(as & Play || ((as & Touch) && !_panner->touching()))) {
+       if (!((as & Play) || ((as & (Touch | Latch)) && !_panner->touching()))) {
 
                distribute_no_automation (inbufs, outbufs, nframes, 1.0);
 
index 31a94702e122c4486daf6c02e7cc2914cc13f4c8..17c1da0850a54096f3bbd63df0759c061fc039bc 100644 (file)
@@ -561,6 +561,8 @@ ARDOUR::string_to_auto_state (std::string str)
                return Write;
        } else if (str == X_("Touch")) {
                return Touch;
+       } else if (str == X_("Latch")) {
+               return Latch;
        }
 
        fatal << string_compose (_("programming error: %1 %2"), "illegal AutoState string: ", str) << endmsg;
@@ -585,6 +587,10 @@ ARDOUR::auto_state_to_string (AutoState as)
                break;
        case Touch:
                return X_("Touch");
+               break;
+       case Latch:
+               return X_("Latch");
+               break;
        }
 
        fatal << string_compose (_("programming error: %1 %2"), "illegal AutoState type: ", as) << endmsg;