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