add Record-Safe feature to libardour (from Nikolay Polyanovskii)
[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, SessionEvent::RTeventCallback after, bool group_override)
37 {
38         queue_event (get_rt_event (rl, mc, after, group_override, &Session::rt_set_monitoring));
39 }
40
41 void
42 Session::rt_set_monitoring (boost::shared_ptr<RouteList> rl, MonitorChoice mc, bool /* group_override */)
43 {
44         for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
45                 if (!(*i)->is_auditioner()) {
46                         boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*i);
47                         if (t) {
48                                 t->set_monitoring (mc);
49                         }
50                 }
51         }
52
53         set_dirty();
54 }
55
56 void
57 Session::set_solo (boost::shared_ptr<RouteList> rl, bool yn, SessionEvent::RTeventCallback after, bool group_override)
58 {
59         queue_event (get_rt_event (rl, yn, after, group_override, &Session::rt_set_solo));
60 }
61
62 void
63 Session::rt_set_solo (boost::shared_ptr<RouteList> rl, bool yn, bool /* group_override */)
64 {
65         for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
66                 if (!(*i)->is_auditioner()) {
67                         (*i)->set_solo (yn, this);
68                 }
69         }
70
71         set_dirty();
72 }
73
74 void
75 Session::cancel_solo_after_disconnect (boost::shared_ptr<Route> r, bool upstream, SessionEvent::RTeventCallback after)
76 {
77         boost::shared_ptr<RouteList> rl (new RouteList);
78         rl->push_back (r);
79
80         queue_event (get_rt_event (rl, upstream, after, false, &Session::rt_cancel_solo_after_disconnect));
81 }
82
83 void
84 Session::rt_cancel_solo_after_disconnect (boost::shared_ptr<RouteList> rl, bool upstream, bool /* group_override */)
85 {
86         for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
87                 if (!(*i)->is_auditioner()) {
88                         (*i)->cancel_solo_after_disconnect (upstream);
89                 }
90         }
91         /* no need to call set-dirty - the disconnect will already have done that */
92 }
93
94 void
95 Session::set_just_one_solo (boost::shared_ptr<Route> r, bool yn, SessionEvent::RTeventCallback after)
96 {
97         /* its a bit silly to have to do this, but it keeps the API for this public method sane (we're
98            only going to solo one route) and keeps our ability to use get_rt_event() for the internal
99            private method.
100         */
101
102         boost::shared_ptr<RouteList> rl (new RouteList);
103         rl->push_back (r);
104
105         queue_event (get_rt_event (rl, yn, after, false, &Session::rt_set_just_one_solo));
106 }
107
108 void
109 Session::rt_set_just_one_solo (boost::shared_ptr<RouteList> just_one, bool yn, bool /*ignored*/)
110 {
111         boost::shared_ptr<RouteList> rl = routes.reader ();
112         boost::shared_ptr<Route> r = just_one->front();
113
114         for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
115                 if (!(*i)->is_auditioner() && r != *i) {
116                         (*i)->set_solo (!yn, (*i)->route_group());
117                 }
118         }
119
120         r->set_solo (yn, r->route_group());
121
122         set_dirty();
123 }
124
125 void
126 Session::set_listen (boost::shared_ptr<RouteList> rl, bool yn, SessionEvent::RTeventCallback after, bool group_override)
127 {
128         queue_event (get_rt_event (rl, yn, after, group_override, &Session::rt_set_listen));
129 }
130
131 void
132 Session::rt_set_listen (boost::shared_ptr<RouteList> rl, bool yn, bool /*group_override*/ )
133 {
134         for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
135                 if (!(*i)->is_auditioner()) {
136                         (*i)->set_listen (yn, this);
137                 }
138         }
139
140         set_dirty();
141 }
142
143 void
144 Session::set_mute (boost::shared_ptr<RouteList> rl, bool yn, SessionEvent::RTeventCallback after, bool group_override)
145 {
146         /* Set superficial value of mute controls for automation. */
147         for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
148                 boost::shared_ptr<Route::MuteControllable> mc = (*i)->mute_control();
149                 mc->set_superficial_value(yn);
150         }
151
152         queue_event (get_rt_event (rl, yn, after, group_override, &Session::rt_set_mute));
153 }
154
155 void
156 Session::rt_set_mute (boost::shared_ptr<RouteList> rl, bool yn, bool /*group_override*/)
157 {
158         for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
159                 if (!(*i)->is_monitor() && !(*i)->is_auditioner()) {
160                         (*i)->set_mute (yn, this);
161                 }
162         }
163
164         set_dirty();
165 }
166
167 void
168 Session::set_solo_isolated (boost::shared_ptr<RouteList> rl, bool yn, SessionEvent::RTeventCallback after, bool group_override)
169 {
170         queue_event (get_rt_event (rl, yn, after, group_override, &Session::rt_set_solo_isolated));
171 }
172
173 void
174 Session::rt_set_solo_isolated (boost::shared_ptr<RouteList> rl, bool yn, bool /*group_override*/)
175 {
176         for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
177                 if (!(*i)->is_master() && !(*i)->is_monitor() && !(*i)->is_auditioner()) {
178                         (*i)->set_solo_isolated (yn, this);
179                 }
180         }
181
182         set_dirty();
183 }
184
185 void
186 Session::set_record_enabled (boost::shared_ptr<RouteList> rl, bool yn, SessionEvent::RTeventCallback after, bool group_override)
187 {
188         if (!writable()) {
189                 return;
190         }
191
192         /* do the non-RT part of rec-enabling first - the RT part will be done
193          * on the next process cycle. This does mean that theoretically we are
194          * doing things provisionally on the assumption that the rec-enable
195          * change will work, but this had better be a solid assumption for
196          * other reasons.
197          */
198
199         for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
200                 if ((*i)->is_auditioner() || (*i)->record_safe ()) {
201                         continue;
202                 }
203
204                 boost::shared_ptr<Track> t;
205
206                 if ((t = boost::dynamic_pointer_cast<Track>(*i)) != 0) {
207                         t->prep_record_enabled (yn, (group_override ? (void*) t->route_group() : (void *) this));
208                 }
209         }
210
211         queue_event (get_rt_event (rl, yn, after, group_override, &Session::rt_set_record_enabled));
212 }
213
214 void
215 Session::rt_set_record_enabled (boost::shared_ptr<RouteList> rl, bool yn, bool group_override)
216 {
217         for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
218                 if ((*i)->is_auditioner() || (*i)->record_safe ()) {
219                         continue;
220                 }
221
222                 boost::shared_ptr<Track> t;
223
224                 if ((t = boost::dynamic_pointer_cast<Track>(*i)) != 0) {
225                         t->set_record_enabled (yn, (group_override ? (void*) t->route_group() : (void *) this));
226                 }
227         }
228
229         set_dirty ();
230 }
231
232
233 void
234 Session::set_record_safe (boost::shared_ptr<RouteList> rl, bool yn, SessionEvent::RTeventCallback after, bool group_override)
235 {
236         set_record_enabled (rl, false, after, group_override);
237         queue_event (get_rt_event (rl, yn, after, group_override, &Session::rt_set_record_safe));
238 }
239
240 void
241 Session::rt_set_record_safe (boost::shared_ptr<RouteList> rl, bool yn, bool group_override)
242 {
243         for (RouteList::iterator i = rl->begin (); i != rl->end (); ++i) {
244                 if ((*i)->is_auditioner ()) { // REQUIRES REVIEW Can audiotioner be in Record Safe mode?
245                         continue;
246                 }
247             
248                 boost::shared_ptr<Track> t;
249             
250                 if ((t = boost::dynamic_pointer_cast<Track>(*i)) != 0) {
251                         t->set_record_safe (yn, (group_override ? (void*) t->route_group () : (void *) this));
252                 }
253         }
254         
255         set_dirty ();
256 }
257
258 void
259 Session::process_rtop (SessionEvent* ev)
260 {
261         ev->rt_slot ();
262
263         if (ev->event_loop) {
264                 ev->event_loop->call_slot (MISSING_INVALIDATOR, boost::bind (ev->rt_return, ev));
265         } else {
266                 warning << string_compose ("programming error: %1", X_("Session RT event queued from thread without a UI - cleanup in RT thread!")) << endmsg;
267                 ev->rt_return (ev);
268         }
269 }