OSC: allow setting of marker name
[ardour.git] / libs / surfaces / osc / osc_select_observer.cc
1 /*
2     Copyright (C) 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
20 #include <vector>
21 #include "boost/lambda/lambda.hpp"
22
23 #include "pbd/control_math.h"
24
25 #include "ardour/session.h"
26 #include "ardour/track.h"
27 #include "ardour/monitor_control.h"
28 #include "ardour/dB.h"
29 #include "ardour/meter.h"
30 #include "ardour/phase_control.h"
31 #include "ardour/solo_isolate_control.h"
32 #include "ardour/solo_safe_control.h"
33 #include "ardour/route.h"
34 #include "ardour/route_group.h"
35 #include "ardour/send.h"
36 #include "ardour/plugin.h"
37 #include "ardour/plugin_insert.h"
38 #include "ardour/processor.h"
39 #include "ardour/readonly_control.h"
40
41 #include "osc.h"
42 #include "osc_select_observer.h"
43
44 #include <glibmm.h>
45
46 #include "pbd/i18n.h"
47
48 using namespace std;
49 using namespace PBD;
50 using namespace ARDOUR;
51 using namespace ArdourSurface;
52
53 OSCSelectObserver::OSCSelectObserver (OSC& o, ArdourSurface::OSC::OSCSurface* su)
54         : _osc (o)
55         ,sur (su)
56         ,nsends (0)
57         ,_last_gain (-1.0)
58         ,_last_trim (-1.0)
59         ,_init (true)
60         ,eq_bands (0)
61         ,_expand (2048)
62 {
63         addr = lo_address_new_from_url  (sur->remote_url.c_str());
64         gainmode = sur->gainmode;
65         feedback = sur->feedback;
66         in_line = feedback[2];
67         send_page_size = sur->send_page_size;
68         send_size = send_page_size;
69         send_page = sur->send_page;
70         plug_page_size = sur->plug_page_size;
71         plug_size = plug_page_size;
72         plug_page = sur->plug_page;
73         if (sur->plugins.size () > 0) {
74                 plug_id = sur->plugins[sur->plugin_id - 1];
75         } else {
76                 plug_id = -1;
77         }
78         refresh_strip (sur->select, sur->nsends, gainmode, true);
79         set_expand (sur->expand_enable);
80 }
81
82 OSCSelectObserver::~OSCSelectObserver ()
83 {
84         _init = true;
85         no_strip ();
86         lo_address_free (addr);
87 }
88
89 void
90 OSCSelectObserver::no_strip ()
91 {
92         // This gets called on drop references
93         _init = true;
94
95         strip_connections.drop_connections ();
96         send_connections.drop_connections ();
97         plugin_connections.drop_connections ();
98         eq_connections.drop_connections ();
99         /*
100          * The strip will sit idle at this point doing nothing until
101          * the surface has recalculated it's strip list and then calls
102          * refresh_strip. Otherwise refresh strip will get a strip address
103          * that does not exist... Crash
104          */
105  }
106
107 void
108 OSCSelectObserver::refresh_strip (boost::shared_ptr<ARDOUR::Stripable> new_strip, uint32_t s_nsends, uint32_t gm, bool force)
109 {
110         _init = true;
111         if (_tick_busy) {
112                 Glib::usleep(100); // let tick finish
113         }
114         gainmode = gm;
115
116         if (_strip && (new_strip == _strip) && !force) {
117                 _init = false;
118                 return;
119         }
120
121         _strip = new_strip;
122         if (!_strip) {
123                 clear_observer ();
124                 return;
125         }
126
127         _strip->DropReferences.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCSelectObserver::no_strip, this), OSC::instance());
128         as = ARDOUR::Off;
129         _comp_redux = 1;
130         nsends = s_nsends;
131         _last_gain = -1.0;
132         _last_trim = -1.0;
133
134         _strip->PropertyChanged.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCSelectObserver::name_changed, this, boost::lambda::_1), OSC::instance());
135         name_changed (ARDOUR::Properties::name);
136
137         boost::shared_ptr<Route> rt = boost::dynamic_pointer_cast<Route> (_strip);
138         if (rt) {
139                 rt->route_group_changed.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCSelectObserver::group_name, this), OSC::instance());
140                 group_name ();
141
142                 rt->comment_changed.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCSelectObserver::comment_changed, this), OSC::instance());
143                 comment_changed ();
144         }
145
146         _strip->presentation_info().PropertyChanged.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCSelectObserver::pi_changed, this, _1), OSC::instance());
147         _osc.float_message (X_("/select/hide"), _strip->is_hidden (), addr);
148
149         _strip->mute_control()->Changed.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCSelectObserver::change_message, this, X_("/select/mute"), _strip->mute_control()), OSC::instance());
150         change_message (X_("/select/mute"), _strip->mute_control());
151
152         _strip->solo_control()->Changed.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCSelectObserver::change_message, this, X_("/select/solo"), _strip->solo_control()), OSC::instance());
153         change_message (X_("/select/solo"), _strip->solo_control());
154
155         if (_strip->solo_isolate_control()) {
156                 _strip->solo_isolate_control()->Changed.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCSelectObserver::change_message, this, X_("/select/solo_iso"), _strip->solo_isolate_control()), OSC::instance());
157                 change_message (X_("/select/solo_iso"), _strip->solo_isolate_control());
158         }
159
160         if (_strip->solo_safe_control()) {
161                 _strip->solo_safe_control()->Changed.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCSelectObserver::change_message, this, X_("/select/solo_safe"), _strip->solo_safe_control()), OSC::instance());
162                 change_message (X_("/select/solo_safe"), _strip->solo_safe_control());
163         }
164
165         boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (_strip);
166         if (track) {
167                 track->monitoring_control()->Changed.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCSelectObserver::monitor_status, this, track->monitoring_control()), OSC::instance());
168                 monitor_status (track->monitoring_control());
169         }
170
171         boost::shared_ptr<AutomationControl> rec_controllable = _strip->rec_enable_control ();
172         if (rec_controllable) {
173                 rec_controllable->Changed.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCSelectObserver::change_message, this, X_("/select/recenable"), _strip->rec_enable_control()), OSC::instance());
174                 change_message (X_("/select/recenable"), _strip->rec_enable_control());
175         }
176
177         boost::shared_ptr<AutomationControl> recsafe_controllable = _strip->rec_safe_control ();
178         if (recsafe_controllable) {
179                 recsafe_controllable->Changed.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCSelectObserver::change_message, this, X_("/select/record_safe"), _strip->rec_safe_control()), OSC::instance());
180                 change_message (X_("/select/record_safe"), _strip->rec_safe_control());
181         }
182
183         boost::shared_ptr<AutomationControl> phase_controllable = _strip->phase_control ();
184         if (phase_controllable) {
185                 phase_controllable->Changed.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCSelectObserver::change_message, this, X_("/select/polarity"), _strip->phase_control()), OSC::instance());
186                 change_message (X_("/select/polarity"), _strip->phase_control());
187         }
188
189         _strip->gain_control()->alist()->automation_state_changed.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCSelectObserver::gain_automation, this), OSC::instance());
190         _strip->gain_control()->Changed.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCSelectObserver::gain_message, this), OSC::instance());
191         gain_automation ();
192
193         boost::shared_ptr<Controllable> trim_controllable = boost::dynamic_pointer_cast<Controllable>(_strip->trim_control());
194         if (trim_controllable) {
195                 trim_controllable->Changed.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCSelectObserver::trim_message, this, X_("/select/trimdB"), _strip->trim_control()), OSC::instance());
196                 trim_message (X_("/select/trimdB"), _strip->trim_control());
197         }
198
199         boost::shared_ptr<Controllable> pan_controllable = boost::dynamic_pointer_cast<Controllable>(_strip->pan_azimuth_control());
200         if (pan_controllable) {
201                 pan_controllable->Changed.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCSelectObserver::change_message, this, X_("/select/pan_stereo_position"), _strip->pan_azimuth_control()), OSC::instance());
202                 change_message (X_("/select/pan_stereo_position"), _strip->pan_azimuth_control());
203         }
204
205         boost::shared_ptr<Controllable> width_controllable = boost::dynamic_pointer_cast<Controllable>(_strip->pan_width_control());
206         if (width_controllable) {
207                 width_controllable->Changed.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCSelectObserver::change_message, this, X_("/select/pan_stereo_width"), _strip->pan_width_control()), OSC::instance());
208                 change_message (X_("/select/pan_stereo_width"), _strip->pan_width_control());
209         }
210
211         // Rest of possible pan controls... Untested because I can't find a way to get them in the GUI :)
212         if (_strip->pan_elevation_control ()) {
213                 _strip->pan_elevation_control()->Changed.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCSelectObserver::change_message, this, X_("/select/pan_elevation_position"), _strip->pan_elevation_control()), OSC::instance());
214                 change_message (X_("/select/pan_elevation_position"), _strip->pan_elevation_control());
215         }
216         if (_strip->pan_frontback_control ()) {
217                 _strip->pan_frontback_control()->Changed.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCSelectObserver::change_message, this, X_("/select/pan_frontback_position"), _strip->pan_frontback_control()), OSC::instance());
218                 change_message (X_("/select/pan_frontback_position"), _strip->pan_frontback_control());
219         }
220         if (_strip->pan_lfe_control ()) {
221                 _strip->pan_lfe_control()->Changed.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCSelectObserver::change_message, this, X_("/select/pan_lfe_control"), _strip->pan_lfe_control()), OSC::instance());
222                 change_message (X_("/select/pan_lfe_control"), _strip->pan_lfe_control());
223         }
224
225         // sends, plugins and eq
226         // detecting processor changes is now in osc.cc
227
228         // but... MB master send enable is different
229         if (_strip->master_send_enable_controllable ()) {
230                 _strip->master_send_enable_controllable ()->Changed.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCSelectObserver::enable_message, this, X_("/select/master_send_enable"), _strip->master_send_enable_controllable()), OSC::instance());
231                 enable_message (X_("/select/master_send_enable"), _strip->master_send_enable_controllable());
232         }
233
234         // Compressor
235         if (_strip->comp_enable_controllable ()) {
236                 _strip->comp_enable_controllable ()->Changed.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCSelectObserver::enable_message, this, X_("/select/comp_enable"), _strip->comp_enable_controllable()), OSC::instance());
237                 enable_message (X_("/select/comp_enable"), _strip->comp_enable_controllable());
238         }
239         if (_strip->comp_threshold_controllable ()) {
240                 _strip->comp_threshold_controllable ()->Changed.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCSelectObserver::change_message, this, X_("/select/comp_threshold"), _strip->comp_threshold_controllable()), OSC::instance());
241                 change_message (X_("/select/comp_threshold"), _strip->comp_threshold_controllable());
242         }
243         if (_strip->comp_speed_controllable ()) {
244                 _strip->comp_speed_controllable ()->Changed.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCSelectObserver::change_message, this, X_("/select/comp_speed"), _strip->comp_speed_controllable()), OSC::instance());
245                 change_message (X_("/select/comp_speed"), _strip->comp_speed_controllable());
246         }
247         if (_strip->comp_mode_controllable ()) {
248                 _strip->comp_mode_controllable ()->Changed.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCSelectObserver::comp_mode, this), OSC::instance());
249                 comp_mode ();
250         }
251         if (_strip->comp_makeup_controllable ()) {
252                 _strip->comp_makeup_controllable ()->Changed.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCSelectObserver::change_message, this, X_("/select/comp_makeup"), _strip->comp_makeup_controllable()), OSC::instance());
253                 change_message (X_("/select/comp_makeup"), _strip->comp_makeup_controllable());
254         }
255         renew_sends ();
256         renew_plugin ();
257         eq_restart(0);
258         _init = false;
259
260         tick();
261 }
262
263 void
264 OSCSelectObserver::set_expand (uint32_t expand)
265 {
266         if (expand != _expand) {
267                 _expand = expand;
268                 if (expand) {
269                         _osc.float_message (X_("/select/expand"), 1.0, addr);
270                 } else {
271                         _osc.float_message (X_("/select/expand"), 0.0, addr);
272                 }
273         }
274 }
275
276 void
277 OSCSelectObserver::clear_observer ()
278 {
279         _init = true;
280         strip_connections.drop_connections ();
281         // all strip buttons should be off and faders 0 and etc.
282         _osc.float_message (X_("/select/expand"), 0, addr);
283         _osc.text_message (X_("/select/name"), " ", addr);
284         _osc.text_message (X_("/select/group"), " ", addr);
285         _osc.text_message (X_("/select/comment"), " ", addr);
286         _osc.float_message (X_("/select/mute"), 0, addr);
287         _osc.float_message (X_("/select/solo"), 0, addr);
288         _osc.float_message (X_("/select/recenable"), 0, addr);
289         _osc.float_message (X_("/select/record_safe"), 0, addr);
290         _osc.float_message (X_("/select/monitor_input"), 0, addr);
291         _osc.float_message (X_("/select/monitor_disk"), 0, addr);
292         _osc.float_message (X_("/select/polarity"), 0, addr);
293         _osc.float_message (X_("/select/n_inputs"), 0, addr);
294         _osc.float_message (X_("/select/n_outputs"), 0, addr);
295         if (gainmode) {
296                 _osc.float_message (X_("/select/fader"), 0, addr);
297         } else {
298                 _osc.float_message (X_("/select/gain"), -193, addr);
299         }
300         _osc.float_message (X_("/select/trimdB"), 0, addr);
301         _osc.float_message (X_("/select/pan_stereo_position"), 0.5, addr);
302         _osc.float_message (X_("/select/pan_stereo_width"), 1, addr);
303         if (feedback[9]) {
304                 _osc.float_message (X_("/select/signal"), 0, addr);
305         }
306         if (feedback[7]) {
307                 if (gainmode) {
308                         _osc.float_message (X_("/select/meter"), 0, addr);
309                 } else {
310                         _osc.float_message (X_("/select/meter"), -193, addr);
311                 }
312         }else if (feedback[8]) {
313                 _osc.float_message (X_("/select/meter"), 0, addr);
314         }
315         _osc.float_message (X_("/select/pan_elevation_position"), 0, addr);
316         _osc.float_message (X_("/select/pan_frontback_position"), .5, addr);
317         _osc.float_message (X_("/select/pan_lfe_control"), 0, addr);
318         _osc.float_message (X_("/select/comp_enable"), 0, addr);
319         _osc.float_message (X_("/select/comp_threshold"), 0, addr);
320         _osc.float_message (X_("/select/comp_speed"), 0, addr);
321         _osc.float_message (X_("/select/comp_mode"), 0, addr);
322         _osc.text_message (X_("/select/comp_mode_name"), " ", addr);
323         _osc.text_message (X_("/select/comp_speed_name"), " ", addr);
324         _osc.float_message (X_("/select/comp_makeup"), 0, addr);
325         _osc.float_message (X_("/select/expand"), 0.0, addr);
326         send_end();
327         plugin_end();
328         eq_end();
329 }
330
331 void
332 OSCSelectObserver::set_send_page (uint32_t page)
333 {
334         if (send_page != page) {
335                 send_page = page;
336                 renew_sends ();
337         }
338 }
339
340 void
341 OSCSelectObserver::set_send_size (uint32_t size)
342 {
343         send_page_size = size;
344         renew_sends ();
345 }
346
347 void
348 OSCSelectObserver::renew_sends () {
349         send_connections.drop_connections ();
350         send_timeout.clear();
351         send_init();
352 }
353
354 void
355 OSCSelectObserver::send_init()
356 {
357         send_size = nsends;
358         if (send_page_size) {
359                 send_size = send_page_size;
360         }
361         if (!send_size) {
362                 return;
363         }
364         uint32_t page_start = ((send_page - 1) * send_size);
365         uint32_t last_send = send_page * send_size;
366         uint32_t c = 1;
367         send_timeout.push_back (2);
368         _last_send.clear();
369         _last_send.push_back (0.0);
370
371         for (uint32_t s = page_start; s < last_send; ++s, ++c) {
372
373                 bool send_valid = false;
374                 if (_strip->send_level_controllable (s)) {
375                         _strip->send_level_controllable(s)->Changed.connect (send_connections, MISSING_INVALIDATOR, boost::bind (&OSCSelectObserver::send_gain, this, c, _strip->send_level_controllable(s)), OSC::instance());
376                         send_timeout.push_back (2);
377                         _last_send.push_back (20.0);
378                         send_gain (c, _strip->send_level_controllable(s));
379                         send_valid = true;
380                 } else {
381                         send_gain (c, _strip->send_level_controllable(s));
382                         _osc.float_message_with_id (X_("/select/send_enable"), c, 0, in_line, addr);
383                         _osc.text_message_with_id (X_("/select/send_name"), c, " ", in_line, addr);
384                 }
385
386                 if (_strip->send_enable_controllable (s)) {
387                         _strip->send_enable_controllable(s)->Changed.connect (send_connections, MISSING_INVALIDATOR, boost::bind (&OSCSelectObserver::enable_message_with_id, this, X_("/select/send_enable"), c, _strip->send_enable_controllable(s)), OSC::instance());
388                         enable_message_with_id (X_("/select/send_enable"), c, _strip->send_enable_controllable(s));
389                 } else if (send_valid) {
390                         boost::shared_ptr<Route> r = boost::dynamic_pointer_cast<Route> (_strip);
391                         if (!r) {
392                                 // should never get here
393                                 _osc.float_message_with_id (X_("/select/send_enable"), c, 0, in_line, addr);
394                         }
395                         boost::shared_ptr<Send> snd = boost::dynamic_pointer_cast<Send> (r->nth_send(s));
396                         if (snd) {
397                                 boost::shared_ptr<Processor> proc = boost::dynamic_pointer_cast<Processor> (snd);
398                                 proc->ActiveChanged.connect (send_connections, MISSING_INVALIDATOR, boost::bind (&OSCSelectObserver::send_enable, this, X_("/select/send_enable"), c, proc), OSC::instance());
399                                 _osc.float_message_with_id (X_("/select/send_enable"), c, proc->enabled(), in_line, addr);
400                         }
401                 }
402                 if ((gainmode != 1) && send_valid) {
403                         _osc.text_message_with_id (X_("/select/send_name"), c, _strip->send_name(s), in_line, addr);
404                 }
405         }
406 }
407
408 void
409 OSCSelectObserver::send_end ()
410 {
411         send_connections.drop_connections ();
412         for (uint32_t i = 1; i <= send_size; i++) {
413                 if (gainmode) {
414                         _osc.float_message_with_id (X_("/select/send_fader"), i, 0, in_line, addr);
415                 } else {
416                         _osc.float_message_with_id (X_("/select/send_gain"), i, -193, in_line, addr);
417                 }
418                 // next enable
419                 _osc.float_message_with_id (X_("/select/send_enable"), i, 0, in_line, addr);
420                 // next name
421                 _osc.text_message_with_id (X_("/select/send_name"), i, " ", in_line, addr);
422         }
423         // need to delete or clear send_timeout
424         send_size = 0;
425         send_timeout.clear();
426 }
427
428 void
429 OSCSelectObserver::set_plugin_id (int id, uint32_t page)
430 {
431         plug_id = id;
432         plug_page = page;
433         renew_plugin ();
434 }
435
436 void
437 OSCSelectObserver::set_plugin_page (uint32_t page)
438 {
439         plug_page = page;
440         renew_plugin ();
441 }
442
443 void
444 OSCSelectObserver::set_plugin_size (uint32_t size)
445 {
446         plug_page_size = size;
447         renew_plugin ();
448 }
449
450 void
451 OSCSelectObserver::renew_plugin () {
452         plugin_connections.drop_connections ();
453         plugin_init();
454 }
455
456 void
457 OSCSelectObserver::plugin_init()
458 {
459         if (plug_id < 0) {
460                 plugin_end ();
461                 return;
462         }
463         boost::shared_ptr<Route> r = boost::dynamic_pointer_cast<Route>(_strip);
464         if (!r) {
465                 plugin_end ();
466                 return;
467         }
468
469         // we have a plugin number now get the processor
470         boost::shared_ptr<Processor> proc = r->nth_plugin (plug_id);
471         boost::shared_ptr<PluginInsert> pi;
472         if (!(pi = boost::dynamic_pointer_cast<PluginInsert>(proc))) {
473                 plugin_end ();
474                 return;
475         }
476         boost::shared_ptr<ARDOUR::Plugin> pip = pi->plugin();
477         // we have a plugin we can ask if it is activated
478         proc->ActiveChanged.connect (plugin_connections, MISSING_INVALIDATOR, boost::bind (&OSCSelectObserver::plug_enable, this, X_("/select/plugin/activate"), proc), OSC::instance());
479         _osc.float_message (X_("/select/plugin/activate"), proc->enabled(), addr);
480
481         bool ok = false;
482         // put only input controls into a vector
483         plug_params.clear ();
484         uint32_t nplug_params  = pip->parameter_count();
485         for ( uint32_t ppi = 0;  ppi < nplug_params; ++ppi) {
486                 uint32_t controlid = pip->nth_parameter(ppi, ok);
487                 if (!ok) {
488                         continue;
489                 }
490                 if (pip->parameter_is_input(controlid)) {
491                         plug_params.push_back (ppi);
492                 }
493         }
494         nplug_params = plug_params.size ();
495
496         // default of 0 page size means show all
497         plug_size = nplug_params;
498         if (plug_page_size) {
499                 plug_size = plug_page_size;
500         }
501         _osc.text_message (X_("/select/plugin/name"), pip->name(), addr);
502         uint32_t page_start = plug_page - 1;
503         uint32_t page_end = page_start + plug_size;
504
505         int pid = 1;
506         for ( uint32_t ppi = page_start;  ppi < page_end; ++ppi, ++pid) {
507                 if (ppi >= nplug_params) {
508                         _osc.text_message_with_id (X_("/select/plugin/parameter/name"), pid, " ", in_line, addr);
509                         _osc.float_message_with_id (X_("/select/plugin/parameter"), pid, 0, in_line, addr);
510                         continue;
511                 }
512
513                 uint32_t controlid = pip->nth_parameter(plug_params[ppi], ok);
514                 if (!ok) {
515                         continue;
516                 }
517                 ParameterDescriptor pd;
518                 pip->get_parameter_descriptor(controlid, pd);
519                 _osc.text_message_with_id (X_("/select/plugin/parameter/name"), pid, pd.label, in_line, addr);
520                 if ( pip->parameter_is_input(controlid)) {
521                         boost::shared_ptr<AutomationControl> c = pi->automation_control(Evoral::Parameter(PluginAutomation, 0, controlid));
522                         if (c) {
523                                 bool swtch = false;
524                                 if (pd.integer_step && pd.upper == 1) {
525                                         swtch = true;
526                                 }
527                                 c->Changed.connect (plugin_connections, MISSING_INVALIDATOR, boost::bind (&OSCSelectObserver::plugin_parameter_changed, this, pid, swtch, c), OSC::instance());
528                                 plugin_parameter_changed (pid, swtch, c);
529                         }
530                 }
531         }
532 }
533
534 void
535 OSCSelectObserver::plugin_parameter_changed (int pid, bool swtch, boost::shared_ptr<PBD::Controllable> controllable)
536 {
537         if (swtch) {
538                 enable_message_with_id (X_("/select/plugin/parameter"), pid, controllable);
539         } else {
540                 change_message_with_id (X_("/select/plugin/parameter"), pid, controllable);
541         }
542 }
543
544 void
545 OSCSelectObserver::plugin_end ()
546 {
547         plugin_connections.drop_connections ();
548         _osc.float_message (X_("/select/plugin/activate"), 0, addr);
549         _osc.text_message (X_("/select/plugin/name"), " ", addr);
550         for (uint32_t i = 1; i <= plug_size; i++) {
551                 _osc.float_message_with_id (X_("/select/plugin/parameter"), i, 0, in_line, addr);
552                 // next name
553                 _osc.text_message_with_id (X_("/select/plugin/parameter/name"), i, " ", in_line, addr);
554         }
555         plug_size = 0;
556         nplug_params = 0;
557 }
558
559 void
560 OSCSelectObserver::tick ()
561 {
562         if (_init) {
563                 return;
564         }
565         _tick_busy = true;
566         if (feedback[7] || feedback[8] || feedback[9]) { // meters enabled
567                 float now_meter;
568                 if (_strip->peak_meter()) {
569                         now_meter = _strip->peak_meter()->meter_level(0, MeterMCP);
570                 } else {
571                         now_meter = -193;
572                 }
573                 if (now_meter < -144) now_meter = -193;
574                 if (_last_meter != now_meter) {
575                         if (feedback[7] || feedback[8]) {
576                                 string path = X_("/select/meter");
577                                 if (gainmode && feedback[7]) {
578                                         _osc.float_message (path, ((now_meter + 94) / 100), addr);
579                                 } else if ((!gainmode) && feedback[7]) {
580                                         _osc.float_message (path, now_meter, addr);
581                                 } else if (feedback[8]) {
582                                         uint32_t ledlvl = (uint32_t)(((now_meter + 54) / 3.75)-1);
583                                         uint16_t ledbits = ~(0xfff<<ledlvl);
584                                         _osc.float_message (path, ledbits, addr);
585                                 }
586                         }
587                         if (feedback[9]) {
588                                 string path = X_("/select/signal");
589                                 float signal;
590                                 if (now_meter < -40) {
591                                         signal = 0;
592                                 } else {
593                                         signal = 1;
594                                 }
595                                 _osc.float_message (path, signal, addr);
596                         }
597                 }
598                 _last_meter = now_meter;
599
600         }
601         if (gain_timeout) {
602                 if (gain_timeout == 1) {
603                         _osc.text_message (X_("/select/name"), _strip->name(), addr);
604                 }
605                 gain_timeout--;
606         }
607
608         if (as == ARDOUR::Play ||  as == ARDOUR::Touch) {
609                 if(_last_gain != _strip->gain_control()->get_value()) {
610                         _last_gain = _strip->gain_control()->get_value();
611                                 gain_message ();
612                 }
613         }
614         if (_strip->comp_redux_controllable() && _strip->comp_enable_controllable() && _strip->comp_enable_controllable()->get_value()) {
615                 float new_value = _strip->comp_redux_controllable()->get_parameter();
616                 if (_comp_redux != new_value) {
617                         _osc.float_message (X_("/select/comp_redux"), new_value, addr);
618                         _comp_redux = new_value;
619                 }
620         }
621         for (uint32_t i = 1; i <= send_timeout.size(); i++) {
622                 if (send_timeout[i]) {
623                         if (send_timeout[i] == 1) {
624                                 uint32_t pg_offset = (send_page - 1) * send_page_size;
625                                 _osc.text_message_with_id (X_("/select/send_name"), i, _strip->send_name(pg_offset + i - 1), in_line, addr);
626                         }
627                         send_timeout[i]--;
628                 }
629         }
630         _tick_busy = false;
631 }
632
633 void
634 OSCSelectObserver::name_changed (const PBD::PropertyChange& what_changed)
635 {
636         if (!what_changed.contains (ARDOUR::Properties::name)) {
637                 return;
638         }
639
640         if (!_strip) {
641                 return;
642         }
643
644         _osc.text_message (X_("/select/name"), _strip->name(), addr);
645         boost::shared_ptr<Route> route = boost::dynamic_pointer_cast<Route> (_strip);
646         if (route) {
647                 // lets tell the surface how many inputs this strip has
648                 _osc.float_message (X_("/select/n_inputs"), (float) route->n_inputs().n_total(), addr);
649                 // lets tell the surface how many outputs this strip has
650                 _osc.float_message (X_("/select/n_outputs"), (float) route->n_outputs().n_total(), addr);
651         }
652 }
653
654 void
655 OSCSelectObserver::group_name ()
656 {
657         boost::shared_ptr<Route> rt = boost::dynamic_pointer_cast<Route> (_strip);
658
659         RouteGroup *rg = rt->route_group();
660         if (rg) {
661                 _osc.text_message (X_("/select/group"), rg->name(), addr);
662         } else {
663                 _osc.text_message (X_("/select/group"), " ", addr);
664         }
665 }
666
667 void
668 OSCSelectObserver::comment_changed ()
669 {
670         boost::shared_ptr<Route> rt = boost::dynamic_pointer_cast<Route> (_strip);
671         if (rt) {
672                 _osc.text_message (X_("/select/comment"), rt->comment(), addr);
673         }
674 }
675
676 void
677 OSCSelectObserver::pi_changed (PBD::PropertyChange const& what_changed)
678 {
679         _osc.float_message (X_("/select/hide"), _strip->is_hidden (), addr);
680 }
681
682 void
683 OSCSelectObserver::change_message (string path, boost::shared_ptr<Controllable> controllable)
684 {
685         float val = controllable->get_value();
686
687         _osc.float_message (path, (float) controllable->internal_to_interface (val), addr);
688 }
689
690 void
691 OSCSelectObserver::enable_message (string path, boost::shared_ptr<Controllable> controllable)
692 {
693         float val = controllable->get_value();
694         if (val) {
695                 _osc.float_message (path, 1, addr);
696         } else {
697                 _osc.float_message (path, 0, addr);
698         }
699
700 }
701
702 void
703 OSCSelectObserver::plug_enable (string path, boost::shared_ptr<Processor> proc)
704 {
705         // with no delay value is wrong
706         Glib::usleep(10);
707
708         _osc.float_message (path, proc->enabled(), addr);
709 }
710
711 void
712 OSCSelectObserver::change_message_with_id (string path, uint32_t id, boost::shared_ptr<Controllable> controllable)
713 {
714         float val = controllable->get_value();
715
716         _osc.float_message_with_id (path, id, (float) controllable->internal_to_interface (val), in_line, addr);
717 }
718
719 void
720 OSCSelectObserver::enable_message_with_id (string path, uint32_t id, boost::shared_ptr<Controllable> controllable)
721 {
722         float val = controllable->get_value();
723         if (val) {
724                 _osc.float_message_with_id (path, id, 1, in_line, addr);
725         } else {
726                 _osc.float_message_with_id (path, id, 0, in_line, addr);
727         }
728 }
729
730 void
731 OSCSelectObserver::monitor_status (boost::shared_ptr<Controllable> controllable)
732 {
733         int disk, input;
734         float val = controllable->get_value();
735         switch ((int) val) {
736                 case 1:
737                         disk = 0;
738                         input = 1;
739                         break;
740                 case 2:
741                         disk = 1;
742                         input = 0;
743                         break;
744                 default:
745                         disk = 0;
746                         input = 0;
747         }
748
749         _osc.float_message (X_("/select/monitor_input"), (float) input, addr);
750         _osc.float_message (X_("/select/monitor_disk"), (float) disk, addr);
751 }
752
753 void
754 OSCSelectObserver::trim_message (string path, boost::shared_ptr<Controllable> controllable)
755 {
756         if (_last_trim != controllable->get_value()) {
757                 _last_trim = controllable->get_value();
758         } else {
759                 return;
760         }
761
762         _osc.float_message (path, (float) accurate_coefficient_to_dB (controllable->get_value()), addr);
763 }
764
765 void
766 OSCSelectObserver::gain_message ()
767 {
768         float value = _strip->gain_control()->get_value();
769         if (_last_gain != value) {
770                 _last_gain = value;
771         } else {
772                 return;
773         }
774
775         if (gainmode) {
776                 _osc.float_message (X_("/select/fader"), _strip->gain_control()->internal_to_interface (value), addr);
777                 if (gainmode == 1) {
778                         _osc.text_message (X_("/select/name"), string_compose ("%1%2%3", std::fixed, std::setprecision(2), accurate_coefficient_to_dB (value)), addr);
779                         gain_timeout = 8;
780                 }
781         }
782         if (!gainmode || gainmode == 2) {
783                 if (value < 1e-15) {
784                         _osc.float_message (X_("/select/gain"), -200, addr);
785                 } else {
786                         _osc.float_message (X_("/select/gain"), accurate_coefficient_to_dB (value), addr);
787                 }
788         }
789 }
790
791 void
792 OSCSelectObserver::gain_automation ()
793 {
794         float output = 0;
795         as = _strip->gain_control()->alist()->automation_state();
796         string auto_name;
797         switch (as) {
798                 case ARDOUR::Off:
799                         output = 0;
800                         auto_name = "Manual";
801                         break;
802                 case ARDOUR::Play:
803                         output = 1;
804                         auto_name = "Play";
805                         break;
806                 case ARDOUR::Write:
807                         output = 2;
808                         auto_name = "Write";
809                         break;
810                 case ARDOUR::Touch:
811                         output = 3;
812                         auto_name = "Touch";
813                         break;
814                 default:
815                         break;
816         }
817
818         if (gainmode) {
819                 _osc.float_message (X_("/select/fader/automation"), output, addr);
820                 _osc.text_message (X_("/select/fader/automation_name"), auto_name, addr);
821         } else {
822                 _osc.float_message (X_("/select/gain/automation"), output, addr);
823                 _osc.text_message (X_("/select/gain/automation_name"), auto_name, addr);
824         }
825
826         gain_message ();
827 }
828
829 void
830 OSCSelectObserver::send_gain (uint32_t id, boost::shared_ptr<PBD::Controllable> controllable)
831 {
832         float raw_value = 0.0;
833         if (controllable) {
834                 raw_value = controllable->get_value();
835         }
836         if (_last_send[id] != raw_value) {
837                 _last_send[id] = raw_value;
838         } else {
839                 return;
840         }
841         string path;
842         float value = 0.0;
843         float db;
844 #ifdef MIXBUS
845         if (controllable) {
846                 db = raw_value;
847         } else {
848                 db = -193;
849         }
850 #else
851         if (raw_value < 1e-15) {
852                 db = -193;
853         } else {
854                 db = accurate_coefficient_to_dB (raw_value);
855         }
856 #endif
857
858         if (gainmode) {
859                 if (controllable) {
860                         value = controllable->internal_to_interface (raw_value);
861                 }
862                 _osc.float_message_with_id (X_("/select/send_fader"), id, value, in_line, addr);
863                 if (gainmode == 1) {
864                         _osc.text_message_with_id (X_("/select/send_name") , id, string_compose ("%1%2%3", std::fixed, std::setprecision(2), db), in_line, addr);
865                         if (send_timeout.size() > id) {
866                                 send_timeout[id] = 8;
867                         }
868                 }
869         }
870         if (!gainmode || gainmode == 2) {
871                 _osc.float_message_with_id (X_("/select/send_gain"), id, db, in_line, addr);
872         }
873
874 }
875
876 void
877 OSCSelectObserver::send_enable (string path, uint32_t id, boost::shared_ptr<Processor> proc)
878 {
879         // with no delay value is wrong
880         Glib::usleep(10);
881
882         _osc.float_message_with_id (X_("/select/send_enable"), id, proc->enabled(), in_line, addr);
883 }
884
885 void
886 OSCSelectObserver::comp_mode ()
887 {
888         change_message (X_("/select/comp_mode"), _strip->comp_mode_controllable());
889         _osc.text_message (X_("/select/comp_mode_name"), _strip->comp_mode_name(_strip->comp_mode_controllable()->get_value()), addr);
890         _osc.text_message (X_("/select/comp_speed_name"), _strip->comp_speed_name(_strip->comp_mode_controllable()->get_value()), addr);
891 }
892
893 void
894 OSCSelectObserver::eq_init()
895 {
896         // HPF and enable are special case, rest are in bands
897         if (_strip->filter_enable_controllable (true)) {
898                 _strip->filter_enable_controllable (true)->Changed.connect (eq_connections, MISSING_INVALIDATOR, boost::bind (&OSCSelectObserver::change_message, this, X_("/select/eq_hpf/enable"), _strip->filter_enable_controllable (true)), OSC::instance());
899                 change_message (X_("/select/eq_hpf/enable"), _strip->filter_enable_controllable(true));
900         }
901
902         if (_strip->filter_enable_controllable (false)) {
903                 _strip->filter_enable_controllable (false)->Changed.connect (eq_connections, MISSING_INVALIDATOR, boost::bind (&OSCSelectObserver::change_message, this, X_("/select/eq_lpf/enable"), _strip->filter_enable_controllable (false)), OSC::instance());
904                 change_message (X_("/select/eq_lpf/enable"), _strip->filter_enable_controllable(false));
905         }
906
907         if (_strip->filter_freq_controllable (true)) {
908                 _strip->filter_freq_controllable (true)->Changed.connect (eq_connections, MISSING_INVALIDATOR, boost::bind (&OSCSelectObserver::change_message, this, X_("/select/eq_hpf/freq"), _strip->filter_freq_controllable (true)), OSC::instance());
909                 change_message (X_("/select/eq_hpf/freq"), _strip->filter_freq_controllable(true));
910         }
911
912         if (_strip->filter_freq_controllable (false)) {
913                 _strip->filter_freq_controllable (false)->Changed.connect (eq_connections, MISSING_INVALIDATOR, boost::bind (&OSCSelectObserver::change_message, this, X_("/select/eq_lpf/freq"), _strip->filter_freq_controllable (false)), OSC::instance());
914                 change_message (X_("/select/eq_lpf/freq"), _strip->filter_freq_controllable(false));
915         }
916
917         if (_strip->filter_slope_controllable (true)) {
918                 _strip->filter_slope_controllable (true)->Changed.connect (eq_connections, MISSING_INVALIDATOR, boost::bind (&OSCSelectObserver::change_message, this, X_("/select/eq_hpf/slope"), _strip->filter_slope_controllable (true)), OSC::instance());
919                 change_message (X_("/select/eq_hpf/slope"), _strip->filter_slope_controllable(true));
920         }
921
922         if (_strip->filter_slope_controllable (false)) {
923                 _strip->filter_slope_controllable (false)->Changed.connect (eq_connections, MISSING_INVALIDATOR, boost::bind (&OSCSelectObserver::change_message, this, X_("/select/eq_lpf/slope"), _strip->filter_slope_controllable (false)), OSC::instance());
924                 change_message (X_("/select/eq_lpf/slope"), _strip->filter_slope_controllable(false));
925         }
926
927         if (_strip->eq_enable_controllable ()) {
928                 _strip->eq_enable_controllable ()->Changed.connect (eq_connections, MISSING_INVALIDATOR, boost::bind (&OSCSelectObserver::enable_message, this, X_("/select/eq_enable"), _strip->eq_enable_controllable()), OSC::instance());
929                 enable_message (X_("/select/eq_enable"), _strip->eq_enable_controllable());
930         }
931
932         eq_bands = _strip->eq_band_cnt ();
933         if (eq_bands < 0) {
934                 eq_bands = 0;
935         }
936         if (!eq_bands) {
937                 return;
938         }
939
940         for (int i = 0; i < eq_bands; i++) {
941                 if (_strip->eq_band_name(i).size()) {
942                         _osc.text_message_with_id (X_("/select/eq_band_name"), i + 1, _strip->eq_band_name (i), in_line, addr);
943                 }
944                 if (_strip->eq_gain_controllable (i)) {
945                         _strip->eq_gain_controllable(i)->Changed.connect (eq_connections, MISSING_INVALIDATOR, boost::bind (&OSCSelectObserver::change_message_with_id, this, X_("/select/eq_gain"), i + 1, _strip->eq_gain_controllable(i)), OSC::instance());
946                         change_message_with_id (X_("/select/eq_gain"), i + 1, _strip->eq_gain_controllable(i));
947                 }
948                 if (_strip->eq_freq_controllable (i)) {
949                         _strip->eq_freq_controllable(i)->Changed.connect (eq_connections, MISSING_INVALIDATOR, boost::bind (&OSCSelectObserver::change_message_with_id, this, X_("/select/eq_freq"), i + 1, _strip->eq_freq_controllable(i)), OSC::instance());
950                         change_message_with_id (X_("/select/eq_freq"), i + 1, _strip->eq_freq_controllable(i));
951                 }
952                 if (_strip->eq_q_controllable (i)) {
953                         _strip->eq_q_controllable(i)->Changed.connect (eq_connections, MISSING_INVALIDATOR, boost::bind (&OSCSelectObserver::change_message_with_id, this, X_("/select/eq_q"), i + 1, _strip->eq_q_controllable(i)), OSC::instance());
954                         change_message_with_id (X_("/select/eq_q"), i + 1, _strip->eq_q_controllable(i));
955                 }
956                 if (_strip->eq_shape_controllable (i)) {
957                         _strip->eq_shape_controllable(i)->Changed.connect (eq_connections, MISSING_INVALIDATOR, boost::bind (&OSCSelectObserver::change_message_with_id, this, X_("/select/eq_shape"), i + 1, _strip->eq_shape_controllable(i)), OSC::instance());
958                         change_message_with_id (X_("/select/eq_shape"), i + 1, _strip->eq_shape_controllable(i));
959                 }
960         }
961 }
962
963 void
964 OSCSelectObserver::eq_end ()
965 {
966         eq_connections.drop_connections ();
967                 _osc.float_message (X_("/select/eq_hpf"), 0, addr);
968                 _osc.float_message (X_("/select/eq_enable"), 0, addr);
969
970         for (int i = 1; i <= eq_bands; i++) {
971                 _osc.text_message_with_id (X_("/select/eq_band_name"), i, " ", in_line, addr);
972                 _osc.float_message_with_id (X_("/select/eq_gain"), i, 0, in_line, addr);
973                 _osc.float_message_with_id (X_("/select/eq_freq"), i, 0, in_line, addr);
974                 _osc.float_message_with_id (X_("/select/eq_q"), i, 0, in_line, addr);
975                 _osc.float_message_with_id (X_("/select/eq_shape"), i, 0, in_line, addr);
976
977
978         }
979 }
980
981 void
982 OSCSelectObserver::eq_restart(int x)
983 {
984         eq_connections.drop_connections ();
985         //eq_end();
986         eq_init();
987 }