try to make sure faderport shows the same strip as the editor mixer strip
[ardour.git] / libs / surfaces / control_protocol / control_protocol.cc
1 /*
2     Copyright (C) 2006 Paul Davis
3
4     This program is free software; you can redistribute it
5     and/or modify it under the terms of the GNU Lesser
6     General Public License as published by the Free Software
7     Foundation; either version 2 of the License, or (at your
8     option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18
19 */
20
21 #include "pbd/error.h"
22
23 #include "ardour/gain_control.h"
24 #include "ardour/session.h"
25 #include "ardour/record_enable_control.h"
26 #include "ardour/route.h"
27 #include "ardour/audio_track.h"
28 #include "ardour/meter.h"
29 #include "ardour/amp.h"
30 #include "control_protocol/control_protocol.h"
31
32 using namespace ARDOUR;
33 using namespace std;
34 using namespace PBD;
35
36 Signal0<void>       ControlProtocol::ZoomToSession;
37 Signal0<void>       ControlProtocol::ZoomOut;
38 Signal0<void>       ControlProtocol::ZoomIn;
39 Signal0<void>       ControlProtocol::Enter;
40 Signal0<void>       ControlProtocol::Undo;
41 Signal0<void>       ControlProtocol::Redo;
42 Signal1<void,float> ControlProtocol::ScrollTimeline;
43 Signal1<void,uint32_t> ControlProtocol::GotoView;
44 Signal0<void> ControlProtocol::CloseDialog;
45 PBD::Signal0<void> ControlProtocol::VerticalZoomInAll;
46 PBD::Signal0<void> ControlProtocol::VerticalZoomOutAll;
47 PBD::Signal0<void> ControlProtocol::VerticalZoomInSelected;
48 PBD::Signal0<void> ControlProtocol::VerticalZoomOutSelected;
49 PBD::Signal0<void>          ControlProtocol::StepTracksDown;
50 PBD::Signal0<void>          ControlProtocol::StepTracksUp;
51
52 PBD::Signal1<void,boost::shared_ptr<ARDOUR::Stripable> > ControlProtocol::AddStripableToSelection;
53 PBD::Signal1<void,boost::shared_ptr<ARDOUR::Stripable> > ControlProtocol::SetStripableSelection;
54 PBD::Signal1<void,boost::shared_ptr<ARDOUR::Stripable> > ControlProtocol::ToggleStripableSelection;
55 PBD::Signal1<void,boost::shared_ptr<ARDOUR::Stripable> > ControlProtocol::RemoveStripableFromSelection;
56 PBD::Signal0<void>          ControlProtocol::ClearStripableSelection;
57
58 PBD::Signal1<void,StripableNotificationListPtr> ControlProtocol::StripableSelectionChanged;
59
60 Glib::Threads::Mutex ControlProtocol::special_stripable_mutex;
61 boost::weak_ptr<Stripable> ControlProtocol::_first_selected_stripable;
62 boost::weak_ptr<Stripable> ControlProtocol::_leftmost_mixer_stripable;
63 StripableNotificationList ControlProtocol::_last_selected;
64 bool ControlProtocol::selection_connected = false;
65 PBD::ScopedConnection ControlProtocol::selection_connection;
66
67 const std::string ControlProtocol::state_node_name ("Protocol");
68
69 ControlProtocol::ControlProtocol (Session& s, string str)
70         : BasicUI (s)
71         , _name (str)
72         , _active (false)
73 {
74         if (!selection_connected) {
75                 /* this is all static, connect it only once (and early), for all ControlProtocols */
76
77                 StripableSelectionChanged.connect_same_thread (selection_connection, boost::bind (&ControlProtocol::stripable_selection_changed, _1));
78                 selection_connected = true;
79         }
80 }
81
82 ControlProtocol::~ControlProtocol ()
83 {
84 }
85
86 int
87 ControlProtocol::set_active (bool yn)
88 {
89         _active = yn;
90         return 0;
91 }
92
93 void
94 ControlProtocol::next_track (uint32_t initial_id)
95 {
96         // STRIPABLE route_table[0] = _session->get_nth_stripable (++initial_id, RemoteControlID::Route);
97 }
98
99 void
100 ControlProtocol::prev_track (uint32_t initial_id)
101 {
102         if (!initial_id) {
103                 return;
104         }
105         // STRIPABLE route_table[0] = _session->get_nth_stripable (--initial_id, RemoteControlID::Route);
106 }
107
108 void
109 ControlProtocol::set_route_table_size (uint32_t size)
110 {
111         while (route_table.size() < size) {
112                 route_table.push_back (boost::shared_ptr<Route> ((Route*) 0));
113         }
114 }
115
116 void
117 ControlProtocol::set_route_table (uint32_t table_index, boost::shared_ptr<ARDOUR::Route> r)
118 {
119         if (table_index >= route_table.size()) {
120                 return;
121         }
122
123         route_table[table_index] = r;
124
125         // XXX SHAREDPTR need to handle r->GoingAway
126 }
127
128 bool
129 ControlProtocol::set_route_table (uint32_t table_index, uint32_t remote_control_id)
130 {
131 #if 0 // STRIPABLE
132         boost::shared_ptr<Route> r = session->route_by_remote_id (remote_control_id);
133
134         if (!r) {
135                 return false;
136         }
137
138         set_route_table (table_index, r);
139 #endif
140         return true;
141 }
142
143 void
144 ControlProtocol::route_set_rec_enable (uint32_t table_index, bool yn)
145 {
146         if (table_index > route_table.size()) {
147                 return;
148         }
149
150         boost::shared_ptr<Route> r = route_table[table_index];
151
152         boost::shared_ptr<AudioTrack> at = boost::dynamic_pointer_cast<AudioTrack>(r);
153
154         if (at) {
155                 at->rec_enable_control()->set_value (1.0, Controllable::UseGroup);
156         }
157 }
158
159 bool
160 ControlProtocol::route_get_rec_enable (uint32_t table_index)
161 {
162         if (table_index > route_table.size()) {
163                 return false;
164         }
165
166         boost::shared_ptr<Route> r = route_table[table_index];
167
168         boost::shared_ptr<AudioTrack> at = boost::dynamic_pointer_cast<AudioTrack>(r);
169
170         if (at) {
171                 return at->rec_enable_control()->get_value();
172         }
173
174         return false;
175 }
176
177
178 float
179 ControlProtocol::route_get_gain (uint32_t table_index)
180 {
181         if (table_index > route_table.size()) {
182                 return 0.0f;
183         }
184
185         boost::shared_ptr<Route> r = route_table[table_index];
186
187         if (r == 0) {
188                 return 0.0f;
189         }
190
191         return r->gain_control()->get_value();
192 }
193
194 void
195 ControlProtocol::route_set_gain (uint32_t table_index, float gain)
196 {
197         if (table_index > route_table.size()) {
198                 return;
199         }
200
201         boost::shared_ptr<Route> r = route_table[table_index];
202
203         if (r != 0) {
204                 r->gain_control()->set_value (gain, Controllable::UseGroup);
205         }
206 }
207
208 float
209 ControlProtocol::route_get_effective_gain (uint32_t table_index)
210 {
211         if (table_index > route_table.size()) {
212                 return 0.0f;
213         }
214
215         boost::shared_ptr<Route> r = route_table[table_index];
216
217         if (r == 0) {
218                 return 0.0f;
219         }
220
221         return r->amp()->gain_control()->get_value();
222 }
223
224
225 float
226 ControlProtocol::route_get_peak_input_power (uint32_t table_index, uint32_t which_input)
227 {
228         if (table_index > route_table.size()) {
229                 return 0.0f;
230         }
231
232         boost::shared_ptr<Route> r = route_table[table_index];
233
234         if (r == 0) {
235                 return 0.0f;
236         }
237
238         return r->peak_meter()->meter_level (which_input, MeterPeak);
239 }
240
241 bool
242 ControlProtocol::route_get_muted (uint32_t table_index)
243 {
244         if (table_index > route_table.size()) {
245                 return false;
246         }
247
248         boost::shared_ptr<Route> r = route_table[table_index];
249
250         if (r == 0) {
251                 return false;
252         }
253
254         return r->mute_control()->muted ();
255 }
256
257 void
258 ControlProtocol::route_set_muted (uint32_t table_index, bool yn)
259 {
260         if (table_index > route_table.size()) {
261                 return;
262         }
263
264         boost::shared_ptr<Route> r = route_table[table_index];
265
266         if (r != 0) {
267                 r->mute_control()->set_value (yn ? 1.0 : 0.0, Controllable::UseGroup);
268         }
269 }
270
271
272 bool
273 ControlProtocol::route_get_soloed (uint32_t table_index)
274 {
275         if (table_index > route_table.size()) {
276                 return false;
277         }
278
279         boost::shared_ptr<Route> r = route_table[table_index];
280
281         if (r == 0) {
282                 return false;
283         }
284
285         return r->soloed ();
286 }
287
288 void
289 ControlProtocol::route_set_soloed (uint32_t table_index, bool yn)
290 {
291         if (table_index > route_table.size()) {
292                 return;
293         }
294
295         boost::shared_ptr<Route> r = route_table[table_index];
296
297         if (r != 0) {
298                 r->solo_control()->set_value (yn ? 1.0 : 0.0, Controllable::UseGroup); // XXX does not propagate
299                 //_session->set_control (r->solo_control(), yn ? 1.0 : 0.0, Controllable::UseGroup); // << correct way, needs a session ptr
300         }
301 }
302
303 string
304 ControlProtocol:: route_get_name (uint32_t table_index)
305 {
306         if (table_index > route_table.size()) {
307                 return "";
308         }
309
310         boost::shared_ptr<Route> r = route_table[table_index];
311
312         if (r == 0) {
313                 return "";
314         }
315
316         return r->name();
317 }
318
319 list<boost::shared_ptr<Bundle> >
320 ControlProtocol::bundles ()
321 {
322         return list<boost::shared_ptr<Bundle> > ();
323 }
324
325 XMLNode&
326 ControlProtocol::get_state ()
327 {
328         XMLNode* node = new XMLNode (state_node_name);
329
330         node->add_property ("name", _name);
331         node->add_property ("feedback", get_feedback() ? "yes" : "no");
332
333         return *node;
334 }
335
336 int
337 ControlProtocol::set_state (XMLNode const & node, int /* version */)
338 {
339         const XMLProperty* prop;
340
341         if ((prop = node.property ("feedback")) != 0) {
342                 set_feedback (string_is_affirmative (prop->value()));
343         }
344
345         return 0;
346 }
347
348 boost::shared_ptr<Stripable>
349 ControlProtocol::first_selected_stripable ()
350 {
351         Glib::Threads::Mutex::Lock lm (special_stripable_mutex);
352         return _first_selected_stripable.lock();
353 }
354
355 boost::shared_ptr<Stripable>
356 ControlProtocol::leftmost_mixer_stripable ()
357 {
358         Glib::Threads::Mutex::Lock lm (special_stripable_mutex);
359         return _leftmost_mixer_stripable.lock();
360 }
361
362 void
363 ControlProtocol::set_leftmost_mixer_stripable (boost::shared_ptr<Stripable> s)
364 {
365         Glib::Threads::Mutex::Lock lm (special_stripable_mutex);
366         _leftmost_mixer_stripable = s;
367 }
368
369 void
370 ControlProtocol::set_first_selected_stripable (boost::shared_ptr<Stripable> s)
371 {
372         Glib::Threads::Mutex::Lock lm (special_stripable_mutex);
373         _first_selected_stripable = s;
374 }
375
376 void
377 ControlProtocol::stripable_selection_changed (StripableNotificationListPtr sp)
378 {
379         bool had_selection = !_last_selected.empty();
380
381         _last_selected = *sp;
382
383         {
384                 Glib::Threads::Mutex::Lock lm (special_stripable_mutex);
385
386                 if (!_last_selected.empty()) {
387                         if (!had_selection) {
388                                 _first_selected_stripable = _last_selected.front().lock();
389                         }
390                 } else {
391                         _first_selected_stripable = boost::weak_ptr<Stripable>();
392                 }
393         }
394 }