Special-case VCA at 0 (-inf dB), force gain slaves to -inf dB
[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                 if (!_masters.empty() && automation_write ()) {
110                         /* writing automation takes the fader value as-is, factor out the master */
111                         return Control::user_double ();
112                 }
113                 return get_value_locked ();
114         } else {
115                 return Control::get_double (true, _session.transport_frame()) * get_masters_value_locked();
116         }
117 }
118
119 bool
120 SlavableAutomationControl::get_masters_curve_locked (framepos_t, framepos_t, float*, framecnt_t) const
121 {
122         /* Every AutomationControl needs to implement this as-needed.
123          *
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()
127          */
128         return false;
129 }
130
131 bool
132 SlavableAutomationControl::masters_curve_multiply (framepos_t start, framepos_t end, float* vec, framecnt_t veclen) const
133 {
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);
137         if (rv) {
138                 for (framecnt_t i = 0; i < veclen; ++i) {
139                         vec[i] *= scratch[i];
140                 }
141         } else {
142                 apply_gain_to_buffer (vec, veclen, Control::get_double ());
143         }
144         if (_masters.empty()) {
145                 return rv;
146         }
147
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());
151                 assert (sc);
152                 rv |= sc->masters_curve_multiply (start, end, vec, veclen);
153                 apply_gain_to_buffer (vec, veclen, mr->second.val_master_inv ());
154         }
155         return rv;
156 }
157
158 double
159 SlavableAutomationControl::reduce_by_masters_locked (double value, bool ignore_automation_state) const
160 {
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) {
167                                 value = 0.0;
168                         } else {
169                                 value /= masters_value;
170                                 value = std::max (lower(), std::min(upper(), value));
171                         }
172                 }
173         }
174         return value;
175 }
176
177 void
178 SlavableAutomationControl::actually_set_value (double value, PBD::Controllable::GroupControlDisposition gcd)
179 {
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);
183 }
184
185 void
186 SlavableAutomationControl::add_master (boost::shared_ptr<AutomationControl> m, bool loading)
187 {
188         std::pair<Masters::iterator,bool> res;
189
190         {
191                 const double master_value = m->get_value();
192                 Glib::Threads::RWLock::WriterLock lm (master_lock);
193
194                 pair<PBD::ID,MasterRecord> newpair (m->id(), MasterRecord (boost::weak_ptr<AutomationControl> (m), get_value_locked(), master_value));
195                 res = _masters.insert (newpair);
196
197                 if (res.second) {
198
199                         /* note that we bind @param m as a weak_ptr<AutomationControl>, thus
200                            avoiding holding a reference to the control in the binding
201                            itself.
202                         */
203                         m->DropReferences.connect_same_thread (res.first->second.dropped_connection, boost::bind (&SlavableAutomationControl::master_going_away, this, boost::weak_ptr<AutomationControl>(m)));
204
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
208                            AutomationControl.
209
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).
215
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.
219                         */
220
221                         m->Changed.connect_same_thread (res.first->second.changed_connection, boost::bind (&SlavableAutomationControl::master_changed, this, _1, _2, boost::weak_ptr<AutomationControl>(m)));
222                 }
223         }
224
225         if (res.second) {
226                 /* this will notify everyone that we're now slaved to the master */
227                 MasterStatusChange (); /* EMIT SIGNAL */
228         }
229
230         post_add_master (m);
231
232         update_boolean_masters_records (m);
233 }
234
235 int32_t
236 SlavableAutomationControl::get_boolean_masters () const
237 {
238         int32_t n = 0;
239
240         if (_desc.toggled) {
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()) {
244                                 ++n;
245                         }
246                 }
247         }
248
249         return n;
250 }
251
252 void
253 SlavableAutomationControl::update_boolean_masters_records (boost::shared_ptr<AutomationControl> m)
254 {
255         if (_desc.toggled) {
256                 /* We may modify a MasterRecord, but we not modify the master
257                  * map, so we use a ReaderLock
258                  */
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).
275
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
280                            this themselves).
281                         */
282                         mi->second.set_yn (m->get_value());
283                 }
284         }
285 }
286
287 void
288 SlavableAutomationControl::master_changed (bool /*from_self*/, GroupControlDisposition gcd, boost::weak_ptr<AutomationControl> wm)
289 {
290         boost::shared_ptr<AutomationControl> m = wm.lock ();
291         assert (m);
292         Glib::Threads::RWLock::ReaderLock lm (master_lock, Glib::Threads::TRY_LOCK);
293         if (!lm.locked ()) {
294                 /* boolean_automation_run_locked () special case */
295                 return;
296         }
297         bool send_signal = handle_master_change (m);
298         lm.release (); // update_boolean_masters_records() takes lock
299
300         update_boolean_masters_records (m);
301         if (send_signal) {
302                 Changed (false, Controllable::NoGroup); /* EMIT SIGNAL */
303         }
304 }
305
306 void
307 SlavableAutomationControl::master_going_away (boost::weak_ptr<AutomationControl> wm)
308 {
309         boost::shared_ptr<AutomationControl> m = wm.lock();
310         if (m) {
311                 remove_master (m);
312         }
313 }
314
315 double
316 SlavableAutomationControl::scale_automation_callback (double value, double ratio) const
317 {
318         /* derived classes can override this and e.g. add/subtract. */
319         value *= ratio;
320         value = std::max (lower(), std::min(upper(), value));
321         return value;
322 }
323
324 void
325 SlavableAutomationControl::remove_master (boost::shared_ptr<AutomationControl> m)
326 {
327         if (_session.deletion_in_progress()) {
328                 /* no reason to care about new values or sending signals */
329                 return;
330         }
331
332         pre_remove_master (m);
333
334         const double old_val = AutomationControl::get_double();
335
336         bool update_value = false;
337         double master_ratio = 0;
338         double list_ratio = 1;
339
340         boost::shared_ptr<AutomationControl> master;
341
342         {
343                 Glib::Threads::RWLock::WriterLock lm (master_lock);
344
345                 Masters::const_iterator mi = _masters.find (m->id ());
346
347                 if (mi != _masters.end()) {
348                         master_ratio = mi->second.master_ratio ();
349                         update_value = true;
350                         master = mi->second.master();
351                         list_ratio *= mi->second.val_master_inv ();
352                 }
353
354                 if (!_masters.erase (m->id())) {
355                         return;
356                 }
357         }
358
359         if (update_value) {
360                 /* when un-assigning we apply the master-value permanently */
361                 double new_val = old_val * master_ratio;
362
363                 if (old_val != new_val) {
364                         AutomationControl::set_double (new_val, Controllable::NoGroup);
365                 }
366
367                 /* ..and update automation */
368                 if (_list) {
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));
372                         } else {
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));
375                         }
376                 }
377         }
378
379         MasterStatusChange (); /* EMIT SIGNAL */
380
381         /* no need to update boolean masters records, since the MR will have
382          * been removed already.
383          */
384 }
385
386 void
387 SlavableAutomationControl::clear_masters ()
388 {
389         if (_session.deletion_in_progress()) {
390                 /* no reason to care about new values or sending signals */
391                 return;
392         }
393
394         const double old_val = AutomationControl::get_double();
395
396         ControlList masters;
397         bool update_value = false;
398         double master_ratio = 0;
399         double list_ratio = 1;
400
401         /* null ptr means "all masters */
402         pre_remove_master (boost::shared_ptr<AutomationControl>());
403
404         {
405                 Glib::Threads::RWLock::WriterLock lm (master_lock);
406                 if (_masters.empty()) {
407                         return;
408                 }
409
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 ();
415                         } else {
416                                 list_ratio *= mr->second.master_ratio ();
417                         }
418                 }
419
420                 master_ratio = get_masters_value_locked ();
421                 update_value = true;
422                 _masters.clear ();
423         }
424
425         if (update_value) {
426                 /* permanently apply masters value */
427                         double new_val = old_val * master_ratio;
428
429                         if (old_val != new_val) {
430                                 AutomationControl::set_double (new_val, Controllable::NoGroup);
431                         }
432
433                         /* ..and update automation */
434                         if (_list) {
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));
438                                         }
439                                         _list->y_transform (boost::bind (&SlavableAutomationControl::scale_automation_callback, this, _1, list_ratio));
440                                 } else {
441                                         _list->y_transform (boost::bind (&SlavableAutomationControl::scale_automation_callback, this, _1, master_ratio));
442                                 }
443                         }
444         }
445
446         MasterStatusChange (); /* EMIT SIGNAL */
447
448         /* no need to update boolean masters records, since all MRs will have
449          * been removed already.
450          */
451 }
452
453 bool
454 SlavableAutomationControl::find_next_event_locked (double now, double end, Evoral::ControlEvent& next_event) const
455 {
456         if (_masters.empty()) {
457                 return false;
458         }
459         bool rv = false;
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)
464          */
465         for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
466                 boost::shared_ptr<AutomationControl> ac (mr->second.master());
467
468                 boost::shared_ptr<SlavableAutomationControl> sc
469                         = boost::dynamic_pointer_cast<SlavableAutomationControl>(ac);
470
471                 if (sc && sc->find_next_event_locked (now, end, next_event)) {
472                         rv = true;
473                 }
474
475                 Evoral::ControlList::const_iterator i;
476                 boost::shared_ptr<const Evoral::ControlList> alist (ac->list());
477                 Evoral::ControlEvent cp (now, 0.0f);
478                 if (!alist) {
479                         continue;
480                 }
481
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) {
485                                 break;
486                         }
487                 }
488
489                 if (i != alist->end() && (*i)->when < end) {
490                         if ((*i)->when < next_event.when) {
491                                 next_event.when = (*i)->when;
492                                 rv = true;
493                         }
494                 }
495         }
496
497         return rv;
498 }
499
500 bool
501 SlavableAutomationControl::handle_master_change (boost::shared_ptr<AutomationControl>)
502 {
503         /* Derived classes can implement this for special cases (e.g. mute).
504          * This method is called with a ReaderLock (master_lock) held.
505          *
506          * return true if the changed master value resulted
507          * in a change of the control itself. */
508         return true; // emit Changed
509 }
510
511 bool
512 SlavableAutomationControl::boolean_automation_run_locked (framepos_t start, pframes_t len)
513 {
514         bool rv = false;
515         if (!_desc.toggled) {
516                 return false;
517         }
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 ()) {
521                         continue;
522                 }
523                 if (!ac->toggled ()) {
524                         continue;
525                 }
526                 boost::shared_ptr<SlavableAutomationControl> sc = boost::dynamic_pointer_cast<MuteControl>(ac);
527                 if (sc) {
528                         rv |= sc->boolean_automation_run (start, len);
529                 }
530                 boost::shared_ptr<const Evoral::ControlList> alist (ac->list());
531                 bool valid = false;
532                 const bool yn = alist->rt_safe_eval (start, valid) >= 0.5;
533                 if (!valid) {
534                         continue;
535                 }
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.
543                          */
544                         ac->set_value_unchecked (yn ? 1. : 0.);
545                         ac->Changed (false, Controllable::NoGroup); /* EMIT SIGNAL */
546                 }
547         }
548         return rv;
549 }
550
551 bool
552 SlavableAutomationControl::boolean_automation_run (framepos_t start, pframes_t len)
553 {
554         bool change = false;
555         {
556                  Glib::Threads::RWLock::ReaderLock lm (master_lock);
557                  change = boolean_automation_run_locked (start, len);
558         }
559         if (change) {
560                 Changed (false, Controllable::NoGroup); /* EMIT SIGNAL */
561         }
562         return change;
563 }
564
565 bool
566 SlavableAutomationControl::slaved_to (boost::shared_ptr<AutomationControl> m) const
567 {
568         Glib::Threads::RWLock::ReaderLock lm (master_lock);
569         return _masters.find (m->id()) != _masters.end();
570 }
571
572 bool
573 SlavableAutomationControl::slaved () const
574 {
575         Glib::Threads::RWLock::ReaderLock lm (master_lock);
576         return !_masters.empty();
577 }
578
579 int
580 SlavableAutomationControl::MasterRecord::set_state (XMLNode const& n, int)
581 {
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);
585         return 0;
586 }
587
588 void
589 SlavableAutomationControl::use_saved_master_ratios ()
590 {
591         if (!_masters_node) {
592                 return;
593         }
594
595         Glib::Threads::RWLock::ReaderLock lm (master_lock);
596
597         XMLNodeList nlist = _masters_node->children();
598         XMLNodeIterator niter;
599
600         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
601                 ID id_val;
602                 if (!(*niter)->get_property (X_("id"), id_val)) {
603                         continue;
604                 }
605                 Masters::iterator mi = _masters.find (id_val);
606                 if (mi == _masters.end()) {
607                         continue;
608                 }
609                 mi->second.set_state (**niter, Stateful::loading_state_version);
610         }
611
612         delete _masters_node;
613         _masters_node = 0;
614
615         return;
616 }
617
618
619 XMLNode&
620 SlavableAutomationControl::get_state ()
621 {
622         XMLNode& node (AutomationControl::get_state());
623
624         /* store VCA master ratios */
625
626         {
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());
633
634                                 if (_desc.toggled) {
635                                         mnode->set_property (X_("yn"), mr->second.yn());
636                                 } else {
637                                         mnode->set_property (X_("val-ctrl"), mr->second.val_ctrl());
638                                         mnode->set_property (X_("val-master"), mr->second.val_master());
639                                 }
640                                 masters_node->add_child_nocopy (*mnode);
641                         }
642                         node.add_child_nocopy (*masters_node);
643                 }
644         }
645
646         return node;
647 }
648
649 int
650 SlavableAutomationControl::set_state (XMLNode const& node, int version)
651 {
652         XMLNodeList nlist = node.children();
653         XMLNodeIterator niter;
654
655         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
656                 if ((*niter)->name() == X_("masters")) {
657                         _masters_node = new XMLNode (**niter);
658                 }
659         }
660
661         return AutomationControl::set_state (node, version);
662 }
663
664
665 #endif /* __libardour_slavable_automation_control_h__ */