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"
24 #include "pbd/types_convert.h"
27 #include "ardour/audioengine.h"
28 #include "ardour/slavable_automation_control.h"
29 #include "ardour/session.h"
32 using namespace ARDOUR;
35 SlavableAutomationControl::SlavableAutomationControl(ARDOUR::Session& s,
36 const Evoral::Parameter& parameter,
37 const ParameterDescriptor& desc,
38 boost::shared_ptr<ARDOUR::AutomationList> l,
39 const std::string& name,
40 Controllable::Flag flags)
41 : AutomationControl (s, parameter, desc, l, name, flags)
46 SlavableAutomationControl::~SlavableAutomationControl ()
55 SlavableAutomationControl::get_masters_value_locked () const
59 for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
60 if (mr->second.master()->get_value()) {
67 double v = 1.0; /* the masters function as a scaling factor */
69 for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
70 v *= mr->second.master()->get_value ();
78 SlavableAutomationControl::get_value_locked() const
80 /* read or write masters lock must be held */
82 if (_masters.empty()) {
83 return Control::get_double (false, _session.transport_frame());
87 /* for boolean/toggle controls, if this slave OR any master is
88 * enabled, this slave is enabled. So check our own value
89 * first, because if we are enabled, we can return immediately.
91 if (Control::get_double (false, _session.transport_frame())) {
96 return Control::get_double() * get_masters_value_locked ();
99 /** Get the current effective `user' value based on automation state */
101 SlavableAutomationControl::get_value() const
103 bool from_list = _list && boost::dynamic_pointer_cast<AutomationList>(_list)->automation_playback();
105 Glib::Threads::RWLock::ReaderLock lm (master_lock);
107 return get_value_locked ();
109 return Control::get_double (true, _session.transport_frame()) * get_masters_value_locked();
114 SlavableAutomationControl::actually_set_value (double value, PBD::Controllable::GroupControlDisposition gcd)
116 if (!_desc.toggled) {
118 Glib::Threads::RWLock::WriterLock lm (master_lock);
120 if (!_masters.empty()) {
121 /* need to scale given value by current master's scaling */
122 const double masters_value = get_masters_value_locked();
123 if (masters_value == 0.0) {
126 value /= masters_value;
127 value = std::max (lower(), std::min(upper(), value));
132 /* this will call Control::set_double() and emit Changed signals as appropriate */
133 AutomationControl::actually_set_value (value, gcd);
137 SlavableAutomationControl::add_master (boost::shared_ptr<AutomationControl> m, bool loading)
139 std::pair<Masters::iterator,bool> res;
142 Glib::Threads::RWLock::WriterLock lm (master_lock);
144 pair<PBD::ID,MasterRecord> newpair (m->id(), MasterRecord (m, 1.0));
145 res = _masters.insert (newpair);
151 if (!_desc.toggled) {
152 const double master_value = m->get_value();
154 if (master_value == 0.0) {
155 AutomationControl::set_double (0.0, Controllable::NoGroup);
157 /* scale control's own value by
158 amount that the master will
161 AutomationControl::set_double ((Control::get_double() / master_value), Controllable::NoGroup);
166 /* note that we bind @param m as a weak_ptr<AutomationControl>, thus
167 avoiding holding a reference to the control in the binding
171 m->DropReferences.connect_same_thread (masters_connections, boost::bind (&SlavableAutomationControl::master_going_away, this, boost::weak_ptr<AutomationControl>(m)));
173 /* Store the connection inside the MasterRecord, so
174 that when we destroy it, the connection is destroyed
175 and we no longer hear about changes to the
178 Note that this also makes it safe to store a
179 boost::shared_ptr<AutomationControl> in the functor,
180 since we know we will destroy the functor when the
181 connection is destroyed, which happens when we
182 disconnect from the master (for any reason).
184 Note that we fix the "from_self" argument that will
185 be given to our own Changed signal to "false",
186 because the change came from the master.
189 m->Changed.connect_same_thread (res.first->second.connection, boost::bind (&SlavableAutomationControl::master_changed, this, _1, _2, m));
194 /* this will notify everyone that we're now slaved to the master */
195 MasterStatusChange (); /* EMIT SIGNAL */
200 update_boolean_masters_records (m);
204 SlavableAutomationControl::get_boolean_masters () const
209 Glib::Threads::RWLock::ReaderLock lm (master_lock);
210 for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
211 if (mr->second.yn()) {
221 SlavableAutomationControl::update_boolean_masters_records (boost::shared_ptr<AutomationControl> m)
224 /* We may modify a MasterRecord, but we not modify the master
225 * map, so we use a ReaderLock
227 Glib::Threads::RWLock::ReaderLock lm (master_lock);
228 Masters::iterator mi = _masters.find (m->id());
229 if (mi != _masters.end()) {
230 /* update MasterRecord to show whether the master is
231 on/off. We need to store this because the master
232 may change (in the sense of emitting Changed())
233 several times without actually changing the result
234 of ::get_value(). This is a feature of
235 AutomationControls (or even just Controllables,
236 really) which have more than a simple scalar
237 value. For example, the master may be a mute control
238 which can be muted_by_self() and/or
239 muted_by_masters(). When either of those two
240 conditions changes, Changed() will be emitted, even
241 though ::get_value() will return the same value each
242 time (1.0 if either are true, 0.0 if neither is).
244 This provides a way for derived types to check
245 the last known state of a Master when the Master
246 changes. We update it after calling
247 ::master_changed() (though derived types must do
250 mi->second.set_yn (m->get_value());
256 SlavableAutomationControl::master_changed (bool /*from_self*/, GroupControlDisposition gcd, boost::shared_ptr<AutomationControl> m)
258 update_boolean_masters_records (m);
259 Changed (false, Controllable::NoGroup); /* EMIT SIGNAL */
263 SlavableAutomationControl::master_going_away (boost::weak_ptr<AutomationControl> wm)
265 boost::shared_ptr<AutomationControl> m = wm.lock();
272 SlavableAutomationControl::remove_master (boost::shared_ptr<AutomationControl> m)
274 pre_remove_master (m);
277 Glib::Threads::RWLock::WriterLock lm (master_lock);
279 if (!_masters.erase (m->id())) {
283 if (!_session.deletion_in_progress()) {
285 const double master_value = m->get_value ();
287 if (master_value == 0.0) {
288 /* slave would have been set to 0.0 as well,
289 so just leave it there, and the user can
290 bring it back up. this fits with the
291 "removing a VCA does not change the level" rule.
294 /* bump up the control's own value by the level
295 of the master that is being removed.
297 AutomationControl::set_double (AutomationControl::get_double() * master_value, Controllable::NoGroup);
302 if (_session.deletion_in_progress()) {
303 /* no reason to care about new values or sending signals */
307 MasterStatusChange (); /* EMIT SIGNAL */
309 /* no need to update boolean masters records, since the MR will have
310 * been removed already.
315 SlavableAutomationControl::clear_masters ()
317 double current_value;
319 bool had_masters = false;
321 /* null ptr means "all masters */
322 pre_remove_master (boost::shared_ptr<AutomationControl>());
325 Glib::Threads::RWLock::WriterLock lm (master_lock);
326 current_value = get_value_locked ();
327 if (!_masters.empty()) {
331 new_value = get_value_locked ();
335 MasterStatusChange (); /* EMIT SIGNAL */
338 if (new_value != current_value) {
339 actually_set_value (current_value, Controllable::UseGroup);
342 /* no need to update boolean masters records, since all MRs will have
343 * been removed already.
348 SlavableAutomationControl::find_next_event (double now, double end, Evoral::ControlEvent& next_event) const
350 Glib::Threads::RWLock::ReaderLock lm (master_lock);
351 if (_masters.empty()) {
355 /* iterate over all masters check their automation lists
356 * for any event between "now" and "end" which is earlier than
357 * next_event.when. If found, set next_event.when and return true.
358 * (see also Automatable::find_next_event)
360 for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
361 boost::shared_ptr<AutomationControl> ac (mr->second.master());
363 boost::shared_ptr<SlavableAutomationControl> sc
364 = boost::dynamic_pointer_cast<SlavableAutomationControl>(ac);
366 if (sc && sc->find_next_event (now, end, next_event)) {
370 Evoral::ControlList::const_iterator i;
371 boost::shared_ptr<const Evoral::ControlList> alist (ac->list());
372 Evoral::ControlEvent cp (now, 0.0f);
377 for (i = lower_bound (alist->begin(), alist->end(), &cp, Evoral::ControlList::time_comparator);
378 i != alist->end() && (*i)->when < end; ++i) {
379 if ((*i)->when > now) {
384 if (i != alist->end() && (*i)->when < end) {
385 if ((*i)->when < next_event.when) {
386 next_event.when = (*i)->when;
396 SlavableAutomationControl::slaved_to (boost::shared_ptr<AutomationControl> m) const
398 Glib::Threads::RWLock::ReaderLock lm (master_lock);
399 return _masters.find (m->id()) != _masters.end();
403 SlavableAutomationControl::slaved () const
405 Glib::Threads::RWLock::ReaderLock lm (master_lock);
406 return !_masters.empty();
410 SlavableAutomationControl::use_saved_master_ratios ()
412 if (!_masters_node) {
416 Glib::Threads::RWLock::ReaderLock lm (master_lock);
418 /* use stored state, do not recompute */
422 XMLNodeList nlist = _masters_node->children();
423 XMLNodeIterator niter;
425 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
428 if (!(*niter)->get_property (X_("id"), id_val) || !(*niter)->get_property (X_("yn"), yn)) {
432 Masters::iterator mi = _masters.find (id_val);
433 if (mi != _masters.end()) {
434 mi->second.set_yn (yn);
442 delete _masters_node;
450 SlavableAutomationControl::get_state ()
452 XMLNode& node (AutomationControl::get_state());
454 /* store VCA master ratios */
457 Glib::Threads::RWLock::ReaderLock lm (master_lock);
459 if (!_masters.empty()) {
461 XMLNode* masters_node = new XMLNode (X_("masters"));
464 for (Masters::iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
465 XMLNode* mnode = new XMLNode (X_("master"));
466 mnode->set_property (X_("id"), mr->second.master()->id());
467 mnode->set_property (X_("yn"), mr->second.yn());
468 masters_node->add_child_nocopy (*mnode);
474 node.add_child_nocopy (*masters_node);
482 SlavableAutomationControl::set_state (XMLNode const& node, int version)
484 XMLNodeList nlist = node.children();
485 XMLNodeIterator niter;
487 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
488 if ((*niter)->name() == X_("masters")) {
489 _masters_node = new XMLNode (**niter);
493 return AutomationControl::set_state (node, version);
497 #endif /* __libardour_slavable_automation_control_h__ */