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)
101 if (!_desc.toggled) {
103 Glib::Threads::RWLock::WriterLock lm (master_lock);
105 if (!_masters.empty()) {
106 /* need to scale given value by current master's scaling */
107 const double masters_value = get_masters_value_locked();
108 if (masters_value == 0.0) {
111 value /= masters_value;
112 value = std::max (lower(), std::min(upper(), value));
117 /* this will call Control::set_double() and emit Changed signals as appropriate */
118 AutomationControl::actually_set_value (value, gcd);
121 /** Get the current effective `user' value based on automation state */
123 SlavableAutomationControl::get_value() const
125 bool from_list = _list && boost::dynamic_pointer_cast<AutomationList>(_list)->automation_playback();
127 Glib::Threads::RWLock::ReaderLock lm (master_lock);
129 return get_value_locked ();
131 return Control::get_double (true, _session.transport_frame()) * get_masters_value_locked();
136 SlavableAutomationControl::add_master (boost::shared_ptr<AutomationControl> m, bool loading)
138 std::pair<Masters::iterator,bool> res;
141 Glib::Threads::RWLock::WriterLock lm (master_lock);
143 pair<PBD::ID,MasterRecord> newpair (m->id(), MasterRecord (m, 1.0));
144 res = _masters.insert (newpair);
150 if (!_desc.toggled) {
151 const double master_value = m->get_value();
153 if (master_value == 0.0) {
154 AutomationControl::set_double (0.0, Controllable::NoGroup);
156 /* scale control's own value by
157 amount that the master will
160 AutomationControl::set_double ((Control::get_double() / master_value), Controllable::NoGroup);
165 /* note that we bind @param m as a weak_ptr<AutomationControl>, thus
166 avoiding holding a reference to the control in the binding
170 m->DropReferences.connect_same_thread (masters_connections, boost::bind (&SlavableAutomationControl::master_going_away, this, boost::weak_ptr<AutomationControl>(m)));
172 /* Store the connection inside the MasterRecord, so
173 that when we destroy it, the connection is destroyed
174 and we no longer hear about changes to the
177 Note that this also makes it safe to store a
178 boost::shared_ptr<AutomationControl> in the functor,
179 since we know we will destroy the functor when the
180 connection is destroyed, which happens when we
181 disconnect from the master (for any reason).
183 Note that we fix the "from_self" argument that will
184 be given to our own Changed signal to "false",
185 because the change came from the master.
188 m->Changed.connect_same_thread (res.first->second.connection, boost::bind (&SlavableAutomationControl::master_changed, this, _1, _2, m));
193 /* this will notify everyone that we're now slaved to the master */
194 MasterStatusChange (); /* EMIT SIGNAL */
199 update_boolean_masters_records (m);
203 SlavableAutomationControl::get_boolean_masters () const
208 Glib::Threads::RWLock::ReaderLock lm (master_lock);
209 for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
210 if (mr->second.yn()) {
220 SlavableAutomationControl::update_boolean_masters_records (boost::shared_ptr<AutomationControl> m)
223 /* We may modify a MasterRecord, but we not modify the master
224 * map, so we use a ReaderLock
226 Glib::Threads::RWLock::ReaderLock lm (master_lock);
227 Masters::iterator mi = _masters.find (m->id());
228 if (mi != _masters.end()) {
229 /* update MasterRecord to show whether the master is
230 on/off. We need to store this because the master
231 may change (in the sense of emitting Changed())
232 several times without actually changing the result
233 of ::get_value(). This is a feature of
234 AutomationControls (or even just Controllables,
235 really) which have more than a simple scalar
236 value. For example, the master may be a mute control
237 which can be muted_by_self() and/or
238 muted_by_masters(). When either of those two
239 conditions changes, Changed() will be emitted, even
240 though ::get_value() will return the same value each
241 time (1.0 if either are true, 0.0 if neither is).
243 This provides a way for derived types to check
244 the last known state of a Master when the Master
245 changes. We update it after calling
246 ::master_changed() (though derived types must do
249 mi->second.set_yn (m->get_value());
255 SlavableAutomationControl::master_changed (bool /*from_self*/, GroupControlDisposition gcd, boost::shared_ptr<AutomationControl> m)
257 update_boolean_masters_records (m);
258 Changed (false, Controllable::NoGroup); /* EMIT SIGNAL */
262 SlavableAutomationControl::master_going_away (boost::weak_ptr<AutomationControl> wm)
264 boost::shared_ptr<AutomationControl> m = wm.lock();
271 SlavableAutomationControl::remove_master (boost::shared_ptr<AutomationControl> m)
273 pre_remove_master (m);
276 Glib::Threads::RWLock::WriterLock lm (master_lock);
278 if (!_masters.erase (m->id())) {
282 if (!_session.deletion_in_progress()) {
284 const double master_value = m->get_value ();
286 if (master_value == 0.0) {
287 /* slave would have been set to 0.0 as well,
288 so just leave it there, and the user can
289 bring it back up. this fits with the
290 "removing a VCA does not change the level" rule.
293 /* bump up the control's own value by the level
294 of the master that is being removed.
296 AutomationControl::set_double (AutomationControl::get_double() * master_value, Controllable::NoGroup);
301 if (_session.deletion_in_progress()) {
302 /* no reason to care about new values or sending signals */
306 MasterStatusChange (); /* EMIT SIGNAL */
308 /* no need to update boolean masters records, since the MR will have
309 * been removed already.
314 SlavableAutomationControl::clear_masters ()
316 double current_value;
318 bool had_masters = false;
320 /* null ptr means "all masters */
321 pre_remove_master (boost::shared_ptr<AutomationControl>());
324 Glib::Threads::RWLock::WriterLock lm (master_lock);
325 current_value = get_value_locked ();
326 if (!_masters.empty()) {
330 new_value = get_value_locked ();
334 MasterStatusChange (); /* EMIT SIGNAL */
337 if (new_value != current_value) {
338 actually_set_value (current_value, Controllable::UseGroup);
341 /* no need to update boolean masters records, since all MRs will have
342 * been removed already.
347 SlavableAutomationControl::slaved_to (boost::shared_ptr<AutomationControl> m) const
349 Glib::Threads::RWLock::ReaderLock lm (master_lock);
350 return _masters.find (m->id()) != _masters.end();
354 SlavableAutomationControl::slaved () const
356 Glib::Threads::RWLock::ReaderLock lm (master_lock);
357 return !_masters.empty();
361 SlavableAutomationControl::use_saved_master_ratios ()
363 if (!_masters_node) {
367 Glib::Threads::RWLock::ReaderLock lm (master_lock);
369 /* use stored state, do not recompute */
373 XMLNodeList nlist = _masters_node->children();
374 XMLNodeIterator niter;
376 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
377 XMLProperty const * id_prop = (*niter)->property (X_("id"));
381 XMLProperty const * yn_prop = (*niter)->property (X_("yn"));
385 Masters::iterator mi = _masters.find (ID (id_prop->value()));
386 if (mi != _masters.end()) {
387 mi->second.set_yn (string_is_affirmative (yn_prop->value()));
395 delete _masters_node;
403 SlavableAutomationControl::get_state ()
405 XMLNode& node (AutomationControl::get_state());
407 /* store VCA master ratios */
410 Glib::Threads::RWLock::ReaderLock lm (master_lock);
412 if (!_masters.empty()) {
414 XMLNode* masters_node = new XMLNode (X_("masters"));
417 for (Masters::iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
418 XMLNode* mnode = new XMLNode (X_("master"));
419 mnode->add_property (X_("id"), mr->second.master()->id().to_s());
420 mnode->add_property (X_("yn"), mr->second.yn());
421 masters_node->add_child_nocopy (*mnode);
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__ */