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