+ bool from_list = alist() && alist()->automation_playback();
+ return Control::get_double (from_list, _session.transport_sample());
+}
+
+double
+AutomationControl::get_save_value() const
+{
+ /* save user-value, not incl masters */
+ return Control::get_double ();
+}
+
+void
+AutomationControl::pre_realtime_queue_stuff (double val, PBD::Controllable::GroupControlDisposition gcd)
+{
+ if (_group && _group->use_me (gcd)) {
+ _group->pre_realtime_queue_stuff (val);
+ } else {
+ do_pre_realtime_queue_stuff (val);
+ }
+}
+
+void
+AutomationControl::set_value (double val, PBD::Controllable::GroupControlDisposition gcd)
+{
+ if (!writable()) {
+ return;
+ }
+
+ /* enforce strict double/boolean value mapping */
+
+ if (_desc.toggled) {
+ if (val != 0.0) {
+ val = 1.0;
+ }
+ }
+
+ if (check_rt (val, gcd)) {
+ /* change has been queued to take place in an RT context */
+ return;
+ }
+
+ if (_group && _group->use_me (gcd)) {
+ _group->set_group_value (shared_from_this(), val);
+ } else {
+ actually_set_value (val, gcd);
+ }
+}
+
+ControlList
+AutomationControl::grouped_controls () const
+{
+ if (_group && _group->use_me (PBD::Controllable::UseGroup)) {
+ return _group->controls ();
+ } else {
+ return ControlList ();
+ }
+}
+
+void
+AutomationControl::automation_run (samplepos_t start, pframes_t nframes)
+{
+ if (!automation_playback ()) {
+ return;
+ }
+
+ assert (_list);
+ bool valid = false;
+ double val = _list->rt_safe_eval (start, valid);
+ if (!valid) {
+ return;
+ }
+ if (toggled ()) {
+ const double thresh = .5 * (_desc.upper - _desc.lower);
+ set_value_unchecked (val >= thresh ? _desc.upper : _desc.lower);
+ } else {
+ set_value_unchecked (val);
+ }