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 : AutomationControl (s, parameter, desc, l, name)
41 SlavableAutomationControl::get_masters_value_locked () const
43 double v = _desc.normal;
46 for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
47 if (mr->second.master()->get_value()) {
54 for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
55 /* get current master value, scale by our current ratio with that master */
56 v *= mr->second.master()->get_value () * mr->second.ratio();
59 return min ((double) _desc.upper, v);
63 SlavableAutomationControl::get_value_locked() const
65 /* read or write masters lock must be held */
67 if (_masters.empty()) {
68 return Control::get_double (false, _session.transport_frame());
72 /* for boolean/toggle controls, if this slave OR any master is
73 * enabled, this slave is enabled. So check our own value
74 * first, because if we are enabled, we can return immediately.
76 if (Control::get_double (false, _session.transport_frame())) {
81 return get_masters_value_locked ();
84 /** Get the current effective `user' value based on automation state */
86 SlavableAutomationControl::get_value() const
88 bool from_list = _list && boost::dynamic_pointer_cast<AutomationList>(_list)->automation_playback();
91 Glib::Threads::RWLock::ReaderLock lm (master_lock);
92 return get_value_locked ();
94 return Control::get_double (from_list, _session.transport_frame());
99 SlavableAutomationControl::actually_set_value (double val, Controllable::GroupControlDisposition group_override)
101 val = std::max (std::min (val, (double)_desc.upper), (double)_desc.lower);
104 Glib::Threads::RWLock::WriterLock lm (master_lock);
106 if (!_masters.empty()) {
107 recompute_masters_ratios (val);
111 /* this sets the Evoral::Control::_user_value for us, which will
112 be retrieved by AutomationControl::get_value ()
114 AutomationControl::actually_set_value (val, group_override);
116 _session.set_dirty ();
120 SlavableAutomationControl::add_master (boost::shared_ptr<AutomationControl> m)
122 std::pair<Masters::iterator,bool> res;
125 Glib::Threads::RWLock::WriterLock lm (master_lock);
126 const double current_value = get_value_locked ();
128 /* ratio will be recomputed below */
130 pair<PBD::ID,MasterRecord> newpair (m->id(), MasterRecord (m, 1.0));
131 res = _masters.insert (newpair);
135 recompute_masters_ratios (current_value);
137 /* note that we bind @param m as a weak_ptr<AutomationControl>, thus
138 avoiding holding a reference to the control in the binding
142 m->DropReferences.connect_same_thread (masters_connections, boost::bind (&SlavableAutomationControl::master_going_away, this, boost::weak_ptr<AutomationControl>(m)));
144 /* Store the connection inside the MasterRecord, so
145 that when we destroy it, the connection is destroyed
146 and we no longer hear about changes to the
149 Note that this also makes it safe to store a
150 boost::shared_ptr<AutomationControl> in the functor,
151 since we know we will destroy the functor when the
152 connection is destroyed, which happens when we
153 disconnect from the master (for any reason).
155 Note that we fix the "from_self" argument that will
156 be given to our own Changed signal to "false",
157 because the change came from the master.
160 m->Changed.connect_same_thread (res.first->second.connection, boost::bind (&SlavableAutomationControl::master_changed, this, _1, _2, m));
161 cerr << this << enum_2_string ((AutomationType) _parameter.type()) << " now listening to Changed from " << m << endl;
166 /* this will notify everyone that we're now slaved to the master */
167 MasterStatusChange (); /* EMIT SIGNAL */
172 update_boolean_masters_records (m);
176 SlavableAutomationControl::get_boolean_masters () const
181 Glib::Threads::RWLock::ReaderLock lm (master_lock);
182 for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
183 if (mr->second.yn()) {
193 SlavableAutomationControl::update_boolean_masters_records (boost::shared_ptr<AutomationControl> m)
196 /* We may modify a MasterRecord, but we not modify the master
197 * map, so we use a ReaderLock
199 Glib::Threads::RWLock::ReaderLock lm (master_lock);
200 Masters::iterator mi = _masters.find (m->id());
201 if (mi != _masters.end()) {
202 /* update MasterRecord to show whether the master is
203 on/off. We need to store this because the master
204 may change (in the sense of emitting Changed())
205 several times without actually changing the result
206 of ::get_value(). This is a feature of
207 AutomationControls (or even just Controllables,
208 really) which have more than a simple scalar
209 value. For example, the master may be a mute control
210 which can be muted_by_self() and/or
211 muted_by_masters(). When either of those two
212 conditions changes, Changed() will be emitted, even
213 though ::get_value() will return the same value each
214 time (1.0 if either are true, 0.0 if neither is).
216 This provides a way for derived types to check
217 the last known state of a Master when the Master
218 changes. We update it after calling
219 ::master_changed() (though derived types must do
222 mi->second.set_yn (m->get_value());
228 SlavableAutomationControl::master_changed (bool /*from_self*/, GroupControlDisposition gcd, boost::shared_ptr<AutomationControl> m)
230 update_boolean_masters_records (m);
231 Changed (false, Controllable::NoGroup); /* EMIT SIGNAL */
235 SlavableAutomationControl::master_going_away (boost::weak_ptr<AutomationControl> wm)
237 boost::shared_ptr<AutomationControl> m = wm.lock();
244 SlavableAutomationControl::remove_master (boost::shared_ptr<AutomationControl> m)
246 double current_value;
249 Masters::size_type erased = 0;
251 pre_remove_master (m);
254 Glib::Threads::RWLock::WriterLock lm (master_lock);
255 current_value = get_value_locked ();
256 erased = _masters.erase (m->id());
257 if (erased && !_session.deletion_in_progress()) {
258 recompute_masters_ratios (current_value);
260 masters_left = _masters.size ();
261 new_value = get_value_locked ();
264 if (_session.deletion_in_progress()) {
265 /* no reason to care about new values or sending signals */
270 MasterStatusChange (); /* EMIT SIGNAL */
273 if (new_value != current_value) {
274 if (masters_left == 0) {
275 /* no masters left, make sure we keep the same value
278 actually_set_value (current_value, Controllable::UseGroup);
282 /* no need to update boolean masters records, since the MR will have
283 * been removed already.
288 SlavableAutomationControl::clear_masters ()
290 double current_value;
292 bool had_masters = false;
294 /* null ptr means "all masters */
295 pre_remove_master (boost::shared_ptr<AutomationControl>());
298 Glib::Threads::RWLock::WriterLock lm (master_lock);
299 current_value = get_value_locked ();
300 if (!_masters.empty()) {
304 new_value = get_value_locked ();
308 MasterStatusChange (); /* EMIT SIGNAL */
311 if (new_value != current_value) {
312 actually_set_value (current_value, Controllable::UseGroup);
315 /* no need to update boolean masters records, since all MRs will have
316 * been removed already.
321 SlavableAutomationControl::slaved_to (boost::shared_ptr<AutomationControl> m) const
323 Glib::Threads::RWLock::ReaderLock lm (master_lock);
324 return _masters.find (m->id()) != _masters.end();
328 SlavableAutomationControl::slaved () const
330 Glib::Threads::RWLock::ReaderLock lm (master_lock);
331 return !_masters.empty();
334 #endif /* __libardour_slavable_automation_control_h__ */