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 if (!_masters.empty() && automation_write ()) {
110 /* writing automation takes the fader value as-is, factor out the master */
111 return Control::user_double ();
113 return get_value_locked ();
115 return Control::get_double (true, _session.transport_frame()) * get_masters_value_locked();
120 SlavableAutomationControl::get_masters_curve_locked (framepos_t, framepos_t, float*, framecnt_t) const
122 /* Every AutomationControl needs to implement this as-needed.
124 * This class also provides some convenient methods which
125 * could be used as defaults here (depending on AutomationType)
126 * e.g. masters_curve_multiply()
132 SlavableAutomationControl::masters_curve_multiply (framepos_t start, framepos_t end, float* vec, framecnt_t veclen) const
134 gain_t* scratch = _session.scratch_automation_buffer ();
135 bool from_list = _list && boost::dynamic_pointer_cast<AutomationList>(_list)->automation_playback();
136 bool rv = from_list && list()->curve().rt_safe_get_vector (start, end, scratch, veclen);
138 for (framecnt_t i = 0; i < veclen; ++i) {
139 vec[i] *= scratch[i];
142 apply_gain_to_buffer (vec, veclen, Control::get_double ());
144 if (_masters.empty()) {
148 for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
149 boost::shared_ptr<SlavableAutomationControl> sc
150 = boost::dynamic_pointer_cast<SlavableAutomationControl>(mr->second.master());
152 rv |= sc->masters_curve_multiply (start, end, vec, veclen);
153 if (mr->second.val_master () != 0) {
154 apply_gain_to_buffer (vec, veclen, 1.f / mr->second.val_master ());
161 SlavableAutomationControl::reduce_by_masters_locked (double value, bool ignore_automation_state) const
163 if (!_desc.toggled) {
164 Glib::Threads::RWLock::ReaderLock lm (master_lock);
165 if (!_masters.empty() && (ignore_automation_state || !automation_write ())) {
166 /* need to scale given value by current master's scaling */
167 const double masters_value = get_masters_value_locked();
168 if (masters_value == 0.0) {
169 value = 0.0; // XXX 1.0, see master_ratio(), val_master_inv()
171 value /= masters_value;
172 value = std::max (lower(), std::min(upper(), value));
180 SlavableAutomationControl::actually_set_value (double value, PBD::Controllable::GroupControlDisposition gcd)
182 value = reduce_by_masters (value);
183 /* this will call Control::set_double() and emit Changed signals as appropriate */
184 AutomationControl::actually_set_value (value, gcd);
188 SlavableAutomationControl::add_master (boost::shared_ptr<AutomationControl> m, bool loading)
190 std::pair<Masters::iterator,bool> res;
193 const double master_value = m->get_value();
194 Glib::Threads::RWLock::WriterLock lm (master_lock);
196 pair<PBD::ID,MasterRecord> newpair (m->id(), MasterRecord (boost::weak_ptr<AutomationControl> (m), get_value_locked(), master_value));
197 res = _masters.insert (newpair);
201 /* note that we bind @param m as a weak_ptr<AutomationControl>, thus
202 avoiding holding a reference to the control in the binding
205 m->DropReferences.connect_same_thread (res.first->second.dropped_connection, boost::bind (&SlavableAutomationControl::master_going_away, this, boost::weak_ptr<AutomationControl>(m)));
207 /* Store the connection inside the MasterRecord, so
208 that when we destroy it, the connection is destroyed
209 and we no longer hear about changes to the
212 Note that this also makes it safe to store a
213 boost::shared_ptr<AutomationControl> in the functor,
214 since we know we will destroy the functor when the
215 connection is destroyed, which happens when we
216 disconnect from the master (for any reason).
218 Note that we fix the "from_self" argument that will
219 be given to our own Changed signal to "false",
220 because the change came from the master.
223 m->Changed.connect_same_thread (res.first->second.changed_connection, boost::bind (&SlavableAutomationControl::master_changed, this, _1, _2, boost::weak_ptr<AutomationControl>(m)));
228 /* this will notify everyone that we're now slaved to the master */
229 MasterStatusChange (); /* EMIT SIGNAL */
234 update_boolean_masters_records (m);
238 SlavableAutomationControl::get_boolean_masters () const
243 Glib::Threads::RWLock::ReaderLock lm (master_lock);
244 for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
245 if (mr->second.yn()) {
255 SlavableAutomationControl::update_boolean_masters_records (boost::shared_ptr<AutomationControl> m)
258 /* We may modify a MasterRecord, but we not modify the master
259 * map, so we use a ReaderLock
261 Glib::Threads::RWLock::ReaderLock lm (master_lock);
262 Masters::iterator mi = _masters.find (m->id());
263 if (mi != _masters.end()) {
264 /* update MasterRecord to show whether the master is
265 on/off. We need to store this because the master
266 may change (in the sense of emitting Changed())
267 several times without actually changing the result
268 of ::get_value(). This is a feature of
269 AutomationControls (or even just Controllables,
270 really) which have more than a simple scalar
271 value. For example, the master may be a mute control
272 which can be muted_by_self() and/or
273 muted_by_masters(). When either of those two
274 conditions changes, Changed() will be emitted, even
275 though ::get_value() will return the same value each
276 time (1.0 if either are true, 0.0 if neither is).
278 This provides a way for derived types to check
279 the last known state of a Master when the Master
280 changes. We update it after calling
281 ::master_changed() (though derived types must do
284 mi->second.set_yn (m->get_value());
290 SlavableAutomationControl::master_changed (bool /*from_self*/, GroupControlDisposition gcd, boost::weak_ptr<AutomationControl> wm)
292 boost::shared_ptr<AutomationControl> m = wm.lock ();
294 Glib::Threads::RWLock::ReaderLock lm (master_lock, Glib::Threads::TRY_LOCK);
296 /* boolean_automation_run_locked () special case */
299 bool send_signal = handle_master_change (m);
300 lm.release (); // update_boolean_masters_records() takes lock
302 update_boolean_masters_records (m);
304 Changed (false, Controllable::NoGroup); /* EMIT SIGNAL */
309 SlavableAutomationControl::master_going_away (boost::weak_ptr<AutomationControl> wm)
311 boost::shared_ptr<AutomationControl> m = wm.lock();
318 SlavableAutomationControl::scale_automation_callback (double value, double ratio) const
320 /* derived classes can override this and e.g. add/subtract. */
322 value = std::max (lower(), std::min(upper(), value));
327 SlavableAutomationControl::remove_master (boost::shared_ptr<AutomationControl> m)
329 if (_session.deletion_in_progress()) {
330 /* no reason to care about new values or sending signals */
334 pre_remove_master (m);
336 const double old_val = AutomationControl::get_double();
338 bool update_value = false;
339 double master_ratio = 0;
340 double list_ratio = 1;
342 boost::shared_ptr<AutomationControl> master;
345 Glib::Threads::RWLock::WriterLock lm (master_lock);
347 Masters::const_iterator mi = _masters.find (m->id ());
349 if (mi != _masters.end()) {
350 master_ratio = mi->second.master_ratio ();
352 master = mi->second.master();
353 list_ratio *= mi->second.val_master_inv ();
356 if (!_masters.erase (m->id())) {
362 /* when un-assigning we apply the master-value permanently */
363 double new_val = old_val * master_ratio;
365 if (old_val != new_val) {
366 AutomationControl::set_double (new_val, Controllable::NoGroup);
369 /* ..and update automation */
371 if (master->automation_playback () && master->list()) {
372 _list->list_merge (*master->list().get(), boost::bind (&SlavableAutomationControl::scale_automation_callback, this, _1, _2));
373 _list->y_transform (boost::bind (&SlavableAutomationControl::scale_automation_callback, this, _1, list_ratio));
375 // do we need to freeze/thaw the list? probably no: iterators & positions don't change
376 _list->y_transform (boost::bind (&SlavableAutomationControl::scale_automation_callback, this, _1, master_ratio));
381 MasterStatusChange (); /* EMIT SIGNAL */
383 /* no need to update boolean masters records, since the MR will have
384 * been removed already.
389 SlavableAutomationControl::clear_masters ()
391 if (_session.deletion_in_progress()) {
392 /* no reason to care about new values or sending signals */
396 const double old_val = AutomationControl::get_double();
399 bool update_value = false;
400 double master_ratio = 0;
401 double list_ratio = 1;
403 /* null ptr means "all masters */
404 pre_remove_master (boost::shared_ptr<AutomationControl>());
407 Glib::Threads::RWLock::WriterLock lm (master_lock);
408 if (_masters.empty()) {
412 for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
413 boost::shared_ptr<AutomationControl> master = mr->second.master();
414 if (master->automation_playback () && master->list()) {
415 masters.push_back (mr->second.master());
416 list_ratio *= mr->second.val_master_inv ();
418 list_ratio *= mr->second.master_ratio ();
422 master_ratio = get_masters_value_locked ();
428 /* permanently apply masters value */
429 double new_val = old_val * master_ratio;
431 if (old_val != new_val) {
432 AutomationControl::set_double (new_val, Controllable::NoGroup);
435 /* ..and update automation */
437 if (!masters.empty()) {
438 for (ControlList::const_iterator m = masters.begin(); m != masters.end(); ++m) {
439 _list->list_merge (*(*m)->list().get(), boost::bind (&SlavableAutomationControl::scale_automation_callback, this, _1, _2));
441 _list->y_transform (boost::bind (&SlavableAutomationControl::scale_automation_callback, this, _1, list_ratio));
443 _list->y_transform (boost::bind (&SlavableAutomationControl::scale_automation_callback, this, _1, master_ratio));
448 MasterStatusChange (); /* EMIT SIGNAL */
450 /* no need to update boolean masters records, since all MRs will have
451 * been removed already.
456 SlavableAutomationControl::find_next_event_locked (double now, double end, Evoral::ControlEvent& next_event) const
458 if (_masters.empty()) {
462 /* iterate over all masters check their automation lists
463 * for any event between "now" and "end" which is earlier than
464 * next_event.when. If found, set next_event.when and return true.
465 * (see also Automatable::find_next_event)
467 for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
468 boost::shared_ptr<AutomationControl> ac (mr->second.master());
470 boost::shared_ptr<SlavableAutomationControl> sc
471 = boost::dynamic_pointer_cast<SlavableAutomationControl>(ac);
473 if (sc && sc->find_next_event_locked (now, end, next_event)) {
477 Evoral::ControlList::const_iterator i;
478 boost::shared_ptr<const Evoral::ControlList> alist (ac->list());
479 Evoral::ControlEvent cp (now, 0.0f);
484 for (i = lower_bound (alist->begin(), alist->end(), &cp, Evoral::ControlList::time_comparator);
485 i != alist->end() && (*i)->when < end; ++i) {
486 if ((*i)->when > now) {
491 if (i != alist->end() && (*i)->when < end) {
492 if ((*i)->when < next_event.when) {
493 next_event.when = (*i)->when;
503 SlavableAutomationControl::handle_master_change (boost::shared_ptr<AutomationControl>)
505 /* Derived classes can implement this for special cases (e.g. mute).
506 * This method is called with a ReaderLock (master_lock) held.
508 * return true if the changed master value resulted
509 * in a change of the control itself. */
510 return true; // emit Changed
514 SlavableAutomationControl::boolean_automation_run_locked (framepos_t start, pframes_t len)
517 if (!_desc.toggled) {
520 for (Masters::iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
521 boost::shared_ptr<AutomationControl> ac (mr->second.master());
522 if (!ac->automation_playback ()) {
525 if (!ac->toggled ()) {
528 boost::shared_ptr<SlavableAutomationControl> sc = boost::dynamic_pointer_cast<MuteControl>(ac);
530 rv |= sc->boolean_automation_run (start, len);
532 boost::shared_ptr<const Evoral::ControlList> alist (ac->list());
534 const bool yn = alist->rt_safe_eval (start, valid) >= 0.5;
538 /* ideally we'd call just master_changed() which calls update_boolean_masters_records()
539 * but that takes the master_lock, which is already locked */
540 if (mr->second.yn() != yn) {
541 rv |= handle_master_change (ac);
542 mr->second.set_yn (yn);
543 /* notify the GUI, without recursion:
544 * master_changed() above will ignore the change if the lock is held.
546 ac->set_value_unchecked (yn ? 1. : 0.);
547 ac->Changed (false, Controllable::NoGroup); /* EMIT SIGNAL */
554 SlavableAutomationControl::boolean_automation_run (framepos_t start, pframes_t len)
558 Glib::Threads::RWLock::ReaderLock lm (master_lock);
559 change = boolean_automation_run_locked (start, len);
562 Changed (false, Controllable::NoGroup); /* EMIT SIGNAL */
568 SlavableAutomationControl::slaved_to (boost::shared_ptr<AutomationControl> m) const
570 Glib::Threads::RWLock::ReaderLock lm (master_lock);
571 return _masters.find (m->id()) != _masters.end();
575 SlavableAutomationControl::slaved () const
577 Glib::Threads::RWLock::ReaderLock lm (master_lock);
578 return !_masters.empty();
582 SlavableAutomationControl::MasterRecord::set_state (XMLNode const& n, int)
584 n.get_property (X_("yn"), _yn);
585 n.get_property (X_("val-ctrl"), _val_ctrl);
586 n.get_property (X_("val-master"), _val_master);
591 SlavableAutomationControl::use_saved_master_ratios ()
593 if (!_masters_node) {
597 Glib::Threads::RWLock::ReaderLock lm (master_lock);
599 XMLNodeList nlist = _masters_node->children();
600 XMLNodeIterator niter;
602 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
604 if (!(*niter)->get_property (X_("id"), id_val)) {
607 Masters::iterator mi = _masters.find (id_val);
608 if (mi == _masters.end()) {
611 mi->second.set_state (**niter, Stateful::loading_state_version);
614 delete _masters_node;
622 SlavableAutomationControl::get_state ()
624 XMLNode& node (AutomationControl::get_state());
626 /* store VCA master ratios */
629 Glib::Threads::RWLock::ReaderLock lm (master_lock);
630 if (!_masters.empty()) {
631 XMLNode* masters_node = new XMLNode (X_("masters"));
632 for (Masters::iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
633 XMLNode* mnode = new XMLNode (X_("master"));
634 mnode->set_property (X_("id"), mr->second.master()->id());
637 mnode->set_property (X_("yn"), mr->second.yn());
639 mnode->set_property (X_("val-ctrl"), mr->second.val_ctrl());
640 mnode->set_property (X_("val-master"), mr->second.val_master());
642 masters_node->add_child_nocopy (*mnode);
644 node.add_child_nocopy (*masters_node);
652 SlavableAutomationControl::set_state (XMLNode const& node, int version)
654 XMLNodeList nlist = node.children();
655 XMLNodeIterator niter;
657 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
658 if ((*niter)->name() == X_("masters")) {
659 _masters_node = new XMLNode (**niter);
663 return AutomationControl::set_state (node, version);
667 #endif /* __libardour_slavable_automation_control_h__ */