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"
23 #include "pbd/error.h"
26 #include "ardour/slavable_automation_control.h"
27 #include "ardour/session.h"
30 using namespace ARDOUR;
33 SlavableAutomationControl::SlavableAutomationControl(ARDOUR::Session& s,
34 const Evoral::Parameter& parameter,
35 const ParameterDescriptor& desc,
36 boost::shared_ptr<ARDOUR::AutomationList> l,
37 const std::string& name,
38 Controllable::Flag flags)
39 : AutomationControl (s, parameter, desc, l, name, flags)
44 SlavableAutomationControl::~SlavableAutomationControl ()
53 SlavableAutomationControl::get_masters_value_locked () const
55 double v = _desc.normal;
58 for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
59 if (mr->second.master()->get_value()) {
66 for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
67 /* get current master value, scale by our current ratio with that master */
68 v *= mr->second.master()->get_value () * mr->second.ratio();
71 return min ((double) _desc.upper, v);
75 SlavableAutomationControl::get_value_locked() const
77 /* read or write masters lock must be held */
79 if (_masters.empty()) {
80 return Control::get_double (false, _session.transport_frame());
84 /* for boolean/toggle controls, if this slave OR any master is
85 * enabled, this slave is enabled. So check our own value
86 * first, because if we are enabled, we can return immediately.
88 if (Control::get_double (false, _session.transport_frame())) {
93 return get_masters_value_locked ();
96 /** Get the current effective `user' value based on automation state */
98 SlavableAutomationControl::get_value() const
100 bool from_list = _list && boost::dynamic_pointer_cast<AutomationList>(_list)->automation_playback();
102 Glib::Threads::RWLock::ReaderLock lm (master_lock);
104 return get_value_locked ();
106 return get_masters_value_locked () * Control::get_double (from_list, _session.transport_frame());
111 SlavableAutomationControl::actually_set_value (double val, Controllable::GroupControlDisposition group_override)
113 val = std::max (std::min (val, (double)_desc.upper), (double)_desc.lower);
116 Glib::Threads::RWLock::WriterLock lm (master_lock);
118 if (!_masters.empty()) {
119 recompute_masters_ratios (val);
123 /* this sets the Evoral::Control::_user_value for us, which will
124 be retrieved by AutomationControl::get_value ()
126 AutomationControl::actually_set_value (val, group_override);
130 SlavableAutomationControl::add_master (boost::shared_ptr<AutomationControl> m, bool loading)
132 std::pair<Masters::iterator,bool> res;
135 Glib::Threads::RWLock::WriterLock lm (master_lock);
136 const double current_value = get_value_locked ();
138 /* ratio will be recomputed below */
140 pair<PBD::ID,MasterRecord> newpair (m->id(), MasterRecord (m, 1.0));
141 res = _masters.insert (newpair);
146 recompute_masters_ratios (current_value);
149 /* note that we bind @param m as a weak_ptr<AutomationControl>, thus
150 avoiding holding a reference to the control in the binding
154 m->DropReferences.connect_same_thread (masters_connections, boost::bind (&SlavableAutomationControl::master_going_away, this, boost::weak_ptr<AutomationControl>(m)));
156 /* Store the connection inside the MasterRecord, so
157 that when we destroy it, the connection is destroyed
158 and we no longer hear about changes to the
161 Note that this also makes it safe to store a
162 boost::shared_ptr<AutomationControl> in the functor,
163 since we know we will destroy the functor when the
164 connection is destroyed, which happens when we
165 disconnect from the master (for any reason).
167 Note that we fix the "from_self" argument that will
168 be given to our own Changed signal to "false",
169 because the change came from the master.
172 m->Changed.connect_same_thread (res.first->second.connection, boost::bind (&SlavableAutomationControl::master_changed, this, _1, _2, m));
177 /* this will notify everyone that we're now slaved to the master */
178 MasterStatusChange (); /* EMIT SIGNAL */
183 update_boolean_masters_records (m);
187 SlavableAutomationControl::get_boolean_masters () const
192 Glib::Threads::RWLock::ReaderLock lm (master_lock);
193 for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
194 if (mr->second.yn()) {
204 SlavableAutomationControl::update_boolean_masters_records (boost::shared_ptr<AutomationControl> m)
207 /* We may modify a MasterRecord, but we not modify the master
208 * map, so we use a ReaderLock
210 Glib::Threads::RWLock::ReaderLock lm (master_lock);
211 Masters::iterator mi = _masters.find (m->id());
212 if (mi != _masters.end()) {
213 /* update MasterRecord to show whether the master is
214 on/off. We need to store this because the master
215 may change (in the sense of emitting Changed())
216 several times without actually changing the result
217 of ::get_value(). This is a feature of
218 AutomationControls (or even just Controllables,
219 really) which have more than a simple scalar
220 value. For example, the master may be a mute control
221 which can be muted_by_self() and/or
222 muted_by_masters(). When either of those two
223 conditions changes, Changed() will be emitted, even
224 though ::get_value() will return the same value each
225 time (1.0 if either are true, 0.0 if neither is).
227 This provides a way for derived types to check
228 the last known state of a Master when the Master
229 changes. We update it after calling
230 ::master_changed() (though derived types must do
233 mi->second.set_yn (m->get_value());
239 SlavableAutomationControl::master_changed (bool /*from_self*/, GroupControlDisposition gcd, boost::shared_ptr<AutomationControl> m)
241 update_boolean_masters_records (m);
242 Changed (false, Controllable::NoGroup); /* EMIT SIGNAL */
246 SlavableAutomationControl::master_going_away (boost::weak_ptr<AutomationControl> wm)
248 boost::shared_ptr<AutomationControl> m = wm.lock();
255 SlavableAutomationControl::remove_master (boost::shared_ptr<AutomationControl> m)
257 double current_value;
260 Masters::size_type erased = 0;
262 pre_remove_master (m);
265 Glib::Threads::RWLock::WriterLock lm (master_lock);
266 current_value = get_value_locked ();
267 erased = _masters.erase (m->id());
268 if (erased && !_session.deletion_in_progress()) {
269 recompute_masters_ratios (current_value);
271 masters_left = _masters.size ();
272 new_value = get_value_locked ();
275 if (_session.deletion_in_progress()) {
276 /* no reason to care about new values or sending signals */
281 MasterStatusChange (); /* EMIT SIGNAL */
284 if (new_value != current_value) {
285 if (masters_left == 0) {
286 /* no masters left, make sure we keep the same value
289 actually_set_value (current_value, Controllable::UseGroup);
293 /* no need to update boolean masters records, since the MR will have
294 * been removed already.
299 SlavableAutomationControl::clear_masters ()
301 double current_value;
303 bool had_masters = false;
305 /* null ptr means "all masters */
306 pre_remove_master (boost::shared_ptr<AutomationControl>());
309 Glib::Threads::RWLock::WriterLock lm (master_lock);
310 current_value = get_value_locked ();
311 if (!_masters.empty()) {
315 new_value = get_value_locked ();
319 MasterStatusChange (); /* EMIT SIGNAL */
322 if (new_value != current_value) {
323 actually_set_value (current_value, Controllable::UseGroup);
326 /* no need to update boolean masters records, since all MRs will have
327 * been removed already.
332 SlavableAutomationControl::slaved_to (boost::shared_ptr<AutomationControl> m) const
334 Glib::Threads::RWLock::ReaderLock lm (master_lock);
335 return _masters.find (m->id()) != _masters.end();
339 SlavableAutomationControl::slaved () const
341 Glib::Threads::RWLock::ReaderLock lm (master_lock);
342 return !_masters.empty();
346 SlavableAutomationControl::use_saved_master_ratios ()
348 if (!_masters_node) {
352 Glib::Threads::RWLock::ReaderLock lm (master_lock);
354 /* use stored state, do not recompute */
358 XMLNodeList nlist = _masters_node->children();
359 XMLNodeIterator niter;
361 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
362 XMLProperty const * id_prop = (*niter)->property (X_("id"));
366 XMLProperty const * yn_prop = (*niter)->property (X_("yn"));
370 Masters::iterator mi = _masters.find (ID (id_prop->value()));
371 if (mi != _masters.end()) {
372 mi->second.set_yn (string_is_affirmative (yn_prop->value()));
378 XMLProperty const * prop = _masters_node->property (X_("ratio"));
383 sscanf (prop->value().c_str(), "%g", &ratio);
385 for (Masters::iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
386 mr->second.reset_ratio (ratio);
389 PBD::error << string_compose (_("programming error: %1"), X_("missing ratio information for control slave"))<< endmsg;
393 delete _masters_node;
401 SlavableAutomationControl::get_state ()
403 XMLNode& node (AutomationControl::get_state());
405 /* store VCA master ratios */
408 Glib::Threads::RWLock::ReaderLock lm (master_lock);
410 if (!_masters.empty()) {
412 XMLNode* masters_node = new XMLNode (X_("masters"));
415 for (Masters::iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
416 XMLNode* mnode = new XMLNode (X_("master"));
417 mnode->add_property (X_("id"), mr->second.master()->id().to_s());
418 mnode->add_property (X_("yn"), mr->second.yn());
419 masters_node->add_child_nocopy (*mnode);
422 XMLNode* masters_node = new XMLNode (X_("masters"));
423 /* ratio is the same for all masters, so just store one */
424 masters_node->add_property (X_("ratio"), PBD::to_string (_masters.begin()->second.ratio(), std::dec));
427 node.add_child_nocopy (*masters_node);
435 SlavableAutomationControl::set_state (XMLNode const& node, int version)
437 XMLNodeList nlist = node.children();
438 XMLNodeIterator niter;
440 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
441 if ((*niter)->name() == X_("masters")) {
442 _masters_node = new XMLNode (**niter);
446 return AutomationControl::set_state (node, version);
450 #endif /* __libardour_slavable_automation_control_h__ */