TempoMap::bbt_duration_at() handles an audio-locked meter.
[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
118 void
119 SlavableAutomationControl::add_master (boost::shared_ptr<AutomationControl> m)
120 {
121         std::pair<Masters::iterator,bool> res;
122
123         {
124                 Glib::Threads::RWLock::WriterLock lm (master_lock);
125                 const double current_value = get_value_locked ();
126
127                 /* ratio will be recomputed below */
128
129                 pair<PBD::ID,MasterRecord> newpair (m->id(), MasterRecord (m, 1.0));
130                 res = _masters.insert (newpair);
131
132                 if (res.second) {
133
134                         recompute_masters_ratios (current_value);
135
136                         /* note that we bind @param m as a weak_ptr<AutomationControl>, thus
137                            avoiding holding a reference to the control in the binding
138                            itself.
139                         */
140
141                         m->DropReferences.connect_same_thread (masters_connections, boost::bind (&SlavableAutomationControl::master_going_away, this, boost::weak_ptr<AutomationControl>(m)));
142
143                         /* Store the connection inside the MasterRecord, so
144                            that when we destroy it, the connection is destroyed
145                            and we no longer hear about changes to the
146                            AutomationControl. 
147
148                            Note that this also makes it safe to store a
149                            boost::shared_ptr<AutomationControl> in the functor,
150                            since we know we will destroy the functor when the 
151                            connection is destroyed, which happens when we
152                            disconnect from the master (for any reason).
153
154                            Note that we fix the "from_self" argument that will
155                            be given to our own Changed signal to "false",
156                            because the change came from the master.
157                         */
158
159                         m->Changed.connect_same_thread (res.first->second.connection, boost::bind (&SlavableAutomationControl::master_changed, this, _1, _2, m));
160                         cerr << this << enum_2_string ((AutomationType) _parameter.type()) << " now listening to Changed from " << m << endl;
161                 }
162         }
163
164         if (res.second) {
165                 /* this will notify everyone that we're now slaved to the master */
166                 MasterStatusChange (); /* EMIT SIGNAL */
167         }
168
169         post_add_master (m);
170
171         update_boolean_masters_records (m);
172 }
173
174 int32_t
175 SlavableAutomationControl::get_boolean_masters () const
176 {
177         int32_t n = 0;
178
179         if (_desc.toggled) {
180                 Glib::Threads::RWLock::ReaderLock lm (master_lock);
181                 for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
182                         if (mr->second.yn()) {
183                                 ++n;
184                         }
185                 }
186         }
187
188         return n;
189 }
190
191 void
192 SlavableAutomationControl::update_boolean_masters_records (boost::shared_ptr<AutomationControl> m)
193 {
194         if (_desc.toggled) {
195                 /* We may modify a MasterRecord, but we not modify the master
196                  * map, so we use a ReaderLock
197                  */
198                 Glib::Threads::RWLock::ReaderLock lm (master_lock);
199                 Masters::iterator mi = _masters.find (m->id());
200                 if (mi != _masters.end()) {
201                         /* update MasterRecord to show whether the master is
202                            on/off. We need to store this because the master
203                            may change (in the sense of emitting Changed())
204                            several times without actually changing the result
205                            of ::get_value(). This is a feature of
206                            AutomationControls (or even just Controllables,
207                            really) which have more than a simple scalar
208                            value. For example, the master may be a mute control
209                            which can be muted_by_self() and/or
210                            muted_by_masters(). When either of those two
211                            conditions changes, Changed() will be emitted, even
212                            though ::get_value() will return the same value each
213                            time (1.0 if either are true, 0.0 if neither is).
214
215                            This provides a way for derived types to check
216                            the last known state of a Master when the Master
217                            changes. We update it after calling
218                            ::master_changed() (though derived types must do
219                            this themselves).
220                         */
221                         mi->second.set_yn (m->get_value());
222                 }
223         }
224 }
225
226 void
227 SlavableAutomationControl::master_changed (bool /*from_self*/, GroupControlDisposition gcd, boost::shared_ptr<AutomationControl> m)
228 {
229         update_boolean_masters_records (m);
230         Changed (false, Controllable::NoGroup); /* EMIT SIGNAL */
231 }
232
233 void
234 SlavableAutomationControl::master_going_away (boost::weak_ptr<AutomationControl> wm)
235 {
236         boost::shared_ptr<AutomationControl> m = wm.lock();
237         if (m) {
238                 remove_master (m);
239         }
240 }
241
242 void
243 SlavableAutomationControl::remove_master (boost::shared_ptr<AutomationControl> m)
244 {
245         double current_value;
246         double new_value;
247         bool masters_left;
248         Masters::size_type erased = 0;
249
250         pre_remove_master (m);
251
252         {
253                 Glib::Threads::RWLock::WriterLock lm (master_lock);
254                 current_value = get_value_locked ();
255                 erased = _masters.erase (m->id());
256                 if (erased && !_session.deletion_in_progress()) {
257                         recompute_masters_ratios (current_value);
258                 }
259                 masters_left = _masters.size ();
260                 new_value = get_value_locked ();
261         }
262
263         if (_session.deletion_in_progress()) {
264                 /* no reason to care about new values or sending signals */
265                 return;
266         }
267
268         if (erased) {
269                 MasterStatusChange (); /* EMIT SIGNAL */
270         }
271
272         if (new_value != current_value) {
273                 if (masters_left == 0) {
274                         /* no masters left, make sure we keep the same value
275                            that we had before.
276                         */
277                         actually_set_value (current_value, Controllable::UseGroup);
278                 }
279         }
280
281         /* no need to update boolean masters records, since the MR will have
282          * been removed already.
283          */
284 }
285
286 void
287 SlavableAutomationControl::clear_masters ()
288 {
289         double current_value;
290         double new_value;
291         bool had_masters = false;
292
293         /* null ptr means "all masters */
294         pre_remove_master (boost::shared_ptr<AutomationControl>());
295
296         {
297                 Glib::Threads::RWLock::WriterLock lm (master_lock);
298                 current_value = get_value_locked ();
299                 if (!_masters.empty()) {
300                         had_masters = true;
301                 }
302                 _masters.clear ();
303                 new_value = get_value_locked ();
304         }
305
306         if (had_masters) {
307                 MasterStatusChange (); /* EMIT SIGNAL */
308         }
309
310         if (new_value != current_value) {
311                 actually_set_value (current_value, Controllable::UseGroup);
312         }
313
314         /* no need to update boolean masters records, since all MRs will have
315          * been removed already.
316          */
317 }
318
319 bool
320 SlavableAutomationControl::slaved_to (boost::shared_ptr<AutomationControl> m) const
321 {
322         Glib::Threads::RWLock::ReaderLock lm (master_lock);
323         return _masters.find (m->id()) != _masters.end();
324 }
325
326 bool
327 SlavableAutomationControl::slaved () const
328 {
329         Glib::Threads::RWLock::ReaderLock lm (master_lock);
330         return !_masters.empty();
331 }
332
333 #endif /* __libardour_slavable_automation_control_h__ */