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