2 Copyright (C) 2016 Paul Davis
4 This program is free software; you can redistribute it and/or modify it
5 under the terms of the GNU General Public License as published by the Free
6 Software Foundation; either version 2 of the License, or (at your option)
9 This program is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 675 Mass Ave, Cambridge, MA 02139, USA.
19 #ifndef __libardour_slavable_automation_control_h__
20 #define __libardour_slavable_automation_control_h__
22 #include "pbd/enumwriter.h"
24 #include "ardour/slavable_automation_control.h"
25 #include "ardour/session.h"
28 using namespace ARDOUR;
31 SlavableAutomationControl::SlavableAutomationControl(ARDOUR::Session& s,
32 const Evoral::Parameter& parameter,
33 const ParameterDescriptor& desc,
34 boost::shared_ptr<ARDOUR::AutomationList> l,
35 const std::string& name,
36 Controllable::Flag flags)
37 : AutomationControl (s, parameter, desc, l, name, flags)
42 SlavableAutomationControl::get_masters_value_locked () const
44 double v = _desc.normal;
47 for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
48 if (mr->second.master()->get_value()) {
55 for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
56 /* get current master value, scale by our current ratio with that master */
57 v *= mr->second.master()->get_value () * mr->second.ratio();
60 return min ((double) _desc.upper, v);
64 SlavableAutomationControl::get_value_locked() const
66 /* read or write masters lock must be held */
68 if (_masters.empty()) {
69 return Control::get_double (false, _session.transport_frame());
73 /* for boolean/toggle controls, if this slave OR any master is
74 * enabled, this slave is enabled. So check our own value
75 * first, because if we are enabled, we can return immediately.
77 if (Control::get_double (false, _session.transport_frame())) {
82 return get_masters_value_locked ();
85 /** Get the current effective `user' value based on automation state */
87 SlavableAutomationControl::get_value() const
89 bool from_list = _list && boost::dynamic_pointer_cast<AutomationList>(_list)->automation_playback();
92 Glib::Threads::RWLock::ReaderLock lm (master_lock);
93 return get_value_locked ();
95 return Control::get_double (from_list, _session.transport_frame());
100 SlavableAutomationControl::actually_set_value (double val, Controllable::GroupControlDisposition group_override)
102 val = std::max (std::min (val, (double)_desc.upper), (double)_desc.lower);
105 Glib::Threads::RWLock::WriterLock lm (master_lock);
107 if (!_masters.empty()) {
108 recompute_masters_ratios (val);
112 /* this sets the Evoral::Control::_user_value for us, which will
113 be retrieved by AutomationControl::get_value ()
115 AutomationControl::actually_set_value (val, group_override);
119 SlavableAutomationControl::add_master (boost::shared_ptr<AutomationControl> m)
121 std::pair<Masters::iterator,bool> res;
124 Glib::Threads::RWLock::WriterLock lm (master_lock);
125 const double current_value = get_value_locked ();
127 /* ratio will be recomputed below */
129 pair<PBD::ID,MasterRecord> newpair (m->id(), MasterRecord (m, 1.0));
130 res = _masters.insert (newpair);
134 recompute_masters_ratios (current_value);
136 /* note that we bind @param m as a weak_ptr<AutomationControl>, thus
137 avoiding holding a reference to the control in the binding
141 m->DropReferences.connect_same_thread (masters_connections, boost::bind (&SlavableAutomationControl::master_going_away, this, boost::weak_ptr<AutomationControl>(m)));
143 /* Store the connection inside the MasterRecord, so
144 that when we destroy it, the connection is destroyed
145 and we no longer hear about changes to the
148 Note that this also makes it safe to store a
149 boost::shared_ptr<AutomationControl> in the functor,
150 since we know we will destroy the functor when the
151 connection is destroyed, which happens when we
152 disconnect from the master (for any reason).
154 Note that we fix the "from_self" argument that will
155 be given to our own Changed signal to "false",
156 because the change came from the master.
159 m->Changed.connect_same_thread (res.first->second.connection, boost::bind (&SlavableAutomationControl::master_changed, this, _1, _2, m));
160 cerr << this << enum_2_string ((AutomationType) _parameter.type()) << " now listening to Changed from " << m << endl;
165 /* this will notify everyone that we're now slaved to the master */
166 MasterStatusChange (); /* EMIT SIGNAL */
171 update_boolean_masters_records (m);
175 SlavableAutomationControl::get_boolean_masters () const
180 Glib::Threads::RWLock::ReaderLock lm (master_lock);
181 for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
182 if (mr->second.yn()) {
192 SlavableAutomationControl::update_boolean_masters_records (boost::shared_ptr<AutomationControl> m)
195 /* We may modify a MasterRecord, but we not modify the master
196 * map, so we use a ReaderLock
198 Glib::Threads::RWLock::ReaderLock lm (master_lock);
199 Masters::iterator mi = _masters.find (m->id());
200 if (mi != _masters.end()) {
201 /* update MasterRecord to show whether the master is
202 on/off. We need to store this because the master
203 may change (in the sense of emitting Changed())
204 several times without actually changing the result
205 of ::get_value(). This is a feature of
206 AutomationControls (or even just Controllables,
207 really) which have more than a simple scalar
208 value. For example, the master may be a mute control
209 which can be muted_by_self() and/or
210 muted_by_masters(). When either of those two
211 conditions changes, Changed() will be emitted, even
212 though ::get_value() will return the same value each
213 time (1.0 if either are true, 0.0 if neither is).
215 This provides a way for derived types to check
216 the last known state of a Master when the Master
217 changes. We update it after calling
218 ::master_changed() (though derived types must do
221 mi->second.set_yn (m->get_value());
227 SlavableAutomationControl::master_changed (bool /*from_self*/, GroupControlDisposition gcd, boost::shared_ptr<AutomationControl> m)
229 update_boolean_masters_records (m);
230 Changed (false, Controllable::NoGroup); /* EMIT SIGNAL */
234 SlavableAutomationControl::master_going_away (boost::weak_ptr<AutomationControl> wm)
236 boost::shared_ptr<AutomationControl> m = wm.lock();
243 SlavableAutomationControl::remove_master (boost::shared_ptr<AutomationControl> m)
245 double current_value;
248 Masters::size_type erased = 0;
250 pre_remove_master (m);
253 Glib::Threads::RWLock::WriterLock lm (master_lock);
254 current_value = get_value_locked ();
255 erased = _masters.erase (m->id());
256 if (erased && !_session.deletion_in_progress()) {
257 recompute_masters_ratios (current_value);
259 masters_left = _masters.size ();
260 new_value = get_value_locked ();
263 if (_session.deletion_in_progress()) {
264 /* no reason to care about new values or sending signals */
269 MasterStatusChange (); /* EMIT SIGNAL */
272 if (new_value != current_value) {
273 if (masters_left == 0) {
274 /* no masters left, make sure we keep the same value
277 actually_set_value (current_value, Controllable::UseGroup);
281 /* no need to update boolean masters records, since the MR will have
282 * been removed already.
287 SlavableAutomationControl::clear_masters ()
289 double current_value;
291 bool had_masters = false;
293 /* null ptr means "all masters */
294 pre_remove_master (boost::shared_ptr<AutomationControl>());
297 Glib::Threads::RWLock::WriterLock lm (master_lock);
298 current_value = get_value_locked ();
299 if (!_masters.empty()) {
303 new_value = get_value_locked ();
307 MasterStatusChange (); /* EMIT SIGNAL */
310 if (new_value != current_value) {
311 actually_set_value (current_value, Controllable::UseGroup);
314 /* no need to update boolean masters records, since all MRs will have
315 * been removed already.
320 SlavableAutomationControl::slaved_to (boost::shared_ptr<AutomationControl> m) const
322 Glib::Threads::RWLock::ReaderLock lm (master_lock);
323 return _masters.find (m->id()) != _masters.end();
327 SlavableAutomationControl::slaved () const
329 Glib::Threads::RWLock::ReaderLock lm (master_lock);
330 return !_masters.empty();
333 #endif /* __libardour_slavable_automation_control_h__ */