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/audioengine.h"
27 #include "ardour/slavable_automation_control.h"
28 #include "ardour/session.h"
31 using namespace ARDOUR;
34 SlavableAutomationControl::SlavableAutomationControl(ARDOUR::Session& s,
35 const Evoral::Parameter& parameter,
36 const ParameterDescriptor& desc,
37 boost::shared_ptr<ARDOUR::AutomationList> l,
38 const std::string& name,
39 Controllable::Flag flags)
40 : AutomationControl (s, parameter, desc, l, name, flags)
45 SlavableAutomationControl::~SlavableAutomationControl ()
54 SlavableAutomationControl::get_masters_value_locked () const
58 for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
59 if (mr->second.master()->get_value()) {
66 double v = 1.0; /* the masters function as a scaling factor */
68 for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
69 v *= mr->second.master()->get_value ();
77 SlavableAutomationControl::get_value_locked() const
79 /* read or write masters lock must be held */
81 if (_masters.empty()) {
82 return Control::get_double (false, _session.transport_frame());
86 /* for boolean/toggle controls, if this slave OR any master is
87 * enabled, this slave is enabled. So check our own value
88 * first, because if we are enabled, we can return immediately.
90 if (Control::get_double (false, _session.transport_frame())) {
95 return Control::get_double() * get_masters_value_locked ();
99 SlavableAutomationControl::actually_set_value (double value, PBD::Controllable::GroupControlDisposition gcd)
102 Glib::Threads::RWLock::WriterLock lm (master_lock);
104 if (!_masters.empty()) {
105 /* need to scale given value by current master's scaling */
106 const double masters_value = get_masters_value_locked();
107 if (masters_value == 0.0) {
110 value /= masters_value;
115 /* this will call Control::set_double() and emit Changed signals as appropriate */
116 AutomationControl::actually_set_value (value, gcd);
119 /** Get the current effective `user' value based on automation state */
121 SlavableAutomationControl::get_value() const
123 bool from_list = _list && boost::dynamic_pointer_cast<AutomationList>(_list)->automation_playback();
125 Glib::Threads::RWLock::ReaderLock lm (master_lock);
127 return get_value_locked ();
129 return Control::get_double (true, _session.transport_frame()) * get_masters_value_locked();
134 SlavableAutomationControl::add_master (boost::shared_ptr<AutomationControl> m, bool loading)
136 std::pair<Masters::iterator,bool> res;
139 Glib::Threads::RWLock::WriterLock lm (master_lock);
141 pair<PBD::ID,MasterRecord> newpair (m->id(), MasterRecord (m, 1.0));
142 res = _masters.insert (newpair);
148 if (!_desc.toggled) {
149 const double master_value = m->get_value();
151 if (master_value == 0.0) {
152 AutomationControl::set_double (0.0, Controllable::NoGroup);
154 /* scale control's own value by
155 amount that the master will
158 AutomationControl::set_double ((Control::get_double() / master_value), Controllable::NoGroup);
163 /* note that we bind @param m as a weak_ptr<AutomationControl>, thus
164 avoiding holding a reference to the control in the binding
168 m->DropReferences.connect_same_thread (masters_connections, boost::bind (&SlavableAutomationControl::master_going_away, this, boost::weak_ptr<AutomationControl>(m)));
170 /* Store the connection inside the MasterRecord, so
171 that when we destroy it, the connection is destroyed
172 and we no longer hear about changes to the
175 Note that this also makes it safe to store a
176 boost::shared_ptr<AutomationControl> in the functor,
177 since we know we will destroy the functor when the
178 connection is destroyed, which happens when we
179 disconnect from the master (for any reason).
181 Note that we fix the "from_self" argument that will
182 be given to our own Changed signal to "false",
183 because the change came from the master.
186 m->Changed.connect_same_thread (res.first->second.connection, boost::bind (&SlavableAutomationControl::master_changed, this, _1, _2, m));
191 /* this will notify everyone that we're now slaved to the master */
192 MasterStatusChange (); /* EMIT SIGNAL */
197 update_boolean_masters_records (m);
201 SlavableAutomationControl::get_boolean_masters () const
206 Glib::Threads::RWLock::ReaderLock lm (master_lock);
207 for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
208 if (mr->second.yn()) {
218 SlavableAutomationControl::update_boolean_masters_records (boost::shared_ptr<AutomationControl> m)
221 /* We may modify a MasterRecord, but we not modify the master
222 * map, so we use a ReaderLock
224 Glib::Threads::RWLock::ReaderLock lm (master_lock);
225 Masters::iterator mi = _masters.find (m->id());
226 if (mi != _masters.end()) {
227 /* update MasterRecord to show whether the master is
228 on/off. We need to store this because the master
229 may change (in the sense of emitting Changed())
230 several times without actually changing the result
231 of ::get_value(). This is a feature of
232 AutomationControls (or even just Controllables,
233 really) which have more than a simple scalar
234 value. For example, the master may be a mute control
235 which can be muted_by_self() and/or
236 muted_by_masters(). When either of those two
237 conditions changes, Changed() will be emitted, even
238 though ::get_value() will return the same value each
239 time (1.0 if either are true, 0.0 if neither is).
241 This provides a way for derived types to check
242 the last known state of a Master when the Master
243 changes. We update it after calling
244 ::master_changed() (though derived types must do
247 mi->second.set_yn (m->get_value());
253 SlavableAutomationControl::master_changed (bool /*from_self*/, GroupControlDisposition gcd, boost::shared_ptr<AutomationControl> m)
255 update_boolean_masters_records (m);
256 Changed (false, Controllable::NoGroup); /* EMIT SIGNAL */
260 SlavableAutomationControl::master_going_away (boost::weak_ptr<AutomationControl> wm)
262 boost::shared_ptr<AutomationControl> m = wm.lock();
269 SlavableAutomationControl::remove_master (boost::shared_ptr<AutomationControl> m)
271 pre_remove_master (m);
274 Glib::Threads::RWLock::WriterLock lm (master_lock);
276 if (!_masters.erase (m->id())) {
280 if (!_session.deletion_in_progress()) {
282 const double master_value = m->get_value ();
284 if (master_value == 0.0) {
285 /* slave would have been set to 0.0 as well,
286 so just leave it there, and the user can
287 bring it back up. this fits with the
288 "removing a VCA does not change the level" rule.
291 /* bump up the control's own value by the level
292 of the master that is being removed.
294 AutomationControl::set_double (AutomationControl::get_double() * master_value, Controllable::NoGroup);
299 if (_session.deletion_in_progress()) {
300 /* no reason to care about new values or sending signals */
304 MasterStatusChange (); /* EMIT SIGNAL */
306 /* no need to update boolean masters records, since the MR will have
307 * been removed already.
312 SlavableAutomationControl::clear_masters ()
314 double current_value;
316 bool had_masters = false;
318 /* null ptr means "all masters */
319 pre_remove_master (boost::shared_ptr<AutomationControl>());
322 Glib::Threads::RWLock::WriterLock lm (master_lock);
323 current_value = get_value_locked ();
324 if (!_masters.empty()) {
328 new_value = get_value_locked ();
332 MasterStatusChange (); /* EMIT SIGNAL */
335 if (new_value != current_value) {
336 actually_set_value (current_value, Controllable::UseGroup);
339 /* no need to update boolean masters records, since all MRs will have
340 * been removed already.
345 SlavableAutomationControl::slaved_to (boost::shared_ptr<AutomationControl> m) const
347 Glib::Threads::RWLock::ReaderLock lm (master_lock);
348 return _masters.find (m->id()) != _masters.end();
352 SlavableAutomationControl::slaved () const
354 Glib::Threads::RWLock::ReaderLock lm (master_lock);
355 return !_masters.empty();
359 SlavableAutomationControl::use_saved_master_ratios ()
361 if (!_masters_node) {
365 Glib::Threads::RWLock::ReaderLock lm (master_lock);
367 /* use stored state, do not recompute */
371 XMLNodeList nlist = _masters_node->children();
372 XMLNodeIterator niter;
374 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
375 XMLProperty const * id_prop = (*niter)->property (X_("id"));
379 XMLProperty const * yn_prop = (*niter)->property (X_("yn"));
383 Masters::iterator mi = _masters.find (ID (id_prop->value()));
384 if (mi != _masters.end()) {
385 mi->second.set_yn (string_is_affirmative (yn_prop->value()));
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);
425 node.add_child_nocopy (*masters_node);
433 SlavableAutomationControl::set_state (XMLNode const& node, int version)
435 XMLNodeList nlist = node.children();
436 XMLNodeIterator niter;
438 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
439 if ((*niter)->name() == X_("masters")) {
440 _masters_node = new XMLNode (**niter);
444 return AutomationControl::set_state (node, version);
448 #endif /* __libardour_slavable_automation_control_h__ */