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