51b2d30004eb8a9d3d58a8291f32c502f1f61625
[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 "ardour/audioengine.h"
28 #include "ardour/slavable_automation_control.h"
29 #include "ardour/session.h"
30
31 using namespace std;
32 using namespace ARDOUR;
33 using namespace PBD;
34
35 SlavableAutomationControl::SlavableAutomationControl(ARDOUR::Session& s,
36                                                      const Evoral::Parameter&                  parameter,
37                                                      const ParameterDescriptor&                desc,
38                                                      boost::shared_ptr<ARDOUR::AutomationList> l,
39                                                      const std::string&                        name,
40                                                      Controllable::Flag                        flags)
41         : AutomationControl (s, parameter, desc, l, name, flags)
42         , _masters_node (0)
43 {
44 }
45
46 SlavableAutomationControl::~SlavableAutomationControl ()
47 {
48         if (_masters_node) {
49                 delete _masters_node;
50                 _masters_node = 0;
51         }
52 }
53
54 double
55 SlavableAutomationControl::get_masters_value_locked () const
56 {
57
58         if (_desc.toggled) {
59                 for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
60                         if (mr->second.master()->get_value()) {
61                                 return _desc.upper;
62                         }
63                 }
64                 return _desc.lower;
65         } else {
66
67                 double v = 1.0; /* the masters function as a scaling factor */
68
69                 for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
70                         v *= mr->second.master()->get_value ();
71                 }
72
73                 return v;
74         }
75 }
76
77 double
78 SlavableAutomationControl::get_value_locked() const
79 {
80         /* read or write masters lock must be held */
81
82         if (_masters.empty()) {
83                 return Control::get_double (false, _session.transport_frame());
84         }
85
86         if (_desc.toggled) {
87                 /* for boolean/toggle controls, if this slave OR any master is
88                  * enabled, this slave is enabled. So check our own value
89                  * first, because if we are enabled, we can return immediately.
90                  */
91                 if (Control::get_double (false, _session.transport_frame())) {
92                         return _desc.upper;
93                 }
94         }
95
96         return Control::get_double() * get_masters_value_locked ();
97 }
98
99 /** Get the current effective `user' value based on automation state */
100 double
101 SlavableAutomationControl::get_value() const
102 {
103         bool from_list = _list && boost::dynamic_pointer_cast<AutomationList>(_list)->automation_playback();
104
105         Glib::Threads::RWLock::ReaderLock lm (master_lock);
106         if (!from_list) {
107                 return get_value_locked ();
108         } else {
109                 return Control::get_double (true, _session.transport_frame()) * get_masters_value_locked();
110         }
111 }
112
113 void
114 SlavableAutomationControl::actually_set_value (double value, PBD::Controllable::GroupControlDisposition gcd)
115 {
116         if (!_desc.toggled) {
117
118                 Glib::Threads::RWLock::WriterLock lm (master_lock);
119
120                 if (!_masters.empty()) {
121                         /* need to scale given value by current master's scaling */
122                         const double masters_value = get_masters_value_locked();
123                         if (masters_value == 0.0) {
124                                 value = 0.0;
125                         } else {
126                                 value /= masters_value;
127                                 value = std::max (lower(), std::min(upper(), value));
128                         }
129                 }
130         }
131
132         /* this will call Control::set_double() and emit Changed signals as appropriate */
133         AutomationControl::actually_set_value (value, gcd);
134 }
135
136 void
137 SlavableAutomationControl::add_master (boost::shared_ptr<AutomationControl> m, bool loading)
138 {
139         std::pair<Masters::iterator,bool> res;
140
141         {
142                 Glib::Threads::RWLock::WriterLock lm (master_lock);
143
144                 pair<PBD::ID,MasterRecord> newpair (m->id(), MasterRecord (m, 1.0));
145                 res = _masters.insert (newpair);
146
147                 if (res.second) {
148
149                         if (!loading) {
150
151                                 if (!_desc.toggled) {
152                                         const double master_value = m->get_value();
153
154                                         if (master_value == 0.0) {
155                                                 AutomationControl::set_double (0.0, Controllable::NoGroup);
156                                         } else {
157                                                 /* scale control's own value by
158                                                    amount that the master will
159                                                    contribute.
160                                                 */
161                                                 AutomationControl::set_double ((Control::get_double() / master_value), Controllable::NoGroup);
162                                         }
163                                 }
164                         }
165
166                         /* note that we bind @param m as a weak_ptr<AutomationControl>, thus
167                            avoiding holding a reference to the control in the binding
168                            itself.
169                         */
170
171                         m->DropReferences.connect_same_thread (masters_connections, boost::bind (&SlavableAutomationControl::master_going_away, this, boost::weak_ptr<AutomationControl>(m)));
172
173                         /* Store the connection inside the MasterRecord, so
174                            that when we destroy it, the connection is destroyed
175                            and we no longer hear about changes to the
176                            AutomationControl.
177
178                            Note that this also makes it safe to store a
179                            boost::shared_ptr<AutomationControl> in the functor,
180                            since we know we will destroy the functor when the
181                            connection is destroyed, which happens when we
182                            disconnect from the master (for any reason).
183
184                            Note that we fix the "from_self" argument that will
185                            be given to our own Changed signal to "false",
186                            because the change came from the master.
187                         */
188
189                         m->Changed.connect_same_thread (res.first->second.connection, boost::bind (&SlavableAutomationControl::master_changed, this, _1, _2, m));
190                 }
191         }
192
193         if (res.second) {
194                 /* this will notify everyone that we're now slaved to the master */
195                 MasterStatusChange (); /* EMIT SIGNAL */
196         }
197
198         post_add_master (m);
199
200         update_boolean_masters_records (m);
201 }
202
203 int32_t
204 SlavableAutomationControl::get_boolean_masters () const
205 {
206         int32_t n = 0;
207
208         if (_desc.toggled) {
209                 Glib::Threads::RWLock::ReaderLock lm (master_lock);
210                 for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
211                         if (mr->second.yn()) {
212                                 ++n;
213                         }
214                 }
215         }
216
217         return n;
218 }
219
220 void
221 SlavableAutomationControl::update_boolean_masters_records (boost::shared_ptr<AutomationControl> m)
222 {
223         if (_desc.toggled) {
224                 /* We may modify a MasterRecord, but we not modify the master
225                  * map, so we use a ReaderLock
226                  */
227                 Glib::Threads::RWLock::ReaderLock lm (master_lock);
228                 Masters::iterator mi = _masters.find (m->id());
229                 if (mi != _masters.end()) {
230                         /* update MasterRecord to show whether the master is
231                            on/off. We need to store this because the master
232                            may change (in the sense of emitting Changed())
233                            several times without actually changing the result
234                            of ::get_value(). This is a feature of
235                            AutomationControls (or even just Controllables,
236                            really) which have more than a simple scalar
237                            value. For example, the master may be a mute control
238                            which can be muted_by_self() and/or
239                            muted_by_masters(). When either of those two
240                            conditions changes, Changed() will be emitted, even
241                            though ::get_value() will return the same value each
242                            time (1.0 if either are true, 0.0 if neither is).
243
244                            This provides a way for derived types to check
245                            the last known state of a Master when the Master
246                            changes. We update it after calling
247                            ::master_changed() (though derived types must do
248                            this themselves).
249                         */
250                         mi->second.set_yn (m->get_value());
251                 }
252         }
253 }
254
255 void
256 SlavableAutomationControl::master_changed (bool /*from_self*/, GroupControlDisposition gcd, boost::shared_ptr<AutomationControl> m)
257 {
258         update_boolean_masters_records (m);
259         Changed (false, Controllable::NoGroup); /* EMIT SIGNAL */
260 }
261
262 void
263 SlavableAutomationControl::master_going_away (boost::weak_ptr<AutomationControl> wm)
264 {
265         boost::shared_ptr<AutomationControl> m = wm.lock();
266         if (m) {
267                 remove_master (m);
268         }
269 }
270
271 void
272 SlavableAutomationControl::remove_master (boost::shared_ptr<AutomationControl> m)
273 {
274         pre_remove_master (m);
275
276         {
277                 Glib::Threads::RWLock::WriterLock lm (master_lock);
278
279                 if (!_masters.erase (m->id())) {
280                         return;
281                 }
282
283                 if (!_session.deletion_in_progress()) {
284
285                         const double master_value = m->get_value ();
286
287                         if (master_value == 0.0) {
288                                 /* slave would have been set to 0.0 as well,
289                                    so just leave it there, and the user can
290                                    bring it back up. this fits with the
291                                    "removing a VCA does not change the level" rule.
292                                 */
293                         } else {
294                                 /* bump up the control's own value by the level
295                                    of the master that is being removed.
296                                 */
297                                 AutomationControl::set_double (AutomationControl::get_double() * master_value, Controllable::NoGroup);
298                         }
299                 }
300         }
301
302         if (_session.deletion_in_progress()) {
303                 /* no reason to care about new values or sending signals */
304                 return;
305         }
306
307         MasterStatusChange (); /* EMIT SIGNAL */
308
309         /* no need to update boolean masters records, since the MR will have
310          * been removed already.
311          */
312 }
313
314 void
315 SlavableAutomationControl::clear_masters ()
316 {
317         double current_value;
318         double new_value;
319         bool had_masters = false;
320
321         /* null ptr means "all masters */
322         pre_remove_master (boost::shared_ptr<AutomationControl>());
323
324         {
325                 Glib::Threads::RWLock::WriterLock lm (master_lock);
326                 current_value = get_value_locked ();
327                 if (!_masters.empty()) {
328                         had_masters = true;
329                 }
330                 _masters.clear ();
331                 new_value = get_value_locked ();
332         }
333
334         if (had_masters) {
335                 MasterStatusChange (); /* EMIT SIGNAL */
336         }
337
338         if (new_value != current_value) {
339                 actually_set_value (current_value, Controllable::UseGroup);
340         }
341
342         /* no need to update boolean masters records, since all MRs will have
343          * been removed already.
344          */
345 }
346
347 bool
348 SlavableAutomationControl::find_next_event (double now, double end, Evoral::ControlEvent& next_event) const
349 {
350         Glib::Threads::RWLock::ReaderLock lm (master_lock);
351         if (_masters.empty()) {
352                 return false;
353         }
354         bool rv = false;
355         /* iterate over all masters check their automation lists
356          * for any event between "now" and "end" which is earlier than
357          * next_event.when. If found, set next_event.when and return true.
358          * (see also Automatable::find_next_event)
359          */
360         for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
361                 boost::shared_ptr<AutomationControl> ac (mr->second.master());
362
363                 boost::shared_ptr<SlavableAutomationControl> sc
364                         = boost::dynamic_pointer_cast<SlavableAutomationControl>(ac);
365
366                 if (sc && sc->find_next_event (now, end, next_event)) {
367                         rv = true;
368                 }
369
370                 Evoral::ControlList::const_iterator i;
371                 boost::shared_ptr<const Evoral::ControlList> alist (ac->list());
372                 Evoral::ControlEvent cp (now, 0.0f);
373                 if (!alist) {
374                         continue;
375                 }
376
377                 for (i = lower_bound (alist->begin(), alist->end(), &cp, Evoral::ControlList::time_comparator);
378                      i != alist->end() && (*i)->when < end; ++i) {
379                         if ((*i)->when > now) {
380                                 break;
381                         }
382                 }
383
384                 if (i != alist->end() && (*i)->when < end) {
385                         if ((*i)->when < next_event.when) {
386                                 next_event.when = (*i)->when;
387                                 rv = true;
388                         }
389                 }
390         }
391
392         return rv;
393 }
394
395 bool
396 SlavableAutomationControl::slaved_to (boost::shared_ptr<AutomationControl> m) const
397 {
398         Glib::Threads::RWLock::ReaderLock lm (master_lock);
399         return _masters.find (m->id()) != _masters.end();
400 }
401
402 bool
403 SlavableAutomationControl::slaved () const
404 {
405         Glib::Threads::RWLock::ReaderLock lm (master_lock);
406         return !_masters.empty();
407 }
408
409 void
410 SlavableAutomationControl::use_saved_master_ratios ()
411 {
412         if (!_masters_node) {
413                 return;
414         }
415
416         Glib::Threads::RWLock::ReaderLock lm (master_lock);
417
418         /* use stored state, do not recompute */
419
420         if (_desc.toggled) {
421
422                 XMLNodeList nlist = _masters_node->children();
423                 XMLNodeIterator niter;
424
425                 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
426                         ID id_val;
427                         bool yn;
428                         if (!(*niter)->get_property (X_("id"), id_val) || !(*niter)->get_property (X_("yn"), yn)) {
429                                 continue;
430                   }
431
432                         Masters::iterator mi = _masters.find (id_val);
433                         if (mi != _masters.end()) {
434                                 mi->second.set_yn (yn);
435                         }
436                 }
437
438         } else {
439
440         }
441
442         delete _masters_node;
443         _masters_node = 0;
444
445         return;
446 }
447
448
449 XMLNode&
450 SlavableAutomationControl::get_state ()
451 {
452         XMLNode& node (AutomationControl::get_state());
453
454         /* store VCA master ratios */
455
456         {
457                 Glib::Threads::RWLock::ReaderLock lm (master_lock);
458
459                 if (!_masters.empty()) {
460
461                         XMLNode* masters_node = new XMLNode (X_("masters"));
462
463                         if (_desc.toggled) {
464                                 for (Masters::iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
465                                         XMLNode* mnode = new XMLNode (X_("master"));
466                                         mnode->set_property (X_("id"), mr->second.master()->id());
467                                         mnode->set_property (X_("yn"), mr->second.yn());
468                                         masters_node->add_child_nocopy (*mnode);
469                                 }
470                         } else {
471
472                         }
473
474                         node.add_child_nocopy (*masters_node);
475                 }
476         }
477
478         return node;
479 }
480
481 int
482 SlavableAutomationControl::set_state (XMLNode const& node, int version)
483 {
484         XMLNodeList nlist = node.children();
485         XMLNodeIterator niter;
486
487         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
488                 if ((*niter)->name() == X_("masters")) {
489                         _masters_node = new XMLNode (**niter);
490                 }
491         }
492
493         return AutomationControl::set_state (node, version);
494 }
495
496
497 #endif /* __libardour_slavable_automation_control_h__ */