adde7cdac34bc45653d00a27564f08d6e4878f0d
[ardour.git] / libs / ardour / slavable_automation_control.cc
1 /*
2     Copyright (C) 2016 Paul Davis
3
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)
7     any later version.
8
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
12     for more details.
13
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.
17 */
18
19 #ifndef __libardour_slavable_automation_control_h__
20 #define __libardour_slavable_automation_control_h__
21
22 #include "pbd/enumwriter.h"
23 #include "pbd/error.h"
24 #include "pbd/types_convert.h"
25 #include "pbd/i18n.h"
26
27 #include "evoral/Curve.hpp"
28
29 #include "ardour/audioengine.h"
30 #include "ardour/runtime_functions.h"
31 #include "ardour/slavable_automation_control.h"
32 #include "ardour/session.h"
33
34 using namespace std;
35 using namespace ARDOUR;
36 using namespace PBD;
37
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)
45         , _masters_node (0)
46 {
47 }
48
49 SlavableAutomationControl::~SlavableAutomationControl ()
50 {
51         if (_masters_node) {
52                 delete _masters_node;
53                 _masters_node = 0;
54         }
55 }
56
57 double
58 SlavableAutomationControl::get_masters_value_locked () const
59 {
60         if (_desc.toggled) {
61                 for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
62                         if (mr->second.master()->get_value()) {
63                                 return _desc.upper;
64                         }
65                 }
66                 return _desc.lower;
67         } else {
68
69                 double v = 1.0; /* the masters function as a scaling factor */
70
71                 for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
72                         v *= mr->second.master_ratio ();
73                 }
74
75                 return v;
76         }
77 }
78
79 double
80 SlavableAutomationControl::get_value_locked() const
81 {
82         /* read or write masters lock must be held */
83
84         if (_masters.empty()) {
85                 return Control::get_double (false, _session.transport_frame());
86         }
87
88         if (_desc.toggled) {
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.
92                  */
93                 if (Control::get_double (false, _session.transport_frame())) {
94                         return _desc.upper;
95                 }
96         }
97
98         return Control::get_double() * get_masters_value_locked ();
99 }
100
101 /** Get the current effective `user' value based on automation state */
102 double
103 SlavableAutomationControl::get_value() const
104 {
105         bool from_list = _list && boost::dynamic_pointer_cast<AutomationList>(_list)->automation_playback();
106
107         Glib::Threads::RWLock::ReaderLock lm (master_lock);
108         if (!from_list) {
109                 return get_value_locked ();
110         } else {
111                 return Control::get_double (true, _session.transport_frame()) * get_masters_value_locked();
112         }
113 }
114
115 bool
116 SlavableAutomationControl::get_masters_curve_locked (framepos_t, framepos_t, float*, framecnt_t) const
117 {
118         /* Every AutomationControl needs to implement this as-needed.
119          *
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()
123          */
124         return false;
125 }
126
127 bool
128 SlavableAutomationControl::masters_curve_multiply (framepos_t start, framepos_t end, float* vec, framecnt_t veclen) const
129 {
130         gain_t* scratch = _session.scratch_automation_buffer ();
131         bool rv = list()->curve().rt_safe_get_vector (start, end, scratch, veclen);
132         if (rv) {
133                 for (framecnt_t i = 0; i < veclen; ++i) {
134                         vec[i] *= scratch[i];
135                 }
136         } else {
137                 apply_gain_to_buffer (vec, veclen, Control::get_double ());
138         }
139         if (_masters.empty()) {
140                 return rv;
141         }
142
143         for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
144                 boost::shared_ptr<SlavableAutomationControl> sc
145                         = boost::dynamic_pointer_cast<SlavableAutomationControl>(mr->second.master());
146                 assert (sc);
147                 rv |= sc->masters_curve_multiply (start, end, vec, veclen);
148                 apply_gain_to_buffer (vec, veclen, mr->second.master_ratio ());
149         }
150         return rv;
151 }
152
153 void
154 SlavableAutomationControl::actually_set_value (double value, PBD::Controllable::GroupControlDisposition gcd)
155 {
156         if (!_desc.toggled) {
157
158                 Glib::Threads::RWLock::WriterLock lm (master_lock);
159
160                 if (!_masters.empty()) {
161                         /* need to scale given value by current master's scaling */
162                         const double masters_value = get_masters_value_locked();
163                         if (masters_value == 0.0) {
164                                 value = 0.0;
165                         } else {
166                                 value /= masters_value;
167                                 value = std::max (lower(), std::min(upper(), value));
168                         }
169                 }
170         }
171
172         /* this will call Control::set_double() and emit Changed signals as appropriate */
173         AutomationControl::actually_set_value (value, gcd);
174 }
175
176 void
177 SlavableAutomationControl::add_master (boost::shared_ptr<AutomationControl> m, bool loading)
178 {
179         std::pair<Masters::iterator,bool> res;
180
181         {
182                 const double master_value = m->get_value();
183                 Glib::Threads::RWLock::WriterLock lm (master_lock);
184
185                 pair<PBD::ID,MasterRecord> newpair (m->id(), MasterRecord (boost::weak_ptr<AutomationControl> (m), get_value_locked(), master_value));
186                 res = _masters.insert (newpair);
187
188                 if (res.second) {
189
190                         /* note that we bind @param m as a weak_ptr<AutomationControl>, thus
191                            avoiding holding a reference to the control in the binding
192                            itself.
193                         */
194                         m->DropReferences.connect_same_thread (res.first->second.dropped_connection, boost::bind (&SlavableAutomationControl::master_going_away, this, boost::weak_ptr<AutomationControl>(m)));
195
196                         /* Store the connection inside the MasterRecord, so
197                            that when we destroy it, the connection is destroyed
198                            and we no longer hear about changes to the
199                            AutomationControl.
200
201                            Note that this also makes it safe to store a
202                            boost::shared_ptr<AutomationControl> in the functor,
203                            since we know we will destroy the functor when the
204                            connection is destroyed, which happens when we
205                            disconnect from the master (for any reason).
206
207                            Note that we fix the "from_self" argument that will
208                            be given to our own Changed signal to "false",
209                            because the change came from the master.
210                         */
211
212                         m->Changed.connect_same_thread (res.first->second.changed_connection, boost::bind (&SlavableAutomationControl::master_changed, this, _1, _2, boost::weak_ptr<AutomationControl>(m)));
213                 }
214         }
215
216         if (res.second) {
217                 /* this will notify everyone that we're now slaved to the master */
218                 MasterStatusChange (); /* EMIT SIGNAL */
219         }
220
221         post_add_master (m);
222
223         update_boolean_masters_records (m);
224 }
225
226 int32_t
227 SlavableAutomationControl::get_boolean_masters () const
228 {
229         int32_t n = 0;
230
231         if (_desc.toggled) {
232                 Glib::Threads::RWLock::ReaderLock lm (master_lock);
233                 for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
234                         if (mr->second.yn()) {
235                                 ++n;
236                         }
237                 }
238         }
239
240         return n;
241 }
242
243 void
244 SlavableAutomationControl::update_boolean_masters_records (boost::shared_ptr<AutomationControl> m)
245 {
246         if (_desc.toggled) {
247                 /* We may modify a MasterRecord, but we not modify the master
248                  * map, so we use a ReaderLock
249                  */
250                 Glib::Threads::RWLock::ReaderLock lm (master_lock);
251                 Masters::iterator mi = _masters.find (m->id());
252                 if (mi != _masters.end()) {
253                         /* update MasterRecord to show whether the master is
254                            on/off. We need to store this because the master
255                            may change (in the sense of emitting Changed())
256                            several times without actually changing the result
257                            of ::get_value(). This is a feature of
258                            AutomationControls (or even just Controllables,
259                            really) which have more than a simple scalar
260                            value. For example, the master may be a mute control
261                            which can be muted_by_self() and/or
262                            muted_by_masters(). When either of those two
263                            conditions changes, Changed() will be emitted, even
264                            though ::get_value() will return the same value each
265                            time (1.0 if either are true, 0.0 if neither is).
266
267                            This provides a way for derived types to check
268                            the last known state of a Master when the Master
269                            changes. We update it after calling
270                            ::master_changed() (though derived types must do
271                            this themselves).
272                         */
273                         mi->second.set_yn (m->get_value());
274                 }
275         }
276 }
277
278 void
279 SlavableAutomationControl::master_changed (bool /*from_self*/, GroupControlDisposition gcd, boost::weak_ptr<AutomationControl> wm)
280 {
281         boost::shared_ptr<AutomationControl> m = wm.lock ();
282         assert (m);
283         Glib::Threads::RWLock::ReaderLock lm (master_lock, Glib::Threads::TRY_LOCK);
284         if (!lm.locked ()) {
285                 /* boolean_automation_run_locked () special case */
286                 return;
287         }
288         bool send_signal = handle_master_change (m);
289         lm.release (); // update_boolean_masters_records() takes lock
290
291         update_boolean_masters_records (m);
292         if (send_signal) {
293                 Changed (false, Controllable::NoGroup); /* EMIT SIGNAL */
294         }
295 }
296
297 void
298 SlavableAutomationControl::master_going_away (boost::weak_ptr<AutomationControl> wm)
299 {
300         boost::shared_ptr<AutomationControl> m = wm.lock();
301         if (m) {
302                 remove_master (m);
303         }
304 }
305
306 void
307 SlavableAutomationControl::remove_master (boost::shared_ptr<AutomationControl> m)
308 {
309         if (_session.deletion_in_progress()) {
310                 /* no reason to care about new values or sending signals */
311                 return;
312         }
313
314         pre_remove_master (m);
315         double new_val = AutomationControl::get_double();
316         const double old_val = new_val;
317
318         {
319                 Glib::Threads::RWLock::WriterLock lm (master_lock);
320
321                 Masters::const_iterator mi = _masters.find (m->id ());
322
323                 /* when un-assigning we apply the master-value permanently */
324                 if (mi != _masters.end()) {
325                         new_val *= mi->second.master_ratio ();
326                 }
327
328                 if (!_masters.erase (m->id())) {
329                         return;
330                 }
331         }
332
333         if (old_val != new_val) {
334                 AutomationControl::set_double (new_val, Controllable::NoGroup);
335         }
336
337         MasterStatusChange (); /* EMIT SIGNAL */
338
339         /* no need to update boolean masters records, since the MR will have
340          * been removed already.
341          */
342 }
343
344 void
345 SlavableAutomationControl::clear_masters ()
346 {
347         if (_session.deletion_in_progress()) {
348                 /* no reason to care about new values or sending signals */
349                 return;
350         }
351
352         double new_val = AutomationControl::get_double();
353         const double old_val = new_val;
354
355         /* null ptr means "all masters */
356         pre_remove_master (boost::shared_ptr<AutomationControl>());
357
358         {
359                 Glib::Threads::RWLock::WriterLock lm (master_lock);
360                 if (_masters.empty()) {
361                         return;
362                 }
363                 /* permanently apply masters value */
364                 new_val *= get_masters_value_locked ();
365
366                 _masters.clear ();
367         }
368
369         if (old_val != new_val) {
370                 AutomationControl::set_double (new_val, Controllable::NoGroup);
371         }
372         MasterStatusChange (); /* EMIT SIGNAL */
373
374         /* no need to update boolean masters records, since all MRs will have
375          * been removed already.
376          */
377 }
378
379 bool
380 SlavableAutomationControl::find_next_event_locked (double now, double end, Evoral::ControlEvent& next_event) const
381 {
382         if (_masters.empty()) {
383                 return false;
384         }
385         bool rv = false;
386         /* iterate over all masters check their automation lists
387          * for any event between "now" and "end" which is earlier than
388          * next_event.when. If found, set next_event.when and return true.
389          * (see also Automatable::find_next_event)
390          */
391         for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
392                 boost::shared_ptr<AutomationControl> ac (mr->second.master());
393
394                 boost::shared_ptr<SlavableAutomationControl> sc
395                         = boost::dynamic_pointer_cast<SlavableAutomationControl>(ac);
396
397                 if (sc && sc->find_next_event_locked (now, end, next_event)) {
398                         rv = true;
399                 }
400
401                 Evoral::ControlList::const_iterator i;
402                 boost::shared_ptr<const Evoral::ControlList> alist (ac->list());
403                 Evoral::ControlEvent cp (now, 0.0f);
404                 if (!alist) {
405                         continue;
406                 }
407
408                 for (i = lower_bound (alist->begin(), alist->end(), &cp, Evoral::ControlList::time_comparator);
409                      i != alist->end() && (*i)->when < end; ++i) {
410                         if ((*i)->when > now) {
411                                 break;
412                         }
413                 }
414
415                 if (i != alist->end() && (*i)->when < end) {
416                         if ((*i)->when < next_event.when) {
417                                 next_event.when = (*i)->when;
418                                 rv = true;
419                         }
420                 }
421         }
422
423         return rv;
424 }
425
426 bool
427 SlavableAutomationControl::handle_master_change (boost::shared_ptr<AutomationControl>)
428 {
429         /* Derived classes can implement this for special cases (e.g. mute).
430          * This method is called with a ReaderLock (master_lock) held.
431          *
432          * return true if the changed master value resulted
433          * in a change of the control itself. */
434         return true; // emit Changed
435 }
436
437 bool
438 SlavableAutomationControl::boolean_automation_run_locked (framepos_t start, pframes_t len)
439 {
440         bool rv = false;
441         if (!_desc.toggled) {
442                 return false;
443         }
444         for (Masters::iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
445                 boost::shared_ptr<AutomationControl> ac (mr->second.master());
446                 if (!ac->automation_playback ()) {
447                         continue;
448                 }
449                 if (!ac->toggled ()) {
450                         continue;
451                 }
452                 boost::shared_ptr<SlavableAutomationControl> sc = boost::dynamic_pointer_cast<MuteControl>(ac);
453                 if (sc) {
454                         rv |= sc->boolean_automation_run (start, len);
455                 }
456                 boost::shared_ptr<const Evoral::ControlList> alist (ac->list());
457                 bool valid = false;
458                 const bool yn = alist->rt_safe_eval (start, valid) >= 0.5;
459                 if (!valid) {
460                         continue;
461                 }
462                 /* ideally we'd call just master_changed() which calls update_boolean_masters_records()
463                  * but that takes the master_lock, which is already locked */
464                 if (mr->second.yn() != yn) {
465                         rv |= handle_master_change (ac);
466                         mr->second.set_yn (yn);
467                         /* notify the GUI, without recursion:
468                          * master_changed() above will ignore the change if the lock is held.
469                          */
470                         ac->set_value_unchecked (yn ? 1. : 0.);
471                         ac->Changed (false, Controllable::NoGroup); /* EMIT SIGNAL */
472                 }
473         }
474         return rv;
475 }
476
477 bool
478 SlavableAutomationControl::boolean_automation_run (framepos_t start, pframes_t len)
479 {
480         bool change = false;
481         {
482                  Glib::Threads::RWLock::ReaderLock lm (master_lock);
483                  change = boolean_automation_run_locked (start, len);
484         }
485         if (change) {
486                 Changed (false, Controllable::NoGroup); /* EMIT SIGNAL */
487         }
488         return change;
489 }
490
491 bool
492 SlavableAutomationControl::slaved_to (boost::shared_ptr<AutomationControl> m) const
493 {
494         Glib::Threads::RWLock::ReaderLock lm (master_lock);
495         return _masters.find (m->id()) != _masters.end();
496 }
497
498 bool
499 SlavableAutomationControl::slaved () const
500 {
501         Glib::Threads::RWLock::ReaderLock lm (master_lock);
502         return !_masters.empty();
503 }
504
505 int
506 SlavableAutomationControl::MasterRecord::set_state (XMLNode const& n, int)
507 {
508         bool yn;
509         double v;
510         if (n.get_property (X_("yn"), yn)) {
511                 _yn = yn;
512         }
513         if (n.get_property (X_("val-ctrl"), v)) {
514                 _val_ctrl = v;
515         }
516         if (n.get_property (X_("val-master"), v)) {
517                 _val_master = v;
518         }
519         return 0;
520 }
521
522 void
523 SlavableAutomationControl::use_saved_master_ratios ()
524 {
525         if (!_masters_node) {
526                 return;
527         }
528
529         Glib::Threads::RWLock::ReaderLock lm (master_lock);
530
531         XMLNodeList nlist = _masters_node->children();
532         XMLNodeIterator niter;
533
534         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
535                 ID id_val;
536                 if (!(*niter)->get_property (X_("id"), id_val)) {
537                         continue;
538                 }
539                 Masters::iterator mi = _masters.find (id_val);
540                 if (mi == _masters.end()) {
541                         continue;
542                 }
543                 mi->second.set_state (**niter, Stateful::loading_state_version);
544         }
545
546         delete _masters_node;
547         _masters_node = 0;
548
549         return;
550 }
551
552
553 XMLNode&
554 SlavableAutomationControl::get_state ()
555 {
556         XMLNode& node (AutomationControl::get_state());
557
558         /* store VCA master ratios */
559
560         {
561                 Glib::Threads::RWLock::ReaderLock lm (master_lock);
562                 if (!_masters.empty()) {
563                         XMLNode* masters_node = new XMLNode (X_("masters"));
564                         for (Masters::iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
565                                 XMLNode* mnode = new XMLNode (X_("master"));
566                                 mnode->set_property (X_("id"), mr->second.master()->id());
567
568                                 if (_desc.toggled) {
569                                         mnode->set_property (X_("yn"), mr->second.yn());
570                                 } else {
571                                         mnode->set_property (X_("val-ctrl"), mr->second.val_ctrl());
572                                         mnode->set_property (X_("val-master"), mr->second.val_master());
573                                 }
574                                 masters_node->add_child_nocopy (*mnode);
575                                 node.add_child_nocopy (*masters_node);
576                         }
577                 }
578         }
579
580         return node;
581 }
582
583 int
584 SlavableAutomationControl::set_state (XMLNode const& node, int version)
585 {
586         XMLNodeList nlist = node.children();
587         XMLNodeIterator niter;
588
589         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
590                 if ((*niter)->name() == X_("masters")) {
591                         _masters_node = new XMLNode (**niter);
592                 }
593         }
594
595         return AutomationControl::set_state (node, version);
596 }
597
598
599 #endif /* __libardour_slavable_automation_control_h__ */