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 apply_gain_to_buffer (vec, veclen, mr->second.val_master_inv ());
159 SlavableAutomationControl::reduce_by_masters_locked (double value, bool ignore_automation_state) const
161 if (!_desc.toggled) {
162 Glib::Threads::RWLock::ReaderLock lm (master_lock);
163 if (!_masters.empty() && (ignore_automation_state || !automation_write ())) {
164 /* need to scale given value by current master's scaling */
165 const double masters_value = get_masters_value_locked();
166 if (masters_value == 0.0) {
169 value /= masters_value;
170 value = std::max (lower(), std::min(upper(), value));
178 SlavableAutomationControl::actually_set_value (double value, PBD::Controllable::GroupControlDisposition gcd)
180 value = reduce_by_masters (value);
181 /* this will call Control::set_double() and emit Changed signals as appropriate */
182 AutomationControl::actually_set_value (value, gcd);
186 SlavableAutomationControl::add_master (boost::shared_ptr<AutomationControl> m, bool loading)
188 std::pair<Masters::iterator,bool> res;
191 const double master_value = m->get_value();
192 Glib::Threads::RWLock::WriterLock lm (master_lock);
194 pair<PBD::ID,MasterRecord> newpair (m->id(), MasterRecord (boost::weak_ptr<AutomationControl> (m), get_value_locked(), master_value));
195 res = _masters.insert (newpair);
199 /* note that we bind @param m as a weak_ptr<AutomationControl>, thus
200 avoiding holding a reference to the control in the binding
203 m->DropReferences.connect_same_thread (res.first->second.dropped_connection, boost::bind (&SlavableAutomationControl::master_going_away, this, boost::weak_ptr<AutomationControl>(m)));
205 /* Store the connection inside the MasterRecord, so
206 that when we destroy it, the connection is destroyed
207 and we no longer hear about changes to the
210 Note that this also makes it safe to store a
211 boost::shared_ptr<AutomationControl> in the functor,
212 since we know we will destroy the functor when the
213 connection is destroyed, which happens when we
214 disconnect from the master (for any reason).
216 Note that we fix the "from_self" argument that will
217 be given to our own Changed signal to "false",
218 because the change came from the master.
221 m->Changed.connect_same_thread (res.first->second.changed_connection, boost::bind (&SlavableAutomationControl::master_changed, this, _1, _2, boost::weak_ptr<AutomationControl>(m)));
226 /* this will notify everyone that we're now slaved to the master */
227 MasterStatusChange (); /* EMIT SIGNAL */
232 update_boolean_masters_records (m);
236 SlavableAutomationControl::get_boolean_masters () const
241 Glib::Threads::RWLock::ReaderLock lm (master_lock);
242 for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
243 if (mr->second.yn()) {
253 SlavableAutomationControl::update_boolean_masters_records (boost::shared_ptr<AutomationControl> m)
256 /* We may modify a MasterRecord, but we not modify the master
257 * map, so we use a ReaderLock
259 Glib::Threads::RWLock::ReaderLock lm (master_lock);
260 Masters::iterator mi = _masters.find (m->id());
261 if (mi != _masters.end()) {
262 /* update MasterRecord to show whether the master is
263 on/off. We need to store this because the master
264 may change (in the sense of emitting Changed())
265 several times without actually changing the result
266 of ::get_value(). This is a feature of
267 AutomationControls (or even just Controllables,
268 really) which have more than a simple scalar
269 value. For example, the master may be a mute control
270 which can be muted_by_self() and/or
271 muted_by_masters(). When either of those two
272 conditions changes, Changed() will be emitted, even
273 though ::get_value() will return the same value each
274 time (1.0 if either are true, 0.0 if neither is).
276 This provides a way for derived types to check
277 the last known state of a Master when the Master
278 changes. We update it after calling
279 ::master_changed() (though derived types must do
282 mi->second.set_yn (m->get_value());
288 SlavableAutomationControl::master_changed (bool /*from_self*/, GroupControlDisposition gcd, boost::weak_ptr<AutomationControl> wm)
290 boost::shared_ptr<AutomationControl> m = wm.lock ();
292 Glib::Threads::RWLock::ReaderLock lm (master_lock, Glib::Threads::TRY_LOCK);
294 /* boolean_automation_run_locked () special case */
297 bool send_signal = handle_master_change (m);
298 lm.release (); // update_boolean_masters_records() takes lock
300 update_boolean_masters_records (m);
302 Changed (false, Controllable::NoGroup); /* EMIT SIGNAL */
307 SlavableAutomationControl::master_going_away (boost::weak_ptr<AutomationControl> wm)
309 boost::shared_ptr<AutomationControl> m = wm.lock();
316 SlavableAutomationControl::scale_automation_callback (double value, double ratio) const
318 /* derived classes can override this and e.g. add/subtract. */
320 value = std::max (lower(), std::min(upper(), value));
325 SlavableAutomationControl::remove_master (boost::shared_ptr<AutomationControl> m)
327 if (_session.deletion_in_progress()) {
328 /* no reason to care about new values or sending signals */
332 pre_remove_master (m);
334 const double old_val = AutomationControl::get_double();
336 bool update_value = false;
337 double master_ratio = 0;
338 double list_ratio = 1;
340 boost::shared_ptr<AutomationControl> master;
343 Glib::Threads::RWLock::WriterLock lm (master_lock);
345 Masters::const_iterator mi = _masters.find (m->id ());
347 if (mi != _masters.end()) {
348 master_ratio = mi->second.master_ratio ();
350 master = mi->second.master();
351 list_ratio *= mi->second.val_master_inv ();
354 if (!_masters.erase (m->id())) {
360 /* when un-assigning we apply the master-value permanently */
361 double new_val = old_val * master_ratio;
363 if (old_val != new_val) {
364 AutomationControl::set_double (new_val, Controllable::NoGroup);
367 /* ..and update automation */
369 if (master->automation_playback () && master->list()) {
370 _list->list_merge (*master->list().get(), boost::bind (&SlavableAutomationControl::scale_automation_callback, this, _1, _2));
371 _list->y_transform (boost::bind (&SlavableAutomationControl::scale_automation_callback, this, _1, list_ratio));
373 // do we need to freeze/thaw the list? probably no: iterators & positions don't change
374 _list->y_transform (boost::bind (&SlavableAutomationControl::scale_automation_callback, this, _1, master_ratio));
379 MasterStatusChange (); /* EMIT SIGNAL */
381 /* no need to update boolean masters records, since the MR will have
382 * been removed already.
387 SlavableAutomationControl::clear_masters ()
389 if (_session.deletion_in_progress()) {
390 /* no reason to care about new values or sending signals */
394 const double old_val = AutomationControl::get_double();
397 bool update_value = false;
398 double master_ratio = 0;
399 double list_ratio = 1;
401 /* null ptr means "all masters */
402 pre_remove_master (boost::shared_ptr<AutomationControl>());
405 Glib::Threads::RWLock::WriterLock lm (master_lock);
406 if (_masters.empty()) {
410 for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
411 boost::shared_ptr<AutomationControl> master = mr->second.master();
412 if (master->automation_playback () && master->list()) {
413 masters.push_back (mr->second.master());
414 list_ratio *= mr->second.val_master_inv ();
416 list_ratio *= mr->second.master_ratio ();
420 master_ratio = get_masters_value_locked ();
426 /* permanently apply masters value */
427 double new_val = old_val * master_ratio;
429 if (old_val != new_val) {
430 AutomationControl::set_double (new_val, Controllable::NoGroup);
433 /* ..and update automation */
435 if (!masters.empty()) {
436 for (ControlList::const_iterator m = masters.begin(); m != masters.end(); ++m) {
437 _list->list_merge (*(*m)->list().get(), boost::bind (&SlavableAutomationControl::scale_automation_callback, this, _1, _2));
439 _list->y_transform (boost::bind (&SlavableAutomationControl::scale_automation_callback, this, _1, list_ratio));
441 _list->y_transform (boost::bind (&SlavableAutomationControl::scale_automation_callback, this, _1, master_ratio));
446 MasterStatusChange (); /* EMIT SIGNAL */
448 /* no need to update boolean masters records, since all MRs will have
449 * been removed already.
454 SlavableAutomationControl::find_next_event_locked (double now, double end, Evoral::ControlEvent& next_event) const
456 if (_masters.empty()) {
460 /* iterate over all masters check their automation lists
461 * for any event between "now" and "end" which is earlier than
462 * next_event.when. If found, set next_event.when and return true.
463 * (see also Automatable::find_next_event)
465 for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
466 boost::shared_ptr<AutomationControl> ac (mr->second.master());
468 boost::shared_ptr<SlavableAutomationControl> sc
469 = boost::dynamic_pointer_cast<SlavableAutomationControl>(ac);
471 if (sc && sc->find_next_event_locked (now, end, next_event)) {
475 Evoral::ControlList::const_iterator i;
476 boost::shared_ptr<const Evoral::ControlList> alist (ac->list());
477 Evoral::ControlEvent cp (now, 0.0f);
482 for (i = lower_bound (alist->begin(), alist->end(), &cp, Evoral::ControlList::time_comparator);
483 i != alist->end() && (*i)->when < end; ++i) {
484 if ((*i)->when > now) {
489 if (i != alist->end() && (*i)->when < end) {
490 if ((*i)->when < next_event.when) {
491 next_event.when = (*i)->when;
501 SlavableAutomationControl::handle_master_change (boost::shared_ptr<AutomationControl>)
503 /* Derived classes can implement this for special cases (e.g. mute).
504 * This method is called with a ReaderLock (master_lock) held.
506 * return true if the changed master value resulted
507 * in a change of the control itself. */
508 return true; // emit Changed
512 SlavableAutomationControl::boolean_automation_run_locked (framepos_t start, pframes_t len)
515 if (!_desc.toggled) {
518 for (Masters::iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
519 boost::shared_ptr<AutomationControl> ac (mr->second.master());
520 if (!ac->automation_playback ()) {
523 if (!ac->toggled ()) {
526 boost::shared_ptr<SlavableAutomationControl> sc = boost::dynamic_pointer_cast<MuteControl>(ac);
528 rv |= sc->boolean_automation_run (start, len);
530 boost::shared_ptr<const Evoral::ControlList> alist (ac->list());
532 const bool yn = alist->rt_safe_eval (start, valid) >= 0.5;
536 /* ideally we'd call just master_changed() which calls update_boolean_masters_records()
537 * but that takes the master_lock, which is already locked */
538 if (mr->second.yn() != yn) {
539 rv |= handle_master_change (ac);
540 mr->second.set_yn (yn);
541 /* notify the GUI, without recursion:
542 * master_changed() above will ignore the change if the lock is held.
544 ac->set_value_unchecked (yn ? 1. : 0.);
545 ac->Changed (false, Controllable::NoGroup); /* EMIT SIGNAL */
552 SlavableAutomationControl::boolean_automation_run (framepos_t start, pframes_t len)
556 Glib::Threads::RWLock::ReaderLock lm (master_lock);
557 change = boolean_automation_run_locked (start, len);
560 Changed (false, Controllable::NoGroup); /* EMIT SIGNAL */
566 SlavableAutomationControl::slaved_to (boost::shared_ptr<AutomationControl> m) const
568 Glib::Threads::RWLock::ReaderLock lm (master_lock);
569 return _masters.find (m->id()) != _masters.end();
573 SlavableAutomationControl::slaved () const
575 Glib::Threads::RWLock::ReaderLock lm (master_lock);
576 return !_masters.empty();
580 SlavableAutomationControl::MasterRecord::set_state (XMLNode const& n, int)
582 n.get_property (X_("yn"), _yn);
583 n.get_property (X_("val-ctrl"), _val_ctrl);
584 n.get_property (X_("val-master"), _val_master);
589 SlavableAutomationControl::use_saved_master_ratios ()
591 if (!_masters_node) {
595 Glib::Threads::RWLock::ReaderLock lm (master_lock);
597 XMLNodeList nlist = _masters_node->children();
598 XMLNodeIterator niter;
600 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
602 if (!(*niter)->get_property (X_("id"), id_val)) {
605 Masters::iterator mi = _masters.find (id_val);
606 if (mi == _masters.end()) {
609 mi->second.set_state (**niter, Stateful::loading_state_version);
612 delete _masters_node;
620 SlavableAutomationControl::get_state ()
622 XMLNode& node (AutomationControl::get_state());
624 /* store VCA master ratios */
627 Glib::Threads::RWLock::ReaderLock lm (master_lock);
628 if (!_masters.empty()) {
629 XMLNode* masters_node = new XMLNode (X_("masters"));
630 for (Masters::iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
631 XMLNode* mnode = new XMLNode (X_("master"));
632 mnode->set_property (X_("id"), mr->second.master()->id());
635 mnode->set_property (X_("yn"), mr->second.yn());
637 mnode->set_property (X_("val-ctrl"), mr->second.val_ctrl());
638 mnode->set_property (X_("val-master"), mr->second.val_master());
640 masters_node->add_child_nocopy (*mnode);
642 node.add_child_nocopy (*masters_node);
650 SlavableAutomationControl::set_state (XMLNode const& node, int version)
652 XMLNodeList nlist = node.children();
653 XMLNodeIterator niter;
655 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
656 if ((*niter)->name() == X_("masters")) {
657 _masters_node = new XMLNode (**niter);
661 return AutomationControl::set_state (node, version);
665 #endif /* __libardour_slavable_automation_control_h__ */