1 /*
2  * Copyright (C) 1999-2017 Paul Davis <paul@linuxaudiosystems.com>
3  * Copyright (C) 2011-2014 David Robillard <d@drobilla.net>
4  * Copyright (C) 2015 Robin Gareus <robin@gareus.org>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20 
21 #include <boost/bind.hpp>
22 
23 #include "pbd/error.h"
24 #include "pbd/compose.h"
25 
26 #include "ardour/audioengine.h"
27 #include "ardour/monitor_control.h"
28 #include "ardour/route.h"
29 #include "ardour/session.h"
30 #include "ardour/solo_mute_release.h"
31 #include "ardour/track.h"
32 #include "ardour/vca_manager.h"
33 
34 #include "pbd/i18n.h"
35 
36 using namespace std;
37 using namespace PBD;
38 using namespace ARDOUR;
39 using namespace Glib;
40 
41 void
set_controls(boost::shared_ptr<ControlList> cl,double val,Controllable::GroupControlDisposition gcd)42 Session::set_controls (boost::shared_ptr<ControlList> cl, double val, Controllable::GroupControlDisposition gcd)
43 {
44 	if (cl->empty()) {
45 		return;
46 	}
47 
48 	for (ControlList::iterator ci = cl->begin(); ci != cl->end(); ++ci) {
49 		/* as of july 2017 this is a no-op for everything except record enable */
50 		(*ci)->pre_realtime_queue_stuff (val, gcd);
51 	}
52 
53 	queue_event (get_rt_event (cl, val, gcd));
54 }
55 
56 void
set_control(boost::shared_ptr<AutomationControl> ac,double val,Controllable::GroupControlDisposition gcd)57 Session::set_control (boost::shared_ptr<AutomationControl> ac, double val, Controllable::GroupControlDisposition gcd)
58 {
59 	if (!ac) {
60 		return;
61 	}
62 
63 	boost::shared_ptr<ControlList> cl (new ControlList);
64 	cl->push_back (ac);
65 	set_controls (cl, val, gcd);
66 }
67 
68 void
rt_set_controls(boost::shared_ptr<ControlList> cl,double val,Controllable::GroupControlDisposition gcd)69 Session::rt_set_controls (boost::shared_ptr<ControlList> cl, double val, Controllable::GroupControlDisposition gcd)
70 {
71 	/* Note that we require that all controls in the ControlList are of the
72 	   same type.
73 	*/
74 	if (cl->empty()) {
75 		return;
76 	}
77 
78 	for (ControlList::iterator c = cl->begin(); c != cl->end(); ++c) {
79 		(*c)->set_value (val, gcd);
80 	}
81 
82 	/* some controls need global work to take place after they are set. Do
83 	 * that here.
84 	 */
85 
86 	switch (cl->front()->parameter().type()) {
87 	case SoloAutomation:
88 		update_route_solo_state ();
89 		break;
90 	default:
91 		break;
92 	}
93 }
94 
95 void
prepare_momentary_solo(SoloMuteRelease * smr,bool exclusive,boost::shared_ptr<Route> route)96 Session::prepare_momentary_solo (SoloMuteRelease* smr, bool exclusive, boost::shared_ptr<Route> route)
97 {
98 	boost::shared_ptr<RouteList> routes_on (new RouteList);
99 	boost::shared_ptr<RouteList> routes_off (new RouteList);
100 	boost::shared_ptr<RouteList> routes = get_routes();
101 
102 	for (RouteList::const_iterator i = routes->begin(); i != routes->end(); ++i) {
103 #ifdef MIXBUS
104 		if (route && (0 == route->mixbus()) != (0 == (*i)->mixbus ())) {
105 			continue;
106 		}
107 #endif
108 		if ((*i)->soloed ()) {
109 			routes_on->push_back (*i);
110 		} else if (smr) {
111 			routes_off->push_back (*i);
112 		}
113 	}
114 
115 	if (exclusive) {
116 		set_controls (route_list_to_control_list (routes_on, &Stripable::solo_control), false, Controllable::UseGroup);
117 	}
118 
119 	if (smr) {
120 		smr->set (routes_on, routes_off);
121 	}
122 
123 	if (_monitor_out) {
124 		if (smr) {
125 			boost::shared_ptr<std::list<std::string> > pml (new std::list<std::string>);
126 			_engine.monitor_port().active_monitors (*pml);
127 			smr->set (pml);
128 		}
129 		if (exclusive) {
130 			/* unset any input monitors */
131 			_engine.monitor_port().clear_ports (false);
132 		}
133 	}
134 }
135 
136 void
clear_all_solo_state(boost::shared_ptr<RouteList> rl)137 Session::clear_all_solo_state (boost::shared_ptr<RouteList> rl)
138 {
139 	queue_event (get_rt_event (rl, false, rt_cleanup, Controllable::NoGroup, &Session::rt_clear_all_solo_state));
140 }
141 
142 void
rt_clear_all_solo_state(boost::shared_ptr<RouteList> rl,bool,Controllable::GroupControlDisposition)143 Session::rt_clear_all_solo_state (boost::shared_ptr<RouteList> rl, bool /* yn */, Controllable::GroupControlDisposition /* group_override */)
144 {
145 	for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
146 		if ((*i)->is_auditioner()) {
147 			continue;
148 		}
149 		(*i)->clear_all_solo_state();
150 	}
151 
152 	_vca_manager->clear_all_solo_state ();
153 
154 	update_route_solo_state ();
155 }
156 
157 void
process_rtop(SessionEvent * ev)158 Session::process_rtop (SessionEvent* ev)
159 {
160 	ev->rt_slot ();
161 
162 	if (ev->event_loop) {
163 		ev->event_loop->call_slot (MISSING_INVALIDATOR, boost::bind (ev->rt_return, ev));
164 	} else {
165 		warning << string_compose ("programming error: %1", X_("Session RT event queued from thread without a UI - cleanup in RT thread!")) << endmsg;
166 		ev->rt_return (ev);
167 	}
168 }
169