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 "evoral/Curve.hpp"
29 #include "ardour/audioengine.h"
30 #include "ardour/runtime_functions.h"
31 #include "ardour/slavable_automation_control.h"
32 #include "ardour/session.h"
35 using namespace ARDOUR;
38 SlavableAutomationControl::SlavableAutomationControl(ARDOUR::Session& s,
39 const Evoral::Parameter& parameter,
40 const ParameterDescriptor& desc,
41 boost::shared_ptr<ARDOUR::AutomationList> l,
42 const std::string& name,
43 Controllable::Flag flags)
44 : AutomationControl (s, parameter, desc, l, name, flags)
49 SlavableAutomationControl::~SlavableAutomationControl ()
58 SlavableAutomationControl::get_masters_value_locked () const
61 for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
62 if (mr->second.master()->get_value()) {
69 double v = 1.0; /* the masters function as a scaling factor */
71 for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
72 v *= mr->second.master_ratio ();
80 SlavableAutomationControl::get_value_locked() const
82 /* read or write masters lock must be held */
84 if (_masters.empty()) {
85 return Control::get_double (false, _session.transport_frame());
89 /* for boolean/toggle controls, if this slave OR any master is
90 * enabled, this slave is enabled. So check our own value
91 * first, because if we are enabled, we can return immediately.
93 if (Control::get_double (false, _session.transport_frame())) {
98 return Control::get_double() * get_masters_value_locked ();
101 /** Get the current effective `user' value based on automation state */
103 SlavableAutomationControl::get_value() const
105 bool from_list = _list && boost::dynamic_pointer_cast<AutomationList>(_list)->automation_playback();
107 Glib::Threads::RWLock::ReaderLock lm (master_lock);
109 return get_value_locked ();
111 return Control::get_double (true, _session.transport_frame()) * get_masters_value_locked();
116 SlavableAutomationControl::get_masters_curve_locked (framepos_t, framepos_t, float*, framecnt_t) const
118 /* Every AutomationControl needs to implement this as-needed.
120 * This class also provides some convenient methods which
121 * could be used as defaults here (depending on AutomationType)
122 * e.g. masters_curve_multiply()
128 SlavableAutomationControl::masters_curve_multiply (framepos_t start, framepos_t end, float* vec, framecnt_t veclen) const
130 gain_t* scratch = _session.scratch_automation_buffer ();
131 bool rv = list()->curve().rt_safe_get_vector (start, end, scratch, veclen);
133 for (framecnt_t i = 0; i < veclen; ++i) {
134 vec[i] *= scratch[i];
137 apply_gain_to_buffer (vec, veclen, Control::get_double ());
139 if (_masters.empty()) {
143 for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
144 boost::shared_ptr<SlavableAutomationControl> sc
145 = boost::dynamic_pointer_cast<SlavableAutomationControl>(mr->second.master());
147 rv |= sc->masters_curve_multiply (start, end, vec, veclen);
148 apply_gain_to_buffer (vec, veclen, mr->second.master_ratio ());
154 SlavableAutomationControl::actually_set_value (double value, PBD::Controllable::GroupControlDisposition gcd)
156 if (!_desc.toggled) {
158 Glib::Threads::RWLock::WriterLock lm (master_lock);
160 if (!_masters.empty()) {
161 /* need to scale given value by current master's scaling */
162 const double masters_value = get_masters_value_locked();
163 if (masters_value == 0.0) {
166 value /= masters_value;
167 value = std::max (lower(), std::min(upper(), value));
172 /* this will call Control::set_double() and emit Changed signals as appropriate */
173 AutomationControl::actually_set_value (value, gcd);
177 SlavableAutomationControl::add_master (boost::shared_ptr<AutomationControl> m, bool loading)
179 std::pair<Masters::iterator,bool> res;
182 const double master_value = m->get_value();
183 Glib::Threads::RWLock::WriterLock lm (master_lock);
185 pair<PBD::ID,MasterRecord> newpair (m->id(), MasterRecord (boost::weak_ptr<AutomationControl> (m), get_value_locked(), master_value));
186 res = _masters.insert (newpair);
190 /* note that we bind @param m as a weak_ptr<AutomationControl>, thus
191 avoiding holding a reference to the control in the binding
194 m->DropReferences.connect_same_thread (res.first->second.dropped_connection, boost::bind (&SlavableAutomationControl::master_going_away, this, boost::weak_ptr<AutomationControl>(m)));
196 /* Store the connection inside the MasterRecord, so
197 that when we destroy it, the connection is destroyed
198 and we no longer hear about changes to the
201 Note that this also makes it safe to store a
202 boost::shared_ptr<AutomationControl> in the functor,
203 since we know we will destroy the functor when the
204 connection is destroyed, which happens when we
205 disconnect from the master (for any reason).
207 Note that we fix the "from_self" argument that will
208 be given to our own Changed signal to "false",
209 because the change came from the master.
212 m->Changed.connect_same_thread (res.first->second.changed_connection, boost::bind (&SlavableAutomationControl::master_changed, this, _1, _2, boost::weak_ptr<AutomationControl>(m)));
217 /* this will notify everyone that we're now slaved to the master */
218 MasterStatusChange (); /* EMIT SIGNAL */
223 update_boolean_masters_records (m);
227 SlavableAutomationControl::get_boolean_masters () const
232 Glib::Threads::RWLock::ReaderLock lm (master_lock);
233 for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
234 if (mr->second.yn()) {
244 SlavableAutomationControl::update_boolean_masters_records (boost::shared_ptr<AutomationControl> m)
247 /* We may modify a MasterRecord, but we not modify the master
248 * map, so we use a ReaderLock
250 Glib::Threads::RWLock::ReaderLock lm (master_lock);
251 Masters::iterator mi = _masters.find (m->id());
252 if (mi != _masters.end()) {
253 /* update MasterRecord to show whether the master is
254 on/off. We need to store this because the master
255 may change (in the sense of emitting Changed())
256 several times without actually changing the result
257 of ::get_value(). This is a feature of
258 AutomationControls (or even just Controllables,
259 really) which have more than a simple scalar
260 value. For example, the master may be a mute control
261 which can be muted_by_self() and/or
262 muted_by_masters(). When either of those two
263 conditions changes, Changed() will be emitted, even
264 though ::get_value() will return the same value each
265 time (1.0 if either are true, 0.0 if neither is).
267 This provides a way for derived types to check
268 the last known state of a Master when the Master
269 changes. We update it after calling
270 ::master_changed() (though derived types must do
273 mi->second.set_yn (m->get_value());
279 SlavableAutomationControl::master_changed (bool /*from_self*/, GroupControlDisposition gcd, boost::weak_ptr<AutomationControl> wm)
281 boost::shared_ptr<AutomationControl> m = wm.lock ();
283 Glib::Threads::RWLock::ReaderLock lm (master_lock, Glib::Threads::TRY_LOCK);
285 /* boolean_automation_run_locked () special case */
288 bool send_signal = handle_master_change (m);
289 lm.release (); // update_boolean_masters_records() takes lock
291 update_boolean_masters_records (m);
293 Changed (false, Controllable::NoGroup); /* EMIT SIGNAL */
298 SlavableAutomationControl::master_going_away (boost::weak_ptr<AutomationControl> wm)
300 boost::shared_ptr<AutomationControl> m = wm.lock();
307 SlavableAutomationControl::remove_master (boost::shared_ptr<AutomationControl> m)
309 if (_session.deletion_in_progress()) {
310 /* no reason to care about new values or sending signals */
314 pre_remove_master (m);
315 double new_val = AutomationControl::get_double();
316 const double old_val = new_val;
319 Glib::Threads::RWLock::WriterLock lm (master_lock);
321 Masters::const_iterator mi = _masters.find (m->id ());
323 /* when un-assigning we apply the master-value permanently */
324 if (mi != _masters.end()) {
325 new_val *= mi->second.master_ratio ();
328 if (!_masters.erase (m->id())) {
333 if (old_val != new_val) {
334 AutomationControl::set_double (new_val, Controllable::NoGroup);
337 MasterStatusChange (); /* EMIT SIGNAL */
339 /* no need to update boolean masters records, since the MR will have
340 * been removed already.
345 SlavableAutomationControl::clear_masters ()
347 if (_session.deletion_in_progress()) {
348 /* no reason to care about new values or sending signals */
352 double new_val = AutomationControl::get_double();
353 const double old_val = new_val;
355 /* null ptr means "all masters */
356 pre_remove_master (boost::shared_ptr<AutomationControl>());
359 Glib::Threads::RWLock::WriterLock lm (master_lock);
360 if (_masters.empty()) {
363 /* permanently apply masters value */
364 new_val *= get_masters_value_locked ();
369 if (old_val != new_val) {
370 AutomationControl::set_double (new_val, Controllable::NoGroup);
372 MasterStatusChange (); /* EMIT SIGNAL */
374 /* no need to update boolean masters records, since all MRs will have
375 * been removed already.
380 SlavableAutomationControl::find_next_event_locked (double now, double end, Evoral::ControlEvent& next_event) const
382 if (_masters.empty()) {
386 /* iterate over all masters check their automation lists
387 * for any event between "now" and "end" which is earlier than
388 * next_event.when. If found, set next_event.when and return true.
389 * (see also Automatable::find_next_event)
391 for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
392 boost::shared_ptr<AutomationControl> ac (mr->second.master());
394 boost::shared_ptr<SlavableAutomationControl> sc
395 = boost::dynamic_pointer_cast<SlavableAutomationControl>(ac);
397 if (sc && sc->find_next_event_locked (now, end, next_event)) {
401 Evoral::ControlList::const_iterator i;
402 boost::shared_ptr<const Evoral::ControlList> alist (ac->list());
403 Evoral::ControlEvent cp (now, 0.0f);
408 for (i = lower_bound (alist->begin(), alist->end(), &cp, Evoral::ControlList::time_comparator);
409 i != alist->end() && (*i)->when < end; ++i) {
410 if ((*i)->when > now) {
415 if (i != alist->end() && (*i)->when < end) {
416 if ((*i)->when < next_event.when) {
417 next_event.when = (*i)->when;
427 SlavableAutomationControl::handle_master_change (boost::shared_ptr<AutomationControl>)
429 /* Derived classes can implement this for special cases (e.g. mute).
430 * This method is called with a ReaderLock (master_lock) held.
432 * return true if the changed master value resulted
433 * in a change of the control itself. */
434 return true; // emit Changed
438 SlavableAutomationControl::boolean_automation_run_locked (framepos_t start, pframes_t len)
441 if (!_desc.toggled) {
444 for (Masters::iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
445 boost::shared_ptr<AutomationControl> ac (mr->second.master());
446 if (!ac->automation_playback ()) {
449 if (!ac->toggled ()) {
452 boost::shared_ptr<SlavableAutomationControl> sc = boost::dynamic_pointer_cast<MuteControl>(ac);
454 rv |= sc->boolean_automation_run (start, len);
456 boost::shared_ptr<const Evoral::ControlList> alist (ac->list());
458 const bool yn = alist->rt_safe_eval (start, valid) >= 0.5;
462 /* ideally we'd call just master_changed() which calls update_boolean_masters_records()
463 * but that takes the master_lock, which is already locked */
464 if (mr->second.yn() != yn) {
465 rv |= handle_master_change (ac);
466 mr->second.set_yn (yn);
467 /* notify the GUI, without recursion:
468 * master_changed() above will ignore the change if the lock is held.
470 ac->set_value_unchecked (yn ? 1. : 0.);
471 ac->Changed (false, Controllable::NoGroup); /* EMIT SIGNAL */
478 SlavableAutomationControl::boolean_automation_run (framepos_t start, pframes_t len)
482 Glib::Threads::RWLock::ReaderLock lm (master_lock);
483 change = boolean_automation_run_locked (start, len);
486 Changed (false, Controllable::NoGroup); /* EMIT SIGNAL */
492 SlavableAutomationControl::slaved_to (boost::shared_ptr<AutomationControl> m) const
494 Glib::Threads::RWLock::ReaderLock lm (master_lock);
495 return _masters.find (m->id()) != _masters.end();
499 SlavableAutomationControl::slaved () const
501 Glib::Threads::RWLock::ReaderLock lm (master_lock);
502 return !_masters.empty();
506 SlavableAutomationControl::MasterRecord::set_state (XMLNode const& n, int)
508 n.get_property (X_("yn"), _yn);
509 n.get_property (X_("val-ctrl"), _val_ctrl);
510 n.get_property (X_("val-master"), _val_master);
515 SlavableAutomationControl::use_saved_master_ratios ()
517 if (!_masters_node) {
521 Glib::Threads::RWLock::ReaderLock lm (master_lock);
523 XMLNodeList nlist = _masters_node->children();
524 XMLNodeIterator niter;
526 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
528 if (!(*niter)->get_property (X_("id"), id_val)) {
531 Masters::iterator mi = _masters.find (id_val);
532 if (mi == _masters.end()) {
535 mi->second.set_state (**niter, Stateful::loading_state_version);
538 delete _masters_node;
546 SlavableAutomationControl::get_state ()
548 XMLNode& node (AutomationControl::get_state());
550 /* store VCA master ratios */
553 Glib::Threads::RWLock::ReaderLock lm (master_lock);
554 if (!_masters.empty()) {
555 XMLNode* masters_node = new XMLNode (X_("masters"));
556 for (Masters::iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
557 XMLNode* mnode = new XMLNode (X_("master"));
558 mnode->set_property (X_("id"), mr->second.master()->id());
561 mnode->set_property (X_("yn"), mr->second.yn());
563 mnode->set_property (X_("val-ctrl"), mr->second.val_ctrl());
564 mnode->set_property (X_("val-master"), mr->second.val_master());
566 masters_node->add_child_nocopy (*mnode);
567 node.add_child_nocopy (*masters_node);
576 SlavableAutomationControl::set_state (XMLNode const& node, int version)
578 XMLNodeList nlist = node.children();
579 XMLNodeIterator niter;
581 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
582 if ((*niter)->name() == X_("masters")) {
583 _masters_node = new XMLNode (**niter);
587 return AutomationControl::set_state (node, version);
591 #endif /* __libardour_slavable_automation_control_h__ */