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 from_list = _list && boost::dynamic_pointer_cast<AutomationList>(_list)->automation_playback();
132 bool rv = from_list && list()->curve().rt_safe_get_vector (start, end, scratch, veclen);
134 for (framecnt_t i = 0; i < veclen; ++i) {
135 vec[i] *= scratch[i];
138 apply_gain_to_buffer (vec, veclen, Control::get_double ());
140 if (_masters.empty()) {
144 for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
145 boost::shared_ptr<SlavableAutomationControl> sc
146 = boost::dynamic_pointer_cast<SlavableAutomationControl>(mr->second.master());
148 rv |= sc->masters_curve_multiply (start, end, vec, veclen);
149 if (mr->second.val_master () != 0) {
150 apply_gain_to_buffer (vec, veclen, 1.f / mr->second.val_master ());
157 SlavableAutomationControl::actually_set_value (double value, PBD::Controllable::GroupControlDisposition gcd)
159 if (!_desc.toggled) {
161 Glib::Threads::RWLock::WriterLock lm (master_lock);
163 if (!_masters.empty()) {
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));
175 /* this will call Control::set_double() and emit Changed signals as appropriate */
176 AutomationControl::actually_set_value (value, gcd);
180 SlavableAutomationControl::add_master (boost::shared_ptr<AutomationControl> m, bool loading)
182 std::pair<Masters::iterator,bool> res;
185 const double master_value = m->get_value();
186 Glib::Threads::RWLock::WriterLock lm (master_lock);
188 pair<PBD::ID,MasterRecord> newpair (m->id(), MasterRecord (boost::weak_ptr<AutomationControl> (m), get_value_locked(), master_value));
189 res = _masters.insert (newpair);
193 /* note that we bind @param m as a weak_ptr<AutomationControl>, thus
194 avoiding holding a reference to the control in the binding
197 m->DropReferences.connect_same_thread (res.first->second.dropped_connection, boost::bind (&SlavableAutomationControl::master_going_away, this, boost::weak_ptr<AutomationControl>(m)));
199 /* Store the connection inside the MasterRecord, so
200 that when we destroy it, the connection is destroyed
201 and we no longer hear about changes to the
204 Note that this also makes it safe to store a
205 boost::shared_ptr<AutomationControl> in the functor,
206 since we know we will destroy the functor when the
207 connection is destroyed, which happens when we
208 disconnect from the master (for any reason).
210 Note that we fix the "from_self" argument that will
211 be given to our own Changed signal to "false",
212 because the change came from the master.
215 m->Changed.connect_same_thread (res.first->second.changed_connection, boost::bind (&SlavableAutomationControl::master_changed, this, _1, _2, boost::weak_ptr<AutomationControl>(m)));
220 /* this will notify everyone that we're now slaved to the master */
221 MasterStatusChange (); /* EMIT SIGNAL */
226 update_boolean_masters_records (m);
230 SlavableAutomationControl::get_boolean_masters () const
235 Glib::Threads::RWLock::ReaderLock lm (master_lock);
236 for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
237 if (mr->second.yn()) {
247 SlavableAutomationControl::update_boolean_masters_records (boost::shared_ptr<AutomationControl> m)
250 /* We may modify a MasterRecord, but we not modify the master
251 * map, so we use a ReaderLock
253 Glib::Threads::RWLock::ReaderLock lm (master_lock);
254 Masters::iterator mi = _masters.find (m->id());
255 if (mi != _masters.end()) {
256 /* update MasterRecord to show whether the master is
257 on/off. We need to store this because the master
258 may change (in the sense of emitting Changed())
259 several times without actually changing the result
260 of ::get_value(). This is a feature of
261 AutomationControls (or even just Controllables,
262 really) which have more than a simple scalar
263 value. For example, the master may be a mute control
264 which can be muted_by_self() and/or
265 muted_by_masters(). When either of those two
266 conditions changes, Changed() will be emitted, even
267 though ::get_value() will return the same value each
268 time (1.0 if either are true, 0.0 if neither is).
270 This provides a way for derived types to check
271 the last known state of a Master when the Master
272 changes. We update it after calling
273 ::master_changed() (though derived types must do
276 mi->second.set_yn (m->get_value());
282 SlavableAutomationControl::master_changed (bool /*from_self*/, GroupControlDisposition gcd, boost::weak_ptr<AutomationControl> wm)
284 boost::shared_ptr<AutomationControl> m = wm.lock ();
286 Glib::Threads::RWLock::ReaderLock lm (master_lock, Glib::Threads::TRY_LOCK);
288 /* boolean_automation_run_locked () special case */
291 bool send_signal = handle_master_change (m);
292 lm.release (); // update_boolean_masters_records() takes lock
294 update_boolean_masters_records (m);
296 Changed (false, Controllable::NoGroup); /* EMIT SIGNAL */
301 SlavableAutomationControl::master_going_away (boost::weak_ptr<AutomationControl> wm)
303 boost::shared_ptr<AutomationControl> m = wm.lock();
310 SlavableAutomationControl::remove_master (boost::shared_ptr<AutomationControl> m)
312 if (_session.deletion_in_progress()) {
313 /* no reason to care about new values or sending signals */
317 pre_remove_master (m);
318 double new_val = AutomationControl::get_double();
319 const double old_val = new_val;
322 Glib::Threads::RWLock::WriterLock lm (master_lock);
324 Masters::const_iterator mi = _masters.find (m->id ());
326 /* when un-assigning we apply the master-value permanently */
327 if (mi != _masters.end()) {
328 new_val *= mi->second.master_ratio ();
331 if (!_masters.erase (m->id())) {
336 if (old_val != new_val) {
337 AutomationControl::set_double (new_val, Controllable::NoGroup);
340 MasterStatusChange (); /* EMIT SIGNAL */
342 /* no need to update boolean masters records, since the MR will have
343 * been removed already.
348 SlavableAutomationControl::clear_masters ()
350 if (_session.deletion_in_progress()) {
351 /* no reason to care about new values or sending signals */
355 double new_val = AutomationControl::get_double();
356 const double old_val = new_val;
358 /* null ptr means "all masters */
359 pre_remove_master (boost::shared_ptr<AutomationControl>());
362 Glib::Threads::RWLock::WriterLock lm (master_lock);
363 if (_masters.empty()) {
366 /* permanently apply masters value */
367 new_val *= get_masters_value_locked ();
372 if (old_val != new_val) {
373 AutomationControl::set_double (new_val, Controllable::NoGroup);
375 MasterStatusChange (); /* EMIT SIGNAL */
377 /* no need to update boolean masters records, since all MRs will have
378 * been removed already.
383 SlavableAutomationControl::find_next_event_locked (double now, double end, Evoral::ControlEvent& next_event) const
385 if (_masters.empty()) {
389 /* iterate over all masters check their automation lists
390 * for any event between "now" and "end" which is earlier than
391 * next_event.when. If found, set next_event.when and return true.
392 * (see also Automatable::find_next_event)
394 for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
395 boost::shared_ptr<AutomationControl> ac (mr->second.master());
397 boost::shared_ptr<SlavableAutomationControl> sc
398 = boost::dynamic_pointer_cast<SlavableAutomationControl>(ac);
400 if (sc && sc->find_next_event_locked (now, end, next_event)) {
404 Evoral::ControlList::const_iterator i;
405 boost::shared_ptr<const Evoral::ControlList> alist (ac->list());
406 Evoral::ControlEvent cp (now, 0.0f);
411 for (i = lower_bound (alist->begin(), alist->end(), &cp, Evoral::ControlList::time_comparator);
412 i != alist->end() && (*i)->when < end; ++i) {
413 if ((*i)->when > now) {
418 if (i != alist->end() && (*i)->when < end) {
419 if ((*i)->when < next_event.when) {
420 next_event.when = (*i)->when;
430 SlavableAutomationControl::handle_master_change (boost::shared_ptr<AutomationControl>)
432 /* Derived classes can implement this for special cases (e.g. mute).
433 * This method is called with a ReaderLock (master_lock) held.
435 * return true if the changed master value resulted
436 * in a change of the control itself. */
437 return true; // emit Changed
441 SlavableAutomationControl::boolean_automation_run_locked (framepos_t start, pframes_t len)
444 if (!_desc.toggled) {
447 for (Masters::iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
448 boost::shared_ptr<AutomationControl> ac (mr->second.master());
449 if (!ac->automation_playback ()) {
452 if (!ac->toggled ()) {
455 boost::shared_ptr<SlavableAutomationControl> sc = boost::dynamic_pointer_cast<MuteControl>(ac);
457 rv |= sc->boolean_automation_run (start, len);
459 boost::shared_ptr<const Evoral::ControlList> alist (ac->list());
461 const bool yn = alist->rt_safe_eval (start, valid) >= 0.5;
465 /* ideally we'd call just master_changed() which calls update_boolean_masters_records()
466 * but that takes the master_lock, which is already locked */
467 if (mr->second.yn() != yn) {
468 rv |= handle_master_change (ac);
469 mr->second.set_yn (yn);
470 /* notify the GUI, without recursion:
471 * master_changed() above will ignore the change if the lock is held.
473 ac->set_value_unchecked (yn ? 1. : 0.);
474 ac->Changed (false, Controllable::NoGroup); /* EMIT SIGNAL */
481 SlavableAutomationControl::boolean_automation_run (framepos_t start, pframes_t len)
485 Glib::Threads::RWLock::ReaderLock lm (master_lock);
486 change = boolean_automation_run_locked (start, len);
489 Changed (false, Controllable::NoGroup); /* EMIT SIGNAL */
495 SlavableAutomationControl::slaved_to (boost::shared_ptr<AutomationControl> m) const
497 Glib::Threads::RWLock::ReaderLock lm (master_lock);
498 return _masters.find (m->id()) != _masters.end();
502 SlavableAutomationControl::slaved () const
504 Glib::Threads::RWLock::ReaderLock lm (master_lock);
505 return !_masters.empty();
509 SlavableAutomationControl::MasterRecord::set_state (XMLNode const& n, int)
511 n.get_property (X_("yn"), _yn);
512 n.get_property (X_("val-ctrl"), _val_ctrl);
513 n.get_property (X_("val-master"), _val_master);
518 SlavableAutomationControl::use_saved_master_ratios ()
520 if (!_masters_node) {
524 Glib::Threads::RWLock::ReaderLock lm (master_lock);
526 XMLNodeList nlist = _masters_node->children();
527 XMLNodeIterator niter;
529 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
531 if (!(*niter)->get_property (X_("id"), id_val)) {
534 Masters::iterator mi = _masters.find (id_val);
535 if (mi == _masters.end()) {
538 mi->second.set_state (**niter, Stateful::loading_state_version);
541 delete _masters_node;
549 SlavableAutomationControl::get_state ()
551 XMLNode& node (AutomationControl::get_state());
553 /* store VCA master ratios */
556 Glib::Threads::RWLock::ReaderLock lm (master_lock);
557 if (!_masters.empty()) {
558 XMLNode* masters_node = new XMLNode (X_("masters"));
559 for (Masters::iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
560 XMLNode* mnode = new XMLNode (X_("master"));
561 mnode->set_property (X_("id"), mr->second.master()->id());
564 mnode->set_property (X_("yn"), mr->second.yn());
566 mnode->set_property (X_("val-ctrl"), mr->second.val_ctrl());
567 mnode->set_property (X_("val-master"), mr->second.val_master());
569 masters_node->add_child_nocopy (*mnode);
571 node.add_child_nocopy (*masters_node);
579 SlavableAutomationControl::set_state (XMLNode const& node, int version)
581 XMLNodeList nlist = node.children();
582 XMLNodeIterator niter;
584 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
585 if ((*niter)->name() == X_("masters")) {
586 _masters_node = new XMLNode (**niter);
590 return AutomationControl::set_state (node, version);
594 #endif /* __libardour_slavable_automation_control_h__ */