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/memento_command.h"
25 #include "pbd/types_convert.h"
28 #include "evoral/Curve.hpp"
30 #include "ardour/audioengine.h"
31 #include "ardour/runtime_functions.h"
32 #include "ardour/slavable_automation_control.h"
33 #include "ardour/session.h"
36 using namespace ARDOUR;
39 SlavableAutomationControl::SlavableAutomationControl(ARDOUR::Session& s,
40 const Evoral::Parameter& parameter,
41 const ParameterDescriptor& desc,
42 boost::shared_ptr<ARDOUR::AutomationList> l,
43 const std::string& name,
44 Controllable::Flag flags)
45 : AutomationControl (s, parameter, desc, l, name, flags)
50 SlavableAutomationControl::~SlavableAutomationControl ()
59 SlavableAutomationControl::get_masters_value_locked () const
62 for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
63 if (mr->second.master()->get_value()) {
70 double v = 1.0; /* the masters function as a scaling factor */
72 for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
73 v *= mr->second.master_ratio ();
81 SlavableAutomationControl::get_value_locked() const
83 /* read or write masters lock must be held */
85 if (_masters.empty()) {
86 return Control::get_double (false, _session.transport_frame());
90 /* for boolean/toggle controls, if this slave OR any master is
91 * enabled, this slave is enabled. So check our own value
92 * first, because if we are enabled, we can return immediately.
94 if (Control::get_double (false, _session.transport_frame())) {
99 return Control::get_double() * get_masters_value_locked ();
102 /** Get the current effective `user' value based on automation state */
104 SlavableAutomationControl::get_value() const
106 bool from_list = _list && boost::dynamic_pointer_cast<AutomationList>(_list)->automation_playback();
108 Glib::Threads::RWLock::ReaderLock lm (master_lock);
110 if (!_masters.empty() && automation_write ()) {
111 /* writing automation takes the fader value as-is, factor out the master */
112 return Control::user_double ();
114 return get_value_locked ();
116 return Control::get_double (true, _session.transport_frame()) * get_masters_value_locked();
121 SlavableAutomationControl::get_masters_curve_locked (framepos_t, framepos_t, float*, framecnt_t) const
123 /* Every AutomationControl needs to implement this as-needed.
125 * This class also provides some convenient methods which
126 * could be used as defaults here (depending on AutomationType)
127 * e.g. masters_curve_multiply()
133 SlavableAutomationControl::masters_curve_multiply (framepos_t start, framepos_t end, float* vec, framecnt_t veclen) const
135 gain_t* scratch = _session.scratch_automation_buffer ();
136 bool from_list = _list && boost::dynamic_pointer_cast<AutomationList>(_list)->automation_playback();
137 bool rv = from_list && list()->curve().rt_safe_get_vector (start, end, scratch, veclen);
139 for (framecnt_t i = 0; i < veclen; ++i) {
140 vec[i] *= scratch[i];
143 apply_gain_to_buffer (vec, veclen, Control::get_double ());
145 if (_masters.empty()) {
149 for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
150 boost::shared_ptr<SlavableAutomationControl> sc
151 = boost::dynamic_pointer_cast<SlavableAutomationControl>(mr->second.master());
153 rv |= sc->masters_curve_multiply (start, end, vec, veclen);
154 apply_gain_to_buffer (vec, veclen, mr->second.val_master_inv ());
160 SlavableAutomationControl::reduce_by_masters_locked (double value, bool ignore_automation_state) const
162 if (!_desc.toggled) {
163 Glib::Threads::RWLock::ReaderLock lm (master_lock);
164 if (!_masters.empty() && (ignore_automation_state || !automation_write ())) {
165 /* need to scale given value by current master's scaling */
166 const double masters_value = get_masters_value_locked();
167 if (masters_value == 0.0) {
170 value /= masters_value;
171 value = std::max (lower(), std::min(upper(), value));
179 SlavableAutomationControl::actually_set_value (double value, PBD::Controllable::GroupControlDisposition gcd)
181 value = reduce_by_masters (value);
182 /* this will call Control::set_double() and emit Changed signals as appropriate */
183 AutomationControl::actually_set_value (value, gcd);
187 SlavableAutomationControl::add_master (boost::shared_ptr<AutomationControl> m)
189 std::pair<Masters::iterator,bool> res;
192 const double master_value = m->get_value();
193 Glib::Threads::RWLock::WriterLock lm (master_lock);
195 pair<PBD::ID,MasterRecord> newpair (m->id(), MasterRecord (boost::weak_ptr<AutomationControl> (m), get_value_locked(), master_value));
196 res = _masters.insert (newpair);
200 /* note that we bind @param m as a weak_ptr<AutomationControl>, thus
201 avoiding holding a reference to the control in the binding
204 m->DropReferences.connect_same_thread (res.first->second.dropped_connection, boost::bind (&SlavableAutomationControl::master_going_away, this, boost::weak_ptr<AutomationControl>(m)));
206 /* Store the connection inside the MasterRecord, so
207 that when we destroy it, the connection is destroyed
208 and we no longer hear about changes to the
211 Note that this also makes it safe to store a
212 boost::shared_ptr<AutomationControl> in the functor,
213 since we know we will destroy the functor when the
214 connection is destroyed, which happens when we
215 disconnect from the master (for any reason).
217 Note that we fix the "from_self" argument that will
218 be given to our own Changed signal to "false",
219 because the change came from the master.
222 m->Changed.connect_same_thread (res.first->second.changed_connection, boost::bind (&SlavableAutomationControl::master_changed, this, _1, _2, boost::weak_ptr<AutomationControl>(m)));
227 /* this will notify everyone that we're now slaved to the master */
228 MasterStatusChange (); /* EMIT SIGNAL */
233 update_boolean_masters_records (m);
237 SlavableAutomationControl::get_boolean_masters () const
242 Glib::Threads::RWLock::ReaderLock lm (master_lock);
243 for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
244 if (mr->second.yn()) {
254 SlavableAutomationControl::update_boolean_masters_records (boost::shared_ptr<AutomationControl> m)
257 /* We may modify a MasterRecord, but we not modify the master
258 * map, so we use a ReaderLock
260 Glib::Threads::RWLock::ReaderLock lm (master_lock);
261 Masters::iterator mi = _masters.find (m->id());
262 if (mi != _masters.end()) {
263 /* update MasterRecord to show whether the master is
264 on/off. We need to store this because the master
265 may change (in the sense of emitting Changed())
266 several times without actually changing the result
267 of ::get_value(). This is a feature of
268 AutomationControls (or even just Controllables,
269 really) which have more than a simple scalar
270 value. For example, the master may be a mute control
271 which can be muted_by_self() and/or
272 muted_by_masters(). When either of those two
273 conditions changes, Changed() will be emitted, even
274 though ::get_value() will return the same value each
275 time (1.0 if either are true, 0.0 if neither is).
277 This provides a way for derived types to check
278 the last known state of a Master when the Master
279 changes. We update it after calling
280 ::master_changed() (though derived types must do
283 mi->second.set_yn (m->get_value());
289 SlavableAutomationControl::master_changed (bool /*from_self*/, GroupControlDisposition gcd, boost::weak_ptr<AutomationControl> wm)
291 boost::shared_ptr<AutomationControl> m = wm.lock ();
293 Glib::Threads::RWLock::ReaderLock lm (master_lock);
294 bool send_signal = handle_master_change (m);
295 lm.release (); // update_boolean_masters_records() takes lock
297 update_boolean_masters_records (m);
299 Changed (false, Controllable::NoGroup); /* EMIT SIGNAL */
304 SlavableAutomationControl::master_going_away (boost::weak_ptr<AutomationControl> wm)
306 boost::shared_ptr<AutomationControl> m = wm.lock();
313 SlavableAutomationControl::scale_automation_callback (double value, double ratio) const
315 /* derived classes can override this and e.g. add/subtract. */
317 // XXX we should use the master's upper/lower as threshold
318 if (ratio >= 0.5 * (upper () - lower ())) {
324 value = std::max (lower(), std::min(upper(), value));
329 SlavableAutomationControl::remove_master (boost::shared_ptr<AutomationControl> m)
331 if (_session.deletion_in_progress()) {
332 /* no reason to care about new values or sending signals */
336 pre_remove_master (m);
338 const double old_val = AutomationControl::get_double();
340 bool update_value = false;
341 double master_ratio = 0;
342 double list_ratio = toggled () ? 0 : 1;
344 boost::shared_ptr<AutomationControl> master;
347 Glib::Threads::RWLock::WriterLock lm (master_lock);
349 Masters::const_iterator mi = _masters.find (m->id ());
351 if (mi != _masters.end()) {
352 master_ratio = mi->second.master_ratio ();
354 master = mi->second.master();
355 list_ratio *= mi->second.val_master_inv ();
358 if (!_masters.erase (m->id())) {
364 /* when un-assigning we apply the master-value permanently */
365 double new_val = old_val * master_ratio;
367 if (old_val != new_val) {
368 AutomationControl::set_double (new_val, Controllable::NoGroup);
371 /* ..and update automation */
373 XMLNode* before = &alist ()->get_state ();
374 if (master->automation_playback () && master->list()) {
375 _list->list_merge (*master->list().get(), boost::bind (&SlavableAutomationControl::scale_automation_callback, this, _1, _2));
376 printf ("y-t %s %f\n", name().c_str(), list_ratio);
377 _list->y_transform (boost::bind (&SlavableAutomationControl::scale_automation_callback, this, _1, list_ratio));
379 // do we need to freeze/thaw the list? probably no: iterators & positions don't change
380 _list->y_transform (boost::bind (&SlavableAutomationControl::scale_automation_callback, this, _1, master_ratio));
382 XMLNode* after = &alist ()->get_state ();
383 if (*before != *after) {
384 _session.begin_reversible_command (string_compose (_("Merge VCA automation into %1"), name ()));
385 _session.commit_reversible_command (alist()->memento_command (before, after));
390 MasterStatusChange (); /* EMIT SIGNAL */
392 /* no need to update boolean masters records, since the MR will have
393 * been removed already.
398 SlavableAutomationControl::clear_masters ()
400 if (_session.deletion_in_progress()) {
401 /* no reason to care about new values or sending signals */
405 const double old_val = AutomationControl::get_double();
408 bool update_value = false;
409 double master_ratio = 0;
410 double list_ratio = toggled () ? 0 : 1;
412 /* null ptr means "all masters */
413 pre_remove_master (boost::shared_ptr<AutomationControl>());
416 Glib::Threads::RWLock::WriterLock lm (master_lock);
417 if (_masters.empty()) {
421 for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
422 boost::shared_ptr<AutomationControl> master = mr->second.master();
423 if (master->automation_playback () && master->list()) {
424 masters.push_back (mr->second.master());
425 list_ratio *= mr->second.val_master_inv ();
427 list_ratio *= mr->second.master_ratio ();
431 master_ratio = get_masters_value_locked ();
437 /* permanently apply masters value */
438 double new_val = old_val * master_ratio;
440 if (old_val != new_val) {
441 AutomationControl::set_double (new_val, Controllable::NoGroup);
444 /* ..and update automation */
446 XMLNode* before = &alist ()->get_state ();
447 if (!masters.empty()) {
448 for (ControlList::const_iterator m = masters.begin(); m != masters.end(); ++m) {
449 _list->list_merge (*(*m)->list().get(), boost::bind (&SlavableAutomationControl::scale_automation_callback, this, _1, _2));
451 _list->y_transform (boost::bind (&SlavableAutomationControl::scale_automation_callback, this, _1, list_ratio));
453 _list->y_transform (boost::bind (&SlavableAutomationControl::scale_automation_callback, this, _1, master_ratio));
455 XMLNode* after = &alist ()->get_state ();
456 if (*before != *after) {
457 _session.begin_reversible_command (string_compose (_("Merge VCA automation into %1"), name ()));
458 _session.commit_reversible_command (alist()->memento_command (before, after));
463 MasterStatusChange (); /* EMIT SIGNAL */
465 /* no need to update boolean masters records, since all MRs will have
466 * been removed already.
471 SlavableAutomationControl::find_next_event_locked (double now, double end, Evoral::ControlEvent& next_event) const
473 if (_masters.empty()) {
477 /* iterate over all masters check their automation lists
478 * for any event between "now" and "end" which is earlier than
479 * next_event.when. If found, set next_event.when and return true.
480 * (see also Automatable::find_next_event)
482 for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
483 boost::shared_ptr<AutomationControl> ac (mr->second.master());
485 boost::shared_ptr<SlavableAutomationControl> sc
486 = boost::dynamic_pointer_cast<SlavableAutomationControl>(ac);
488 if (sc && sc->find_next_event_locked (now, end, next_event)) {
492 Evoral::ControlList::const_iterator i;
493 boost::shared_ptr<const Evoral::ControlList> alist (ac->list());
494 Evoral::ControlEvent cp (now, 0.0f);
499 for (i = lower_bound (alist->begin(), alist->end(), &cp, Evoral::ControlList::time_comparator);
500 i != alist->end() && (*i)->when < end; ++i) {
501 if ((*i)->when > now) {
506 if (i != alist->end() && (*i)->when < end) {
507 if ((*i)->when < next_event.when) {
508 next_event.when = (*i)->when;
518 SlavableAutomationControl::handle_master_change (boost::shared_ptr<AutomationControl>)
520 /* Derived classes can implement this for special cases (e.g. mute).
521 * This method is called with a ReaderLock (master_lock) held.
523 * return true if the changed master value resulted
524 * in a change of the control itself. */
525 return true; // emit Changed
529 SlavableAutomationControl::automation_run (framepos_t start, pframes_t nframes)
531 if (!automation_playback ()) {
537 double val = _list->rt_safe_eval (start, valid);
542 const double thresh = .5 * (_desc.upper - _desc.lower);
543 bool on = (val >= thresh) || (get_masters_value () >= thresh);
544 set_value_unchecked (on ? _desc.upper : _desc.lower);
546 set_value_unchecked (val * get_masters_value ());
551 SlavableAutomationControl::boolean_automation_run_locked (framepos_t start, pframes_t len)
554 if (!_desc.toggled) {
557 for (Masters::iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
558 boost::shared_ptr<AutomationControl> ac (mr->second.master());
559 if (!ac->automation_playback ()) {
562 if (!ac->toggled ()) {
565 boost::shared_ptr<SlavableAutomationControl> sc = boost::dynamic_pointer_cast<MuteControl>(ac);
567 rv |= sc->boolean_automation_run (start, len);
569 boost::shared_ptr<const Evoral::ControlList> alist (ac->list());
571 const bool yn = alist->rt_safe_eval (start, valid) >= 0.5;
575 /* ideally we'd call just master_changed() which calls update_boolean_masters_records()
576 * but that takes the master_lock, which is already locked */
577 if (mr->second.yn() != yn) {
578 rv |= handle_master_change (ac);
579 mr->second.set_yn (yn);
586 SlavableAutomationControl::boolean_automation_run (framepos_t start, pframes_t len)
590 Glib::Threads::RWLock::ReaderLock lm (master_lock);
591 change = boolean_automation_run_locked (start, len);
594 Changed (false, Controllable::NoGroup); /* EMIT SIGNAL */
600 SlavableAutomationControl::slaved_to (boost::shared_ptr<AutomationControl> m) const
602 Glib::Threads::RWLock::ReaderLock lm (master_lock);
603 return _masters.find (m->id()) != _masters.end();
607 SlavableAutomationControl::slaved () const
609 Glib::Threads::RWLock::ReaderLock lm (master_lock);
610 return !_masters.empty();
614 SlavableAutomationControl::MasterRecord::set_state (XMLNode const& n, int)
616 n.get_property (X_("yn"), _yn);
617 n.get_property (X_("val-ctrl"), _val_ctrl);
618 n.get_property (X_("val-master"), _val_master);
623 SlavableAutomationControl::use_saved_master_ratios ()
625 if (!_masters_node) {
629 Glib::Threads::RWLock::ReaderLock lm (master_lock);
631 XMLNodeList nlist = _masters_node->children();
632 XMLNodeIterator niter;
634 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
636 if (!(*niter)->get_property (X_("id"), id_val)) {
639 Masters::iterator mi = _masters.find (id_val);
640 if (mi == _masters.end()) {
643 mi->second.set_state (**niter, Stateful::loading_state_version);
646 delete _masters_node;
654 SlavableAutomationControl::get_state ()
656 XMLNode& node (AutomationControl::get_state());
658 /* store VCA master ratios */
661 Glib::Threads::RWLock::ReaderLock lm (master_lock);
662 if (!_masters.empty()) {
663 XMLNode* masters_node = new XMLNode (X_("masters"));
664 for (Masters::iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
665 XMLNode* mnode = new XMLNode (X_("master"));
666 mnode->set_property (X_("id"), mr->second.master()->id());
669 mnode->set_property (X_("yn"), mr->second.yn());
671 mnode->set_property (X_("val-ctrl"), mr->second.val_ctrl());
672 mnode->set_property (X_("val-master"), mr->second.val_master());
674 masters_node->add_child_nocopy (*mnode);
676 node.add_child_nocopy (*masters_node);
684 SlavableAutomationControl::set_state (XMLNode const& node, int version)
686 XMLNodeList nlist = node.children();
687 XMLNodeIterator niter;
689 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
690 if ((*niter)->name() == X_("masters")) {
691 _masters_node = new XMLNode (**niter);
695 return AutomationControl::set_state (node, version);
699 #endif /* __libardour_slavable_automation_control_h__ */