Session API changes to enable VCAs to set soloed-by-upstream on assigned routes
[ardour.git] / libs / ardour / session_rtevents.cc
1 /*
2     Copyright (C) 1999-2009 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19 #include <boost/bind.hpp>
20
21 #include "pbd/error.h"
22 #include "pbd/compose.h"
23
24 #include "ardour/session.h"
25 #include "ardour/route.h"
26 #include "ardour/track.h"
27
28 #include "i18n.h"
29
30 using namespace std;
31 using namespace PBD;
32 using namespace ARDOUR;
33 using namespace Glib;
34
35 void
36 Session::set_monitoring (boost::shared_ptr<RouteList> rl, MonitorChoice mc, 
37                          SessionEvent::RTeventCallback after,
38                          Controllable::GroupControlDisposition group_override)
39 {
40         queue_event (get_rt_event (rl, mc, after, group_override, &Session::rt_set_monitoring));
41 }
42
43 void
44 Session::rt_set_monitoring (boost::shared_ptr<RouteList> rl, MonitorChoice mc, Controllable::GroupControlDisposition group_override)
45 {
46         for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
47                 if (!(*i)->is_auditioner()) {
48                         boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*i);
49                         if (t) {
50                                 t->set_monitoring (mc, group_override);
51                         }
52                 }
53         }
54
55         set_dirty();
56 }
57
58 void
59 Session::clear_all_solo_state (boost::shared_ptr<RouteList> rl)
60 {
61         queue_event (get_rt_event (rl, false, rt_cleanup, Controllable::NoGroup, &Session::rt_clear_all_solo_state));
62 }
63
64 void
65 Session::rt_clear_all_solo_state (boost::shared_ptr<RouteList> rl, bool /* yn */, Controllable::GroupControlDisposition /* group_override */)
66 {
67         for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
68                 if ((*i)->is_auditioner()) {
69                         continue;
70                 }
71                 (*i)->clear_all_solo_state();
72         }
73         set_dirty();
74 }
75
76 void
77 Session::set_solo (boost::shared_ptr<RouteList> rl, bool yn, SessionEvent::RTeventCallback after,
78                    Controllable::GroupControlDisposition group_override)
79 {
80         queue_event (get_rt_event (rl, yn, after, group_override, &Session::rt_set_solo));
81 }
82
83 void
84 Session::rt_set_solo (boost::shared_ptr<RouteList> rl, bool yn, Controllable::GroupControlDisposition group_override)
85 {
86         for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
87                 if (!(*i)->is_auditioner()) {
88                         (*i)->set_solo (yn, group_override);
89                 }
90         }
91
92         set_dirty();
93
94         /* XXX boost::shared_ptr<RouteList>  goes out of scope here and is likley free()ed in RT context
95          * because boost's shared_ptr does reference counting and free/delete in the dtor.
96          * (this also applies to other rt_  methods here)
97          */
98 }
99
100 void
101 Session::set_implicit_solo (boost::shared_ptr<RouteList> rl, int delta, bool upstream, SessionEvent::RTeventCallback after,
102                    Controllable::GroupControlDisposition group_override)
103 {
104         queue_event (get_rt_event (rl, delta, upstream, after, group_override, &Session::rt_set_implicit_solo));
105 }
106
107 void
108 Session::rt_set_implicit_solo (boost::shared_ptr<RouteList> rl, int delta, bool upstream, PBD::Controllable::GroupControlDisposition)
109 {
110         for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
111                 if (!(*i)->is_auditioner()) {
112                         if (upstream) {
113                                 (*i)->mod_solo_by_others_upstream (delta);
114                         } else {
115                                 (*i)->mod_solo_by_others_downstream (delta);
116                         }
117                 }
118         }
119
120         set_dirty();
121
122         /* XXX boost::shared_ptr<RouteList>  goes out of scope here and is likley free()ed in RT context
123          * because boost's shared_ptr does reference counting and free/delete in the dtor.
124          * (this also applies to other rt_  methods here)
125          */
126 }
127
128 void
129 Session::set_just_one_solo (boost::shared_ptr<Route> r, bool yn, SessionEvent::RTeventCallback after)
130 {
131         /* its a bit silly to have to do this, but it keeps the API for this public method sane (we're
132            only going to solo one route) and keeps our ability to use get_rt_event() for the internal
133            private method.
134         */
135
136         boost::shared_ptr<RouteList> rl (new RouteList);
137         rl->push_back (r);
138
139         queue_event (get_rt_event (rl, yn, after, Controllable::NoGroup, &Session::rt_set_just_one_solo));
140 }
141
142 void
143 Session::rt_set_just_one_solo (boost::shared_ptr<RouteList> just_one, bool yn, Controllable::GroupControlDisposition /*ignored*/)
144 {
145         boost::shared_ptr<RouteList> rl = routes.reader ();
146         boost::shared_ptr<Route> r = just_one->front();
147
148         for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
149                 if (!(*i)->is_auditioner() && r != *i) {
150                         (*i)->set_solo (!yn, Controllable::NoGroup);
151                 }
152         }
153
154         r->set_solo (yn, Controllable::NoGroup);
155
156         set_dirty();
157 }
158
159 void
160 Session::set_listen (boost::shared_ptr<RouteList> rl, bool yn, SessionEvent::RTeventCallback after, Controllable::GroupControlDisposition group_override)
161 {
162         queue_event (get_rt_event (rl, yn, after, group_override, &Session::rt_set_listen));
163 }
164
165 void
166 Session::rt_set_listen (boost::shared_ptr<RouteList> rl, bool yn, Controllable::GroupControlDisposition group_override)
167 {
168         for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
169                 if (!(*i)->is_auditioner()) {
170                         (*i)->set_listen (yn, group_override);
171                 }
172         }
173
174         set_dirty();
175 }
176
177 void
178 Session::set_mute (boost::shared_ptr<RouteList> rl, bool yn, SessionEvent::RTeventCallback after, Controllable::GroupControlDisposition group_override)
179 {
180         /* Set superficial value of mute controls for automation. */
181         for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
182                 boost::shared_ptr<Route::MuteControllable> mc = boost::dynamic_pointer_cast<Route::MuteControllable> ((*i)->mute_control());
183                 mc->set_superficial_value(yn);
184         }
185
186         queue_event (get_rt_event (rl, yn, after, group_override, &Session::rt_set_mute));
187 }
188
189 void
190 Session::rt_set_mute (boost::shared_ptr<RouteList> rl, bool yn, Controllable::GroupControlDisposition group_override)
191 {
192         for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
193                 if (!(*i)->is_monitor() && !(*i)->is_auditioner()) {
194                         (*i)->set_mute (yn, group_override);
195                 }
196         }
197
198         set_dirty();
199 }
200
201 void
202 Session::set_solo_isolated (boost::shared_ptr<RouteList> rl, bool yn, SessionEvent::RTeventCallback after, Controllable::GroupControlDisposition group_override)
203 {
204         queue_event (get_rt_event (rl, yn, after, group_override, &Session::rt_set_solo_isolated));
205 }
206
207 void
208 Session::rt_set_solo_isolated (boost::shared_ptr<RouteList> rl, bool yn, Controllable::GroupControlDisposition group_override)
209 {
210         for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
211                 if (!(*i)->is_master() && !(*i)->is_monitor() && !(*i)->is_auditioner()) {
212                         (*i)->set_solo_isolated (yn, group_override);
213                 }
214         }
215
216         set_dirty();
217 }
218
219 void
220 Session::set_record_enabled (boost::shared_ptr<RouteList> rl, bool yn, SessionEvent::RTeventCallback after, Controllable::GroupControlDisposition group_override)
221 {
222         if (!writable()) {
223                 return;
224         }
225
226         /* do the non-RT part of rec-enabling first - the RT part will be done
227          * on the next process cycle. This does mean that theoretically we are
228          * doing things provisionally on the assumption that the rec-enable
229          * change will work, but this had better be a solid assumption for
230          * other reasons.
231          */
232
233         for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
234                 if ((*i)->is_auditioner() || (*i)->record_safe ()) {
235                         continue;
236                 }
237
238                 boost::shared_ptr<Track> t;
239
240                 if ((t = boost::dynamic_pointer_cast<Track>(*i)) != 0) {
241                         t->prep_record_enabled (yn, group_override);
242                 }
243         }
244
245         queue_event (get_rt_event (rl, yn, after, group_override, &Session::rt_set_record_enabled));
246 }
247
248 void
249 Session::rt_set_record_enabled (boost::shared_ptr<RouteList> rl, bool yn, Controllable::GroupControlDisposition group_override)
250 {
251         for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
252                 if ((*i)->is_auditioner() || (*i)->record_safe ()) {
253                         continue;
254                 }
255
256                 boost::shared_ptr<Track> t;
257
258                 if ((t = boost::dynamic_pointer_cast<Track>(*i)) != 0) {
259                         t->set_record_enabled (yn, group_override);
260                 }
261         }
262
263         set_dirty ();
264 }
265
266
267 void
268 Session::set_record_safe (boost::shared_ptr<RouteList> rl, bool yn, SessionEvent::RTeventCallback after, Controllable::GroupControlDisposition group_override)
269 {
270         set_record_enabled (rl, false, after, group_override);
271         queue_event (get_rt_event (rl, yn, after, group_override, &Session::rt_set_record_safe));
272 }
273
274 void
275 Session::rt_set_record_safe (boost::shared_ptr<RouteList> rl, bool yn, Controllable::GroupControlDisposition group_override)
276 {
277         for (RouteList::iterator i = rl->begin (); i != rl->end (); ++i) {
278                 if ((*i)->is_auditioner ()) { // REQUIRES REVIEW Can audiotioner be in Record Safe mode?
279                         continue;
280                 }
281
282                 boost::shared_ptr<Track> t;
283
284                 if ((t = boost::dynamic_pointer_cast<Track>(*i)) != 0) {
285                         t->set_record_safe (yn, group_override);
286                 }
287         }
288
289         set_dirty ();
290 }
291
292 void
293 Session::process_rtop (SessionEvent* ev)
294 {
295         ev->rt_slot ();
296
297         if (ev->event_loop) {
298                 ev->event_loop->call_slot (MISSING_INVALIDATOR, boost::bind (ev->rt_return, ev));
299         } else {
300                 warning << string_compose ("programming error: %1", X_("Session RT event queued from thread without a UI - cleanup in RT thread!")) << endmsg;
301                 ev->rt_return (ev);
302         }
303 }