2 * Copyright (C) 2016-2017 Paul Davis <paul@linuxaudiosystems.com>
3 * Copyright (C) 2017-2018 Robin Gareus <robin@gareus.org>
4 * Copyright (C) 2017 Tim Mayberry <mojofunk@gmail.com>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 #ifndef __libardour_slavable_automation_control_h__
22 #define __libardour_slavable_automation_control_h__
24 #include "pbd/enumwriter.h"
25 #include "pbd/error.h"
26 #include "pbd/memento_command.h"
27 #include "pbd/types_convert.h"
29 #include "evoral/Curve.hpp"
31 #include "ardour/audioengine.h"
32 #include "ardour/runtime_functions.h"
33 #include "ardour/slavable_automation_control.h"
34 #include "ardour/session.h"
39 using namespace ARDOUR;
42 SlavableAutomationControl::SlavableAutomationControl(ARDOUR::Session& s,
43 const Evoral::Parameter& parameter,
44 const ParameterDescriptor& desc,
45 boost::shared_ptr<ARDOUR::AutomationList> l,
46 const std::string& name,
47 Controllable::Flag flags)
48 : AutomationControl (s, parameter, desc, l, name, flags)
53 SlavableAutomationControl::~SlavableAutomationControl ()
62 SlavableAutomationControl::get_masters_value_locked () const
65 for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
66 if (mr->second.master()->get_value()) {
73 double v = 1.0; /* the masters function as a scaling factor */
75 for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
76 v *= mr->second.master_ratio ();
84 SlavableAutomationControl::get_value_locked() const
86 /* read or write masters lock must be held */
88 if (_masters.empty()) {
89 return Control::get_double (false, _session.transport_sample());
93 /* for boolean/toggle controls, if this slave OR any master is
94 * enabled, this slave is enabled. So check our own value
95 * first, because if we are enabled, we can return immediately.
97 if (Control::get_double (false, _session.transport_sample())) {
102 return Control::get_double() * get_masters_value_locked ();
105 /** Get the current effective `user' value based on automation state */
107 SlavableAutomationControl::get_value() const
109 bool from_list = _list && boost::dynamic_pointer_cast<AutomationList>(_list)->automation_playback();
111 Glib::Threads::RWLock::ReaderLock lm (master_lock);
113 if (!_masters.empty() && automation_write ()) {
114 /* writing automation takes the fader value as-is, factor out the master */
115 return Control::user_double ();
117 return get_value_locked ();
119 return Control::get_double (true, _session.transport_sample()) * get_masters_value_locked();
124 SlavableAutomationControl::get_masters_curve_locked (samplepos_t, samplepos_t, float*, samplecnt_t) const
126 /* Every AutomationControl needs to implement this as-needed.
128 * This class also provides some convenient methods which
129 * could be used as defaults here (depending on AutomationType)
130 * e.g. masters_curve_multiply()
136 SlavableAutomationControl::masters_curve_multiply (samplepos_t start, samplepos_t end, float* vec, samplecnt_t veclen) const
138 gain_t* scratch = _session.scratch_automation_buffer ();
139 bool from_list = _list && boost::dynamic_pointer_cast<AutomationList>(_list)->automation_playback();
140 bool rv = from_list && list()->curve().rt_safe_get_vector (start, end, scratch, veclen);
142 for (samplecnt_t i = 0; i < veclen; ++i) {
143 vec[i] *= scratch[i];
146 apply_gain_to_buffer (vec, veclen, Control::get_double ());
148 if (_masters.empty()) {
152 for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
153 boost::shared_ptr<SlavableAutomationControl> sc
154 = boost::dynamic_pointer_cast<SlavableAutomationControl>(mr->second.master());
156 rv |= sc->masters_curve_multiply (start, end, vec, veclen);
157 apply_gain_to_buffer (vec, veclen, mr->second.val_master_inv ());
163 SlavableAutomationControl::reduce_by_masters_locked (double value, bool ignore_automation_state) const
165 if (!_desc.toggled) {
166 Glib::Threads::RWLock::ReaderLock lm (master_lock);
167 if (!_masters.empty() && (ignore_automation_state || !automation_write ())) {
168 /* need to scale given value by current master's scaling */
169 const double masters_value = get_masters_value_locked();
170 if (masters_value == 0.0) {
173 value /= masters_value;
174 value = std::max (lower(), std::min(upper(), value));
182 SlavableAutomationControl::actually_set_value (double value, PBD::Controllable::GroupControlDisposition gcd)
184 value = reduce_by_masters (value);
185 /* this will call Control::set_double() and emit Changed signals as appropriate */
186 AutomationControl::actually_set_value (value, gcd);
190 SlavableAutomationControl::add_master (boost::shared_ptr<AutomationControl> m)
192 std::pair<Masters::iterator,bool> res;
195 const double master_value = m->get_value();
196 Glib::Threads::RWLock::WriterLock lm (master_lock);
198 pair<PBD::ID,MasterRecord> newpair (m->id(), MasterRecord (boost::weak_ptr<AutomationControl> (m), get_value_locked(), master_value));
199 res = _masters.insert (newpair);
203 /* note that we bind @param m as a weak_ptr<AutomationControl>, thus
204 avoiding holding a reference to the control in the binding
207 m->DropReferences.connect_same_thread (res.first->second.dropped_connection, boost::bind (&SlavableAutomationControl::master_going_away, this, boost::weak_ptr<AutomationControl>(m)));
209 /* Store the connection inside the MasterRecord, so
210 that when we destroy it, the connection is destroyed
211 and we no longer hear about changes to the
214 Note that this also makes it safe to store a
215 boost::shared_ptr<AutomationControl> in the functor,
216 since we know we will destroy the functor when the
217 connection is destroyed, which happens when we
218 disconnect from the master (for any reason).
220 Note that we fix the "from_self" argument that will
221 be given to our own Changed signal to "false",
222 because the change came from the master.
225 m->Changed.connect_same_thread (res.first->second.changed_connection, boost::bind (&SlavableAutomationControl::master_changed, this, _1, _2, boost::weak_ptr<AutomationControl>(m)));
230 /* this will notify everyone that we're now slaved to the master */
231 MasterStatusChange (); /* EMIT SIGNAL */
236 update_boolean_masters_records (m);
240 SlavableAutomationControl::get_boolean_masters () const
245 Glib::Threads::RWLock::ReaderLock lm (master_lock);
246 for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
247 if (mr->second.yn()) {
257 SlavableAutomationControl::update_boolean_masters_records (boost::shared_ptr<AutomationControl> m)
260 /* We may modify a MasterRecord, but we not modify the master
261 * map, so we use a ReaderLock
263 Glib::Threads::RWLock::ReaderLock lm (master_lock);
264 Masters::iterator mi = _masters.find (m->id());
265 if (mi != _masters.end()) {
266 /* update MasterRecord to show whether the master is
267 on/off. We need to store this because the master
268 may change (in the sense of emitting Changed())
269 several times without actually changing the result
270 of ::get_value(). This is a feature of
271 AutomationControls (or even just Controllables,
272 really) which have more than a simple scalar
273 value. For example, the master may be a mute control
274 which can be muted_by_self() and/or
275 muted_by_masters(). When either of those two
276 conditions changes, Changed() will be emitted, even
277 though ::get_value() will return the same value each
278 time (1.0 if either are true, 0.0 if neither is).
280 This provides a way for derived types to check
281 the last known state of a Master when the Master
282 changes. We update it after calling
283 ::master_changed() (though derived types must do
286 mi->second.set_yn (m->get_value());
292 SlavableAutomationControl::master_changed (bool /*from_self*/, GroupControlDisposition gcd, boost::weak_ptr<AutomationControl> wm)
294 boost::shared_ptr<AutomationControl> m = wm.lock ();
296 Glib::Threads::RWLock::ReaderLock lm (master_lock);
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 // XXX we should use the master's upper/lower as threshold
321 if (ratio >= 0.5 * (upper () - lower ())) {
327 value = std::max (lower(), std::min(upper(), value));
332 SlavableAutomationControl::remove_master (boost::shared_ptr<AutomationControl> m)
334 if (_session.deletion_in_progress()) {
335 /* no reason to care about new values or sending signals */
339 pre_remove_master (m);
341 const double old_val = AutomationControl::get_double();
343 bool update_value = false;
344 double master_ratio = 0;
345 double list_ratio = toggled () ? 0 : 1;
347 boost::shared_ptr<AutomationControl> master;
350 Glib::Threads::RWLock::WriterLock lm (master_lock);
352 Masters::const_iterator mi = _masters.find (m->id ());
354 if (mi != _masters.end()) {
355 master_ratio = mi->second.master_ratio ();
357 master = mi->second.master();
358 list_ratio *= mi->second.val_master_inv ();
361 if (!_masters.erase (m->id())) {
367 /* when un-assigning we apply the master-value permanently */
368 double new_val = old_val * master_ratio;
370 if (old_val != new_val) {
371 AutomationControl::set_double (new_val, Controllable::NoGroup);
374 /* ..and update automation */
376 XMLNode* before = &alist ()->get_state ();
377 if (master->automation_playback () && master->list()) {
378 _list->list_merge (*master->list().get(), boost::bind (&SlavableAutomationControl::scale_automation_callback, this, _1, _2));
379 printf ("y-t %s %f\n", name().c_str(), list_ratio);
380 _list->y_transform (boost::bind (&SlavableAutomationControl::scale_automation_callback, this, _1, list_ratio));
382 // do we need to freeze/thaw the list? probably no: iterators & positions don't change
383 _list->y_transform (boost::bind (&SlavableAutomationControl::scale_automation_callback, this, _1, master_ratio));
385 XMLNode* after = &alist ()->get_state ();
386 if (*before != *after) {
387 _session.begin_reversible_command (string_compose (_("Merge VCA automation into %1"), name ()));
388 _session.commit_reversible_command (alist()->memento_command (before, after));
393 MasterStatusChange (); /* EMIT SIGNAL */
395 /* no need to update boolean masters records, since the MR will have
396 * been removed already.
401 SlavableAutomationControl::clear_masters ()
403 if (_session.deletion_in_progress()) {
404 /* no reason to care about new values or sending signals */
408 const double old_val = AutomationControl::get_double();
411 bool update_value = false;
412 double master_ratio = 0;
413 double list_ratio = toggled () ? 0 : 1;
415 /* null ptr means "all masters */
416 pre_remove_master (boost::shared_ptr<AutomationControl>());
419 Glib::Threads::RWLock::WriterLock lm (master_lock);
420 if (_masters.empty()) {
424 for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
425 boost::shared_ptr<AutomationControl> master = mr->second.master();
426 if (master->automation_playback () && master->list()) {
427 masters.push_back (mr->second.master());
428 list_ratio *= mr->second.val_master_inv ();
430 list_ratio *= mr->second.master_ratio ();
434 master_ratio = get_masters_value_locked ();
440 /* permanently apply masters value */
441 double new_val = old_val * master_ratio;
443 if (old_val != new_val) {
444 AutomationControl::set_double (new_val, Controllable::NoGroup);
447 /* ..and update automation */
449 XMLNode* before = &alist ()->get_state ();
450 if (!masters.empty()) {
451 for (ControlList::const_iterator m = masters.begin(); m != masters.end(); ++m) {
452 _list->list_merge (*(*m)->list().get(), boost::bind (&SlavableAutomationControl::scale_automation_callback, this, _1, _2));
454 _list->y_transform (boost::bind (&SlavableAutomationControl::scale_automation_callback, this, _1, list_ratio));
456 _list->y_transform (boost::bind (&SlavableAutomationControl::scale_automation_callback, this, _1, master_ratio));
458 XMLNode* after = &alist ()->get_state ();
459 if (*before != *after) {
460 _session.begin_reversible_command (string_compose (_("Merge VCA automation into %1"), name ()));
461 _session.commit_reversible_command (alist()->memento_command (before, after));
466 MasterStatusChange (); /* EMIT SIGNAL */
468 /* no need to update boolean masters records, since all MRs will have
469 * been removed already.
474 SlavableAutomationControl::find_next_event_locked (double now, double end, Evoral::ControlEvent& next_event) const
476 if (_masters.empty()) {
480 /* iterate over all masters check their automation lists
481 * for any event between "now" and "end" which is earlier than
482 * next_event.when. If found, set next_event.when and return true.
483 * (see also Automatable::find_next_event)
485 for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
486 boost::shared_ptr<AutomationControl> ac (mr->second.master());
488 boost::shared_ptr<SlavableAutomationControl> sc
489 = boost::dynamic_pointer_cast<SlavableAutomationControl>(ac);
491 if (sc && sc->find_next_event_locked (now, end, next_event)) {
495 Evoral::ControlList::const_iterator i;
496 boost::shared_ptr<const Evoral::ControlList> alist (ac->list());
497 Evoral::ControlEvent cp (now, 0.0f);
502 for (i = lower_bound (alist->begin(), alist->end(), &cp, Evoral::ControlList::time_comparator);
503 i != alist->end() && (*i)->when < end; ++i) {
504 if ((*i)->when > now) {
509 if (i != alist->end() && (*i)->when < end) {
510 if ((*i)->when < next_event.when) {
511 next_event.when = (*i)->when;
521 SlavableAutomationControl::handle_master_change (boost::shared_ptr<AutomationControl>)
523 /* Derived classes can implement this for special cases (e.g. mute).
524 * This method is called with a ReaderLock (master_lock) held.
526 * return true if the changed master value resulted
527 * in a change of the control itself. */
528 return true; // emit Changed
532 SlavableAutomationControl::automation_run (samplepos_t start, pframes_t nframes)
534 if (!automation_playback ()) {
540 double val = _list->rt_safe_eval (start, valid);
545 const double thresh = .5 * (_desc.upper - _desc.lower);
546 bool on = (val >= thresh) || (get_masters_value () >= thresh);
547 set_value_unchecked (on ? _desc.upper : _desc.lower);
549 set_value_unchecked (val * get_masters_value ());
554 SlavableAutomationControl::boolean_automation_run_locked (samplepos_t start, pframes_t len)
557 if (!_desc.toggled) {
560 for (Masters::iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
561 boost::shared_ptr<AutomationControl> ac (mr->second.master());
562 if (!ac->automation_playback ()) {
565 if (!ac->toggled ()) {
568 boost::shared_ptr<SlavableAutomationControl> sc = boost::dynamic_pointer_cast<MuteControl>(ac);
570 rv |= sc->boolean_automation_run (start, len);
572 boost::shared_ptr<const Evoral::ControlList> alist (ac->list());
574 const bool yn = alist->rt_safe_eval (start, valid) >= 0.5;
578 /* ideally we'd call just master_changed() which calls update_boolean_masters_records()
579 * but that takes the master_lock, which is already locked */
580 if (mr->second.yn() != yn) {
581 rv |= handle_master_change (ac);
582 mr->second.set_yn (yn);
589 SlavableAutomationControl::boolean_automation_run (samplepos_t start, pframes_t len)
593 Glib::Threads::RWLock::ReaderLock lm (master_lock);
594 change = boolean_automation_run_locked (start, len);
597 Changed (false, Controllable::NoGroup); /* EMIT SIGNAL */
603 SlavableAutomationControl::slaved_to (boost::shared_ptr<AutomationControl> m) const
605 Glib::Threads::RWLock::ReaderLock lm (master_lock);
606 return _masters.find (m->id()) != _masters.end();
610 SlavableAutomationControl::slaved () const
612 Glib::Threads::RWLock::ReaderLock lm (master_lock);
613 return !_masters.empty();
617 SlavableAutomationControl::MasterRecord::set_state (XMLNode const& n, int)
619 n.get_property (X_("yn"), _yn);
620 n.get_property (X_("val-ctrl"), _val_ctrl);
621 n.get_property (X_("val-master"), _val_master);
626 SlavableAutomationControl::use_saved_master_ratios ()
628 if (!_masters_node) {
632 Glib::Threads::RWLock::ReaderLock lm (master_lock);
634 XMLNodeList nlist = _masters_node->children();
635 XMLNodeIterator niter;
637 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
639 if (!(*niter)->get_property (X_("id"), id_val)) {
642 Masters::iterator mi = _masters.find (id_val);
643 if (mi == _masters.end()) {
646 mi->second.set_state (**niter, Stateful::loading_state_version);
649 delete _masters_node;
657 SlavableAutomationControl::get_state ()
659 XMLNode& node (AutomationControl::get_state());
661 /* store VCA master ratios */
664 Glib::Threads::RWLock::ReaderLock lm (master_lock);
665 if (!_masters.empty()) {
666 XMLNode* masters_node = new XMLNode (X_("masters"));
667 for (Masters::iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
668 XMLNode* mnode = new XMLNode (X_("master"));
669 mnode->set_property (X_("id"), mr->second.master()->id());
672 mnode->set_property (X_("yn"), mr->second.yn());
674 mnode->set_property (X_("val-ctrl"), mr->second.val_ctrl());
675 mnode->set_property (X_("val-master"), mr->second.val_master());
677 masters_node->add_child_nocopy (*mnode);
679 node.add_child_nocopy (*masters_node);
687 SlavableAutomationControl::set_state (XMLNode const& node, int version)
689 XMLNodeList nlist = node.children();
690 XMLNodeIterator niter;
692 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
693 if ((*niter)->name() == X_("masters")) {
694 _masters_node = new XMLNode (**niter);
698 return AutomationControl::set_state (node, version);
702 #endif /* __libardour_slavable_automation_control_h__ */