no-op: move method order in file
[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 /** Get the current effective `user' value based on automation state */
99 double
100 SlavableAutomationControl::get_value() const
101 {
102         bool from_list = _list && boost::dynamic_pointer_cast<AutomationList>(_list)->automation_playback();
103
104         Glib::Threads::RWLock::ReaderLock lm (master_lock);
105         if (!from_list) {
106                 return get_value_locked ();
107         } else {
108                 return Control::get_double (true, _session.transport_frame()) * get_masters_value_locked();
109         }
110 }
111
112 void
113 SlavableAutomationControl::actually_set_value (double value, PBD::Controllable::GroupControlDisposition gcd)
114 {
115         if (!_desc.toggled) {
116
117                 Glib::Threads::RWLock::WriterLock lm (master_lock);
118
119                 if (!_masters.empty()) {
120                         /* need to scale given value by current master's scaling */
121                         const double masters_value = get_masters_value_locked();
122                         if (masters_value == 0.0) {
123                                 value = 0.0;
124                         } else {
125                                 value /= masters_value;
126                                 value = std::max (lower(), std::min(upper(), value));
127                         }
128                 }
129         }
130
131         /* this will call Control::set_double() and emit Changed signals as appropriate */
132         AutomationControl::actually_set_value (value, gcd);
133 }
134
135 void
136 SlavableAutomationControl::add_master (boost::shared_ptr<AutomationControl> m, bool loading)
137 {
138         std::pair<Masters::iterator,bool> res;
139
140         {
141                 Glib::Threads::RWLock::WriterLock lm (master_lock);
142
143                 pair<PBD::ID,MasterRecord> newpair (m->id(), MasterRecord (m, 1.0));
144                 res = _masters.insert (newpair);
145
146                 if (res.second) {
147
148                         if (!loading) {
149
150                                 if (!_desc.toggled) {
151                                         const double master_value = m->get_value();
152
153                                         if (master_value == 0.0) {
154                                                 AutomationControl::set_double (0.0, Controllable::NoGroup);
155                                         } else {
156                                                 /* scale control's own value by
157                                                    amount that the master will
158                                                    contribute.
159                                                 */
160                                                 AutomationControl::set_double ((Control::get_double() / master_value), Controllable::NoGroup);
161                                         }
162                                 }
163                         }
164
165                         /* note that we bind @param m as a weak_ptr<AutomationControl>, thus
166                            avoiding holding a reference to the control in the binding
167                            itself.
168                         */
169
170                         m->DropReferences.connect_same_thread (masters_connections, boost::bind (&SlavableAutomationControl::master_going_away, this, boost::weak_ptr<AutomationControl>(m)));
171
172                         /* Store the connection inside the MasterRecord, so
173                            that when we destroy it, the connection is destroyed
174                            and we no longer hear about changes to the
175                            AutomationControl.
176
177                            Note that this also makes it safe to store a
178                            boost::shared_ptr<AutomationControl> in the functor,
179                            since we know we will destroy the functor when the
180                            connection is destroyed, which happens when we
181                            disconnect from the master (for any reason).
182
183                            Note that we fix the "from_self" argument that will
184                            be given to our own Changed signal to "false",
185                            because the change came from the master.
186                         */
187
188                         m->Changed.connect_same_thread (res.first->second.connection, boost::bind (&SlavableAutomationControl::master_changed, this, _1, _2, m));
189                 }
190         }
191
192         if (res.second) {
193                 /* this will notify everyone that we're now slaved to the master */
194                 MasterStatusChange (); /* EMIT SIGNAL */
195         }
196
197         post_add_master (m);
198
199         update_boolean_masters_records (m);
200 }
201
202 int32_t
203 SlavableAutomationControl::get_boolean_masters () const
204 {
205         int32_t n = 0;
206
207         if (_desc.toggled) {
208                 Glib::Threads::RWLock::ReaderLock lm (master_lock);
209                 for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
210                         if (mr->second.yn()) {
211                                 ++n;
212                         }
213                 }
214         }
215
216         return n;
217 }
218
219 void
220 SlavableAutomationControl::update_boolean_masters_records (boost::shared_ptr<AutomationControl> m)
221 {
222         if (_desc.toggled) {
223                 /* We may modify a MasterRecord, but we not modify the master
224                  * map, so we use a ReaderLock
225                  */
226                 Glib::Threads::RWLock::ReaderLock lm (master_lock);
227                 Masters::iterator mi = _masters.find (m->id());
228                 if (mi != _masters.end()) {
229                         /* update MasterRecord to show whether the master is
230                            on/off. We need to store this because the master
231                            may change (in the sense of emitting Changed())
232                            several times without actually changing the result
233                            of ::get_value(). This is a feature of
234                            AutomationControls (or even just Controllables,
235                            really) which have more than a simple scalar
236                            value. For example, the master may be a mute control
237                            which can be muted_by_self() and/or
238                            muted_by_masters(). When either of those two
239                            conditions changes, Changed() will be emitted, even
240                            though ::get_value() will return the same value each
241                            time (1.0 if either are true, 0.0 if neither is).
242
243                            This provides a way for derived types to check
244                            the last known state of a Master when the Master
245                            changes. We update it after calling
246                            ::master_changed() (though derived types must do
247                            this themselves).
248                         */
249                         mi->second.set_yn (m->get_value());
250                 }
251         }
252 }
253
254 void
255 SlavableAutomationControl::master_changed (bool /*from_self*/, GroupControlDisposition gcd, boost::shared_ptr<AutomationControl> m)
256 {
257         update_boolean_masters_records (m);
258         Changed (false, Controllable::NoGroup); /* EMIT SIGNAL */
259 }
260
261 void
262 SlavableAutomationControl::master_going_away (boost::weak_ptr<AutomationControl> wm)
263 {
264         boost::shared_ptr<AutomationControl> m = wm.lock();
265         if (m) {
266                 remove_master (m);
267         }
268 }
269
270 void
271 SlavableAutomationControl::remove_master (boost::shared_ptr<AutomationControl> m)
272 {
273         pre_remove_master (m);
274
275         {
276                 Glib::Threads::RWLock::WriterLock lm (master_lock);
277
278                 if (!_masters.erase (m->id())) {
279                         return;
280                 }
281
282                 if (!_session.deletion_in_progress()) {
283
284                         const double master_value = m->get_value ();
285
286                         if (master_value == 0.0) {
287                                 /* slave would have been set to 0.0 as well,
288                                    so just leave it there, and the user can
289                                    bring it back up. this fits with the
290                                    "removing a VCA does not change the level" rule.
291                                 */
292                         } else {
293                                 /* bump up the control's own value by the level
294                                    of the master that is being removed.
295                                 */
296                                 AutomationControl::set_double (AutomationControl::get_double() * master_value, Controllable::NoGroup);
297                         }
298                 }
299         }
300
301         if (_session.deletion_in_progress()) {
302                 /* no reason to care about new values or sending signals */
303                 return;
304         }
305
306         MasterStatusChange (); /* EMIT SIGNAL */
307
308         /* no need to update boolean masters records, since the MR will have
309          * been removed already.
310          */
311 }
312
313 void
314 SlavableAutomationControl::clear_masters ()
315 {
316         double current_value;
317         double new_value;
318         bool had_masters = false;
319
320         /* null ptr means "all masters */
321         pre_remove_master (boost::shared_ptr<AutomationControl>());
322
323         {
324                 Glib::Threads::RWLock::WriterLock lm (master_lock);
325                 current_value = get_value_locked ();
326                 if (!_masters.empty()) {
327                         had_masters = true;
328                 }
329                 _masters.clear ();
330                 new_value = get_value_locked ();
331         }
332
333         if (had_masters) {
334                 MasterStatusChange (); /* EMIT SIGNAL */
335         }
336
337         if (new_value != current_value) {
338                 actually_set_value (current_value, Controllable::UseGroup);
339         }
340
341         /* no need to update boolean masters records, since all MRs will have
342          * been removed already.
343          */
344 }
345
346 bool
347 SlavableAutomationControl::slaved_to (boost::shared_ptr<AutomationControl> m) const
348 {
349         Glib::Threads::RWLock::ReaderLock lm (master_lock);
350         return _masters.find (m->id()) != _masters.end();
351 }
352
353 bool
354 SlavableAutomationControl::slaved () const
355 {
356         Glib::Threads::RWLock::ReaderLock lm (master_lock);
357         return !_masters.empty();
358 }
359
360 void
361 SlavableAutomationControl::use_saved_master_ratios ()
362 {
363         if (!_masters_node) {
364                 return;
365         }
366
367         Glib::Threads::RWLock::ReaderLock lm (master_lock);
368
369         /* use stored state, do not recompute */
370
371         if (_desc.toggled) {
372
373                 XMLNodeList nlist = _masters_node->children();
374                 XMLNodeIterator niter;
375
376                 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
377                         XMLProperty const * id_prop = (*niter)->property (X_("id"));
378                         if (!id_prop) {
379                                 continue;
380                         }
381                         XMLProperty const * yn_prop = (*niter)->property (X_("yn"));
382                         if (!yn_prop) {
383                                 continue;
384                         }
385                         Masters::iterator mi = _masters.find (ID (id_prop->value()));
386                         if (mi != _masters.end()) {
387                                 mi->second.set_yn (string_is_affirmative (yn_prop->value()));
388                         }
389                 }
390
391         } else {
392
393         }
394
395         delete _masters_node;
396         _masters_node = 0;
397
398         return;
399 }
400
401
402 XMLNode&
403 SlavableAutomationControl::get_state ()
404 {
405         XMLNode& node (AutomationControl::get_state());
406
407         /* store VCA master ratios */
408
409         {
410                 Glib::Threads::RWLock::ReaderLock lm (master_lock);
411
412                 if (!_masters.empty()) {
413
414                         XMLNode* masters_node = new XMLNode (X_("masters"));
415
416                         if (_desc.toggled) {
417                                 for (Masters::iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
418                                         XMLNode* mnode = new XMLNode (X_("master"));
419                                         mnode->add_property (X_("id"), mr->second.master()->id().to_s());
420                                         mnode->add_property (X_("yn"), mr->second.yn());
421                                         masters_node->add_child_nocopy (*mnode);
422                                 }
423                         } else {
424
425                         }
426
427                         node.add_child_nocopy (*masters_node);
428                 }
429         }
430
431         return node;
432 }
433
434 int
435 SlavableAutomationControl::set_state (XMLNode const& node, int version)
436 {
437         XMLNodeList nlist = node.children();
438         XMLNodeIterator niter;
439
440         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
441                 if ((*niter)->name() == X_("masters")) {
442                         _masters_node = new XMLNode (**niter);
443                 }
444         }
445
446         return AutomationControl::set_state (node, version);
447 }
448
449
450 #endif /* __libardour_slavable_automation_control_h__ */