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);
117 _session.set_dirty ();
121 SlavableAutomationControl::add_master (boost::shared_ptr<AutomationControl> m)
123 std::pair<Masters::iterator,bool> res;
126 Glib::Threads::RWLock::WriterLock lm (master_lock);
127 const double current_value = get_value_locked ();
129 /* ratio will be recomputed below */
131 pair<PBD::ID,MasterRecord> newpair (m->id(), MasterRecord (m, 1.0));
132 res = _masters.insert (newpair);
136 recompute_masters_ratios (current_value);
138 /* note that we bind @param m as a weak_ptr<AutomationControl>, thus
139 avoiding holding a reference to the control in the binding
143 m->DropReferences.connect_same_thread (masters_connections, boost::bind (&SlavableAutomationControl::master_going_away, this, boost::weak_ptr<AutomationControl>(m)));
145 /* Store the connection inside the MasterRecord, so
146 that when we destroy it, the connection is destroyed
147 and we no longer hear about changes to the
150 Note that this also makes it safe to store a
151 boost::shared_ptr<AutomationControl> in the functor,
152 since we know we will destroy the functor when the
153 connection is destroyed, which happens when we
154 disconnect from the master (for any reason).
156 Note that we fix the "from_self" argument that will
157 be given to our own Changed signal to "false",
158 because the change came from the master.
161 m->Changed.connect_same_thread (res.first->second.connection, boost::bind (&SlavableAutomationControl::master_changed, this, _1, _2, m));
162 cerr << this << enum_2_string ((AutomationType) _parameter.type()) << " now listening to Changed from " << m << endl;
167 /* this will notify everyone that we're now slaved to the master */
168 MasterStatusChange (); /* EMIT SIGNAL */
173 update_boolean_masters_records (m);
177 SlavableAutomationControl::get_boolean_masters () const
182 Glib::Threads::RWLock::ReaderLock lm (master_lock);
183 for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
184 if (mr->second.yn()) {
194 SlavableAutomationControl::update_boolean_masters_records (boost::shared_ptr<AutomationControl> m)
197 /* We may modify a MasterRecord, but we not modify the master
198 * map, so we use a ReaderLock
200 Glib::Threads::RWLock::ReaderLock lm (master_lock);
201 Masters::iterator mi = _masters.find (m->id());
202 if (mi != _masters.end()) {
203 /* update MasterRecord to show whether the master is
204 on/off. We need to store this because the master
205 may change (in the sense of emitting Changed())
206 several times without actually changing the result
207 of ::get_value(). This is a feature of
208 AutomationControls (or even just Controllables,
209 really) which have more than a simple scalar
210 value. For example, the master may be a mute control
211 which can be muted_by_self() and/or
212 muted_by_masters(). When either of those two
213 conditions changes, Changed() will be emitted, even
214 though ::get_value() will return the same value each
215 time (1.0 if either are true, 0.0 if neither is).
217 This provides a way for derived types to check
218 the last known state of a Master when the Master
219 changes. We update it after calling
220 ::master_changed() (though derived types must do
223 mi->second.set_yn (m->get_value());
229 SlavableAutomationControl::master_changed (bool /*from_self*/, GroupControlDisposition gcd, boost::shared_ptr<AutomationControl> m)
231 update_boolean_masters_records (m);
232 Changed (false, Controllable::NoGroup); /* EMIT SIGNAL */
236 SlavableAutomationControl::master_going_away (boost::weak_ptr<AutomationControl> wm)
238 boost::shared_ptr<AutomationControl> m = wm.lock();
245 SlavableAutomationControl::remove_master (boost::shared_ptr<AutomationControl> m)
247 double current_value;
250 Masters::size_type erased = 0;
252 pre_remove_master (m);
255 Glib::Threads::RWLock::WriterLock lm (master_lock);
256 current_value = get_value_locked ();
257 erased = _masters.erase (m->id());
258 if (erased && !_session.deletion_in_progress()) {
259 recompute_masters_ratios (current_value);
261 masters_left = _masters.size ();
262 new_value = get_value_locked ();
265 if (_session.deletion_in_progress()) {
266 /* no reason to care about new values or sending signals */
271 MasterStatusChange (); /* EMIT SIGNAL */
274 if (new_value != current_value) {
275 if (masters_left == 0) {
276 /* no masters left, make sure we keep the same value
279 actually_set_value (current_value, Controllable::UseGroup);
283 /* no need to update boolean masters records, since the MR will have
284 * been removed already.
289 SlavableAutomationControl::clear_masters ()
291 double current_value;
293 bool had_masters = false;
295 /* null ptr means "all masters */
296 pre_remove_master (boost::shared_ptr<AutomationControl>());
299 Glib::Threads::RWLock::WriterLock lm (master_lock);
300 current_value = get_value_locked ();
301 if (!_masters.empty()) {
305 new_value = get_value_locked ();
309 MasterStatusChange (); /* EMIT SIGNAL */
312 if (new_value != current_value) {
313 actually_set_value (current_value, Controllable::UseGroup);
316 /* no need to update boolean masters records, since all MRs will have
317 * been removed already.
322 SlavableAutomationControl::slaved_to (boost::shared_ptr<AutomationControl> m) const
324 Glib::Threads::RWLock::ReaderLock lm (master_lock);
325 return _masters.find (m->id()) != _masters.end();
329 SlavableAutomationControl::slaved () const
331 Glib::Threads::RWLock::ReaderLock lm (master_lock);
332 return !_masters.empty();
335 #endif /* __libardour_slavable_automation_control_h__ */