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