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;
111 value = std::max (lower(), std::min(upper(), value));
116 /* this will call Control::set_double() and emit Changed signals as appropriate */
117 AutomationControl::actually_set_value (value, gcd);
120 /** Get the current effective `user' value based on automation state */
122 SlavableAutomationControl::get_value() const
124 bool from_list = _list && boost::dynamic_pointer_cast<AutomationList>(_list)->automation_playback();
126 Glib::Threads::RWLock::ReaderLock lm (master_lock);
128 return get_value_locked ();
130 return Control::get_double (true, _session.transport_frame()) * get_masters_value_locked();
135 SlavableAutomationControl::add_master (boost::shared_ptr<AutomationControl> m, bool loading)
137 std::pair<Masters::iterator,bool> res;
140 Glib::Threads::RWLock::WriterLock lm (master_lock);
142 pair<PBD::ID,MasterRecord> newpair (m->id(), MasterRecord (m, 1.0));
143 res = _masters.insert (newpair);
149 if (!_desc.toggled) {
150 const double master_value = m->get_value();
152 if (master_value == 0.0) {
153 AutomationControl::set_double (0.0, Controllable::NoGroup);
155 /* scale control's own value by
156 amount that the master will
159 AutomationControl::set_double ((Control::get_double() / master_value), Controllable::NoGroup);
164 /* note that we bind @param m as a weak_ptr<AutomationControl>, thus
165 avoiding holding a reference to the control in the binding
169 m->DropReferences.connect_same_thread (masters_connections, boost::bind (&SlavableAutomationControl::master_going_away, this, boost::weak_ptr<AutomationControl>(m)));
171 /* Store the connection inside the MasterRecord, so
172 that when we destroy it, the connection is destroyed
173 and we no longer hear about changes to the
176 Note that this also makes it safe to store a
177 boost::shared_ptr<AutomationControl> in the functor,
178 since we know we will destroy the functor when the
179 connection is destroyed, which happens when we
180 disconnect from the master (for any reason).
182 Note that we fix the "from_self" argument that will
183 be given to our own Changed signal to "false",
184 because the change came from the master.
187 m->Changed.connect_same_thread (res.first->second.connection, boost::bind (&SlavableAutomationControl::master_changed, this, _1, _2, m));
192 /* this will notify everyone that we're now slaved to the master */
193 MasterStatusChange (); /* EMIT SIGNAL */
198 update_boolean_masters_records (m);
202 SlavableAutomationControl::get_boolean_masters () const
207 Glib::Threads::RWLock::ReaderLock lm (master_lock);
208 for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
209 if (mr->second.yn()) {
219 SlavableAutomationControl::update_boolean_masters_records (boost::shared_ptr<AutomationControl> m)
222 /* We may modify a MasterRecord, but we not modify the master
223 * map, so we use a ReaderLock
225 Glib::Threads::RWLock::ReaderLock lm (master_lock);
226 Masters::iterator mi = _masters.find (m->id());
227 if (mi != _masters.end()) {
228 /* update MasterRecord to show whether the master is
229 on/off. We need to store this because the master
230 may change (in the sense of emitting Changed())
231 several times without actually changing the result
232 of ::get_value(). This is a feature of
233 AutomationControls (or even just Controllables,
234 really) which have more than a simple scalar
235 value. For example, the master may be a mute control
236 which can be muted_by_self() and/or
237 muted_by_masters(). When either of those two
238 conditions changes, Changed() will be emitted, even
239 though ::get_value() will return the same value each
240 time (1.0 if either are true, 0.0 if neither is).
242 This provides a way for derived types to check
243 the last known state of a Master when the Master
244 changes. We update it after calling
245 ::master_changed() (though derived types must do
248 mi->second.set_yn (m->get_value());
254 SlavableAutomationControl::master_changed (bool /*from_self*/, GroupControlDisposition gcd, boost::shared_ptr<AutomationControl> m)
256 update_boolean_masters_records (m);
257 Changed (false, Controllable::NoGroup); /* EMIT SIGNAL */
261 SlavableAutomationControl::master_going_away (boost::weak_ptr<AutomationControl> wm)
263 boost::shared_ptr<AutomationControl> m = wm.lock();
270 SlavableAutomationControl::remove_master (boost::shared_ptr<AutomationControl> m)
272 pre_remove_master (m);
275 Glib::Threads::RWLock::WriterLock lm (master_lock);
277 if (!_masters.erase (m->id())) {
281 if (!_session.deletion_in_progress()) {
283 const double master_value = m->get_value ();
285 if (master_value == 0.0) {
286 /* slave would have been set to 0.0 as well,
287 so just leave it there, and the user can
288 bring it back up. this fits with the
289 "removing a VCA does not change the level" rule.
292 /* bump up the control's own value by the level
293 of the master that is being removed.
295 AutomationControl::set_double (AutomationControl::get_double() * master_value, Controllable::NoGroup);
300 if (_session.deletion_in_progress()) {
301 /* no reason to care about new values or sending signals */
305 MasterStatusChange (); /* EMIT SIGNAL */
307 /* no need to update boolean masters records, since the MR will have
308 * been removed already.
313 SlavableAutomationControl::clear_masters ()
315 double current_value;
317 bool had_masters = false;
319 /* null ptr means "all masters */
320 pre_remove_master (boost::shared_ptr<AutomationControl>());
323 Glib::Threads::RWLock::WriterLock lm (master_lock);
324 current_value = get_value_locked ();
325 if (!_masters.empty()) {
329 new_value = get_value_locked ();
333 MasterStatusChange (); /* EMIT SIGNAL */
336 if (new_value != current_value) {
337 actually_set_value (current_value, Controllable::UseGroup);
340 /* no need to update boolean masters records, since all MRs will have
341 * been removed already.
346 SlavableAutomationControl::slaved_to (boost::shared_ptr<AutomationControl> m) const
348 Glib::Threads::RWLock::ReaderLock lm (master_lock);
349 return _masters.find (m->id()) != _masters.end();
353 SlavableAutomationControl::slaved () const
355 Glib::Threads::RWLock::ReaderLock lm (master_lock);
356 return !_masters.empty();
360 SlavableAutomationControl::use_saved_master_ratios ()
362 if (!_masters_node) {
366 Glib::Threads::RWLock::ReaderLock lm (master_lock);
368 /* use stored state, do not recompute */
372 XMLNodeList nlist = _masters_node->children();
373 XMLNodeIterator niter;
375 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
376 XMLProperty const * id_prop = (*niter)->property (X_("id"));
380 XMLProperty const * yn_prop = (*niter)->property (X_("yn"));
384 Masters::iterator mi = _masters.find (ID (id_prop->value()));
385 if (mi != _masters.end()) {
386 mi->second.set_yn (string_is_affirmative (yn_prop->value()));
394 delete _masters_node;
402 SlavableAutomationControl::get_state ()
404 XMLNode& node (AutomationControl::get_state());
406 /* store VCA master ratios */
409 Glib::Threads::RWLock::ReaderLock lm (master_lock);
411 if (!_masters.empty()) {
413 XMLNode* masters_node = new XMLNode (X_("masters"));
416 for (Masters::iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
417 XMLNode* mnode = new XMLNode (X_("master"));
418 mnode->add_property (X_("id"), mr->second.master()->id().to_s());
419 mnode->add_property (X_("yn"), mr->second.yn());
420 masters_node->add_child_nocopy (*mnode);
426 node.add_child_nocopy (*masters_node);
434 SlavableAutomationControl::set_state (XMLNode const& node, int version)
436 XMLNodeList nlist = node.children();
437 XMLNodeIterator niter;
439 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
440 if ((*niter)->name() == X_("masters")) {
441 _masters_node = new XMLNode (**niter);
445 return AutomationControl::set_state (node, version);
449 #endif /* __libardour_slavable_automation_control_h__ */