a slew of as-yet incomplete work to get VCA solo+mute closer to working
[ardour.git] / libs / ardour / solo_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 #include "ardour/debug.h"
20 #include "ardour/mute_master.h"
21 #include "ardour/session.h"
22 #include "ardour/solo_control.h"
23
24 #include "i18n.h"
25
26 using namespace ARDOUR;
27 using namespace std;
28 using namespace PBD;
29
30 SoloControl::SoloControl (Session& session, std::string const & name, Soloable& s, Muteable& m)
31         : SlavableAutomationControl (session, SoloAutomation, ParameterDescriptor (SoloAutomation),
32                                      boost::shared_ptr<AutomationList>(new AutomationList(Evoral::Parameter(SoloAutomation))),
33                                      name)
34         , _soloable (s)
35         , _muteable (m)
36         , _self_solo (false)
37         , _soloed_by_others_upstream (0)
38         , _soloed_by_others_downstream (0)
39 {
40         _list->set_interpolation (Evoral::ControlList::Discrete);
41         /* solo changes must be synchronized by the process cycle */
42         set_flags (Controllable::Flag (flags() | Controllable::RealTime));
43 }
44
45 void
46 SoloControl::set_self_solo (bool yn)
47 {
48         DEBUG_TRACE (DEBUG::Solo, string_compose ("%1: set SELF solo => %2\n", name(), yn));
49         _self_solo = yn;
50         set_mute_master_solo ();
51 }
52
53 void
54 SoloControl::set_mute_master_solo ()
55 {
56         _muteable.mute_master()->set_soloed_by_self (self_soloed());
57
58         if (Config->get_solo_control_is_listen_control()) {
59                 _muteable.mute_master()->set_soloed_by_others (false);
60         } else {
61                 _muteable.mute_master()->set_soloed_by_others (soloed_by_others_downstream() || soloed_by_others_upstream());
62         }
63 }
64
65 void
66 SoloControl::mod_solo_by_others_downstream (int32_t delta)
67 {
68         if (_soloable.is_safe() || !_soloable.can_solo()) {
69                 return;
70         }
71
72         DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 mod solo-by-downstream by %2, current up = %3 down = %4\n",
73                                                   name(), delta, _soloed_by_others_upstream, _soloed_by_others_downstream));
74
75         if (delta < 0) {
76                 if (_soloed_by_others_downstream >= (uint32_t) abs (delta)) {
77                         _soloed_by_others_downstream += delta;
78                 } else {
79                         _soloed_by_others_downstream = 0;
80                 }
81         } else {
82                 _soloed_by_others_downstream += delta;
83         }
84
85         DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 SbD delta %2 = %3\n", name(), delta, _soloed_by_others_downstream));
86
87         set_mute_master_solo ();
88         Changed (false, Controllable::UseGroup); /* EMIT SIGNAL */
89 }
90
91 void
92 SoloControl::mod_solo_by_others_upstream (int32_t delta)
93 {
94         if (_soloable.is_safe() || !_soloable.can_solo()) {
95                 return;
96         }
97
98         DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 mod solo-by-upstream by %2, current up = %3 down = %4\n",
99                                                   name(), delta, _soloed_by_others_upstream, _soloed_by_others_downstream));
100
101         uint32_t old_sbu = _soloed_by_others_upstream;
102
103         if (delta < 0) {
104                 if (_soloed_by_others_upstream >= (uint32_t) abs (delta)) {
105                         _soloed_by_others_upstream += delta;
106                 } else {
107                         _soloed_by_others_upstream = 0;
108                 }
109         } else {
110                 _soloed_by_others_upstream += delta;
111         }
112
113         DEBUG_TRACE (DEBUG::Solo, string_compose (
114                              "%1 SbU delta %2 = %3 old = %4 sbd %5 ss %6 exclusive %7\n",
115                              name(), delta, _soloed_by_others_upstream, old_sbu,
116                              _soloed_by_others_downstream, _self_solo, Config->get_exclusive_solo()));
117
118
119         /* push the inverse solo change to everything that feeds us.
120
121            This is important for solo-within-group. When we solo 1 track out of N that
122            feed a bus, that track will cause mod_solo_by_upstream (+1) to be called
123            on the bus. The bus then needs to call mod_solo_by_downstream (-1) on all
124            tracks that feed it. This will silence them if they were audible because
125            of a bus solo, but the newly soloed track will still be audible (because
126            it is self-soloed).
127
128            but .. do this only when we are being told to solo-by-upstream (i.e delta = +1),
129                    not in reverse.
130         */
131
132         if ((_self_solo || _soloed_by_others_downstream) &&
133             ((old_sbu == 0 && _soloed_by_others_upstream > 0) ||
134              (old_sbu > 0 && _soloed_by_others_upstream == 0))) {
135
136                 if (delta > 0 || !Config->get_exclusive_solo()) {
137                         _soloable.push_solo_upstream (delta);
138                 }
139         }
140
141         set_mute_master_solo ();
142         Changed (false, Controllable::NoGroup); /* EMIT SIGNAL */
143 }
144
145 void
146 SoloControl::actually_set_value (double val, PBD::Controllable::GroupControlDisposition group_override)
147 {
148         if (_soloable.is_safe() || !_soloable.can_solo()) {
149                 return;
150         }
151
152         set_self_solo (val == 1.0);
153
154         /* this sets the Evoral::Control::_user_value for us, which will
155            be retrieved by AutomationControl::get_value (), and emits Changed
156         */
157
158         AutomationControl::actually_set_value (val, group_override);
159         _session.set_dirty ();
160 }
161
162 double
163 SoloControl::get_value () const
164 {
165         if (slaved()) {
166                 Glib::Threads::RWLock::ReaderLock lm (master_lock);
167                 return get_masters_value_locked () ? 1.0 : 0.0;
168         }
169
170         if (_list && boost::dynamic_pointer_cast<AutomationList>(_list)->automation_playback()) {
171                 // Playing back automation, get the value from the list
172                 return AutomationControl::get_value();
173         }
174
175         return self_soloed() ? 1.0 : 0.0;
176 }
177
178 void
179 SoloControl::clear_all_solo_state ()
180 {
181         // ideally this function will never do anything, it only exists to forestall Murphy
182
183 #ifndef NDEBUG
184         // these are really debug messages, but of possible interest.
185         if (self_soloed()) {
186                 PBD::info << string_compose (_("Cleared Explicit solo: %1\n"), name());
187         }
188         if (_soloed_by_others_upstream || _soloed_by_others_downstream) {
189                 PBD::info << string_compose (_("Cleared Implicit solo: %1 up:%2 down:%3\n"),
190                                 name(), _soloed_by_others_upstream, _soloed_by_others_downstream);
191         }
192 #endif
193
194         _soloed_by_others_upstream = 0;
195         _soloed_by_others_downstream = 0;
196
197         set_self_solo (false);
198
199         Changed (false, Controllable::UseGroup); /* EMIT SIGNAL */
200 }
201
202 int
203 SoloControl::set_state (XMLNode const & node, int)
204 {
205         XMLProperty const * prop;
206
207         if ((prop = node.property ("self-solo")) != 0) {
208                 set_self_solo (string_is_affirmative (prop->value()));
209         }
210
211         if ((prop = node.property ("soloed-by-upstream")) != 0) {
212                 _soloed_by_others_upstream = 0; // needed for mod_.... () to work
213                 mod_solo_by_others_upstream (atoi (prop->value()));
214         }
215
216         if ((prop = node.property ("soloed-by-downstream")) != 0) {
217                 _soloed_by_others_downstream = 0; // needed for mod_.... () to work
218                 mod_solo_by_others_downstream (atoi (prop->value()));
219         }
220
221         return 0;
222 }
223
224 XMLNode&
225 SoloControl::get_state ()
226 {
227         XMLNode& node (SlavableAutomationControl::get_state());
228
229         node.add_property (X_("self-solo"), _self_solo ? X_("yes") : X_("no"));
230         char buf[32];
231         snprintf (buf, sizeof(buf), "%d",  _soloed_by_others_upstream);
232         node.add_property (X_("soloed-by-upstream"), buf);
233         snprintf (buf, sizeof(buf), "%d",  _soloed_by_others_downstream);
234         node.add_property (X_("soloed-by-downstream"), buf);
235
236         return node;
237 }