c06d8db7a5ca02143daf0dce5c8c32f2790ca322
[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::slaved_to (boost::shared_ptr<AutomationControl> m) const
349 {
350         Glib::Threads::RWLock::ReaderLock lm (master_lock);
351         return _masters.find (m->id()) != _masters.end();
352 }
353
354 bool
355 SlavableAutomationControl::slaved () const
356 {
357         Glib::Threads::RWLock::ReaderLock lm (master_lock);
358         return !_masters.empty();
359 }
360
361 void
362 SlavableAutomationControl::use_saved_master_ratios ()
363 {
364         if (!_masters_node) {
365                 return;
366         }
367
368         Glib::Threads::RWLock::ReaderLock lm (master_lock);
369
370         /* use stored state, do not recompute */
371
372         if (_desc.toggled) {
373
374                 XMLNodeList nlist = _masters_node->children();
375                 XMLNodeIterator niter;
376
377                 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
378                         ID id_val;
379                         bool yn;
380                         if (!(*niter)->get_property (X_("id"), id_val) || !(*niter)->get_property (X_("yn"), yn)) {
381                                 continue;
382                   }
383
384                         Masters::iterator mi = _masters.find (id_val);
385                         if (mi != _masters.end()) {
386                                 mi->second.set_yn (yn);
387                         }
388                 }
389
390         } else {
391
392         }
393
394         delete _masters_node;
395         _masters_node = 0;
396
397         return;
398 }
399
400
401 XMLNode&
402 SlavableAutomationControl::get_state ()
403 {
404         XMLNode& node (AutomationControl::get_state());
405
406         /* store VCA master ratios */
407
408         {
409                 Glib::Threads::RWLock::ReaderLock lm (master_lock);
410
411                 if (!_masters.empty()) {
412
413                         XMLNode* masters_node = new XMLNode (X_("masters"));
414
415                         if (_desc.toggled) {
416                                 for (Masters::iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
417                                         XMLNode* mnode = new XMLNode (X_("master"));
418                                         mnode->set_property (X_("id"), mr->second.master()->id());
419                                         mnode->set_property (X_("yn"), mr->second.yn());
420                                         masters_node->add_child_nocopy (*mnode);
421                                 }
422                         } else {
423
424                         }
425
426                         node.add_child_nocopy (*masters_node);
427                 }
428         }
429
430         return node;
431 }
432
433 int
434 SlavableAutomationControl::set_state (XMLNode const& node, int version)
435 {
436         XMLNodeList nlist = node.children();
437         XMLNodeIterator niter;
438
439         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
440                 if ((*niter)->name() == X_("masters")) {
441                         _masters_node = new XMLNode (**niter);
442                 }
443         }
444
445         return AutomationControl::set_state (node, version);
446 }
447
448
449 #endif /* __libardour_slavable_automation_control_h__ */