840142f4a6b18138a0f9a088d389154e4a4de0a9
[ardour.git] / libs / surfaces / osc / osc_route_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 "boost/lambda/lambda.hpp"
21
22 #include "pbd/control_math.h"
23 #include <glibmm.h>
24
25
26 #include "ardour/session.h"
27 #include "ardour/track.h"
28 #include "ardour/monitor_control.h"
29 #include "ardour/dB.h"
30 #include "ardour/meter.h"
31 #include "ardour/panner.h"
32 #include "ardour/panner_shell.h"
33 #include "ardour/pannable.h"
34 #include "ardour/route.h"
35 #include "ardour/route_group.h"
36 #include "ardour/send.h"
37 #include "ardour/solo_isolate_control.h"
38
39 #include "osc.h"
40 #include "osc_route_observer.h"
41
42 #include "pbd/i18n.h"
43
44 using namespace std;
45 using namespace PBD;
46 using namespace ARDOUR;
47 using namespace ArdourSurface;
48
49 OSCRouteObserver::OSCRouteObserver (OSC& o, uint32_t ss, ArdourSurface::OSC::OSCSurface* su)
50         : _osc (o)
51         ,ssid (ss)
52         ,sur (su)
53         ,_last_gain (-1.0)
54         ,_last_trim (-1.0)
55         ,_init (true)
56         ,_expand (2048)
57 {
58         addr = lo_address_new_from_url (sur->remote_url.c_str());
59         gainmode = sur->gainmode;
60         feedback = sur->feedback;
61         in_line = feedback[2];
62         uint32_t sid = sur->bank + ssid - 2;
63         uint32_t not_ready = 0;
64         if (sur->linkset) {
65                 not_ready = _osc.link_sets[sur->linkset].not_ready;
66         }
67         if (not_ready) {
68                 set_link_ready (not_ready);
69         } else if (sid >= sur->strips.size ()) {
70                 // this _should_ only occure if the number of strips is less than banksize
71                 _strip = boost::shared_ptr<ARDOUR::Stripable>();
72                 clear_strip ();
73         } else {
74                 _strip = sur->strips[sid];
75                 refresh_strip (_strip, true);
76         }
77         if (sur->expand_enable) {
78                 set_expand (sur->expand);
79         } else {
80                 set_expand (0);
81         }
82         _send = boost::shared_ptr<ARDOUR::Send> ();
83 }
84
85 OSCRouteObserver::~OSCRouteObserver ()
86 {
87         _init = true;
88         strip_connections.drop_connections ();
89
90         lo_address_free (addr);
91 }
92
93 void
94 OSCRouteObserver::no_strip ()
95 {
96         // This gets called on drop references
97         _init = true;
98
99         strip_connections.drop_connections ();
100         _gain_control = boost::shared_ptr<ARDOUR::GainControl> ();
101         _send = boost::shared_ptr<ARDOUR::Send> ();
102         _strip = boost::shared_ptr<Stripable> ();
103         /*
104          * The strip will sit idle at this point doing nothing until
105          * the surface has recalculated it's strip list and then calls
106          * refresh_strip. Otherwise refresh strip will get a strip address
107          * that does not exist... Crash
108          */
109  }
110         
111 void
112 OSCRouteObserver::refresh_strip (boost::shared_ptr<ARDOUR::Stripable> new_strip, bool force)
113 {
114         _init = true;
115         if (_tick_busy) {
116                 Glib::usleep(100); // let tick finish
117         }
118         _last_gain =-1.0;
119         _last_trim =-1.0;
120         _send = boost::shared_ptr<ARDOUR::Send> ();
121
122         send_select_status (ARDOUR::Properties::selected);
123
124         if ((new_strip == _strip) && !force) {
125                 // no change don't send feedback
126                 _init = false;
127                 return;
128         }
129         strip_connections.drop_connections ();
130         _strip = new_strip;
131         if (!_strip) {
132                 // this strip is blank and should be cleared
133                 clear_strip ();
134                 return;
135         }
136         _strip->DropReferences.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCRouteObserver::no_strip, this), OSC::instance());
137         as = ARDOUR::Off;
138
139         if (feedback[0]) { // buttons are separate feedback
140                 _strip->PropertyChanged.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCRouteObserver::name_changed, this, boost::lambda::_1), OSC::instance());
141                 name_changed (ARDOUR::Properties::name);
142
143                 boost::shared_ptr<Route> rt = boost::dynamic_pointer_cast<Route> (_strip);
144                 if (rt) {
145                         rt->route_group_changed.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCRouteObserver::group_name, this), OSC::instance());
146                         group_name ();
147                 }
148
149                 _strip->presentation_info().PropertyChanged.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCRouteObserver::pi_changed, this, _1), OSC::instance());
150                 _osc.int_message_with_id (X_("/strip/hide"), ssid, _strip->is_hidden (), in_line, addr);
151
152                 _strip->mute_control()->Changed.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCRouteObserver::send_change_message, this, X_("/strip/mute"), _strip->mute_control()), OSC::instance());
153                 send_change_message (X_("/strip/mute"), _strip->mute_control());
154
155                 _strip->solo_control()->Changed.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCRouteObserver::send_change_message, this, X_("/strip/solo"), _strip->solo_control()), OSC::instance());
156                 send_change_message (X_("/strip/solo"), _strip->solo_control());
157
158                 if (_strip->solo_isolate_control()) {
159                         _strip->solo_isolate_control()->Changed.connect (strip_connections, MISSING_INVALIDATOR, bind (&OSCRouteObserver::send_change_message, this, X_("/strip/solo_iso"), _strip->solo_isolate_control()), OSC::instance());
160                         send_change_message (X_("/strip/solo_iso"), _strip->solo_isolate_control());
161                 }
162
163                 if (_strip->solo_safe_control()) {
164                         _strip->solo_safe_control()->Changed.connect (strip_connections, MISSING_INVALIDATOR, bind (&OSCRouteObserver::send_change_message, this, X_("/strip/solo_safe"), _strip->solo_safe_control()), OSC::instance());
165                         send_change_message (X_("/strip/solo_safe"), _strip->solo_safe_control());
166                 }
167
168                 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (_strip);
169                 if (track) {
170                         track->monitoring_control()->Changed.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCRouteObserver::send_monitor_status, this, track->monitoring_control()), OSC::instance());
171                         send_monitor_status (track->monitoring_control());
172                 }
173
174                 boost::shared_ptr<AutomationControl> rec_controllable = _strip->rec_enable_control ();
175                 if (rec_controllable) {
176                         rec_controllable->Changed.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCRouteObserver::send_change_message, this, X_("/strip/recenable"), _strip->rec_enable_control()), OSC::instance());
177                         send_change_message (X_("/strip/recenable"), _strip->rec_enable_control());
178                 }
179                 boost::shared_ptr<AutomationControl> recsafe_controllable = _strip->rec_safe_control ();
180                 if (rec_controllable) {
181                         recsafe_controllable->Changed.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCRouteObserver::send_change_message, this, X_("/strip/record_safe"), _strip->rec_safe_control()), OSC::instance());
182                         send_change_message (X_("/strip/record_safe"), _strip->rec_safe_control());
183                 }
184                 _strip->presentation_info().PropertyChanged.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCRouteObserver::send_select_status, this, _1), OSC::instance());
185                 send_select_status (ARDOUR::Properties::selected);
186         }
187
188         if (feedback[1]) { // level controls
189                 _gain_control = _strip->gain_control();
190                 _gain_control->alist()->automation_state_changed.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCRouteObserver::gain_automation, this), OSC::instance());
191                 _gain_control->Changed.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCRouteObserver::send_gain_message, this), OSC::instance());
192                 gain_automation ();
193
194                 boost::shared_ptr<Controllable> trim_controllable = boost::dynamic_pointer_cast<Controllable>(_strip->trim_control());
195                 if (trim_controllable) {
196                         trim_controllable->Changed.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCRouteObserver::send_trim_message, this), OSC::instance());
197                         send_trim_message ();
198                 }
199
200                 boost::shared_ptr<Controllable> pan_controllable = boost::dynamic_pointer_cast<Controllable>(_strip->pan_azimuth_control());
201                 if (pan_controllable) {
202                         pan_controllable->Changed.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCRouteObserver::send_change_message, this, X_("/strip/pan_stereo_position"), _strip->pan_azimuth_control()), OSC::instance());
203                         send_change_message (X_("/strip/pan_stereo_position"), _strip->pan_azimuth_control());
204                 }
205         }
206         _init = false;
207         tick();
208
209 }
210
211 void
212 OSCRouteObserver::refresh_send (boost::shared_ptr<ARDOUR::Send> new_send, bool force)
213 {
214         _init = true;
215         if (_tick_busy) {
216                 Glib::usleep(100); // let tick finish
217         }
218         _last_gain =-1.0;
219         _last_trim =-1.0;
220
221         send_select_status (ARDOUR::Properties::selected);
222
223         if ((new_send == _send) && !force) {
224                 // no change don't send feedback
225                 _init = false;
226                 return;
227         }
228         strip_connections.drop_connections ();
229         if (!_strip) {
230                 // this strip is blank and should be cleared
231                 clear_strip ();
232                 return;
233         }
234         _send = new_send;
235         send_clear ();
236         _strip->DropReferences.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCRouteObserver::no_strip, this), OSC::instance());
237         as = ARDOUR::Off;
238
239         if (feedback[0]) { // buttons are separate feedback
240                 _strip->PropertyChanged.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCRouteObserver::name_changed, this, boost::lambda::_1), OSC::instance());
241                 name_changed (ARDOUR::Properties::name);
242         }
243
244         if (feedback[1]) { // level controls
245                 _gain_control = _send->gain_control();
246                 _gain_control->alist()->automation_state_changed.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCRouteObserver::gain_automation, this), OSC::instance());
247                 _gain_control->Changed.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCRouteObserver::send_gain_message, this), OSC::instance());
248                 gain_automation ();
249
250                 if (_send->pan_outs() > 1) {
251                         boost::shared_ptr<Controllable> pan_controllable = boost::dynamic_pointer_cast<Controllable>(_send->panner_shell()->panner()->pannable()->pan_azimuth_control);
252                         if (pan_controllable) {
253                                 pan_controllable->Changed.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCRouteObserver::send_change_message, this, X_("/strip/pan_stereo_position"), pan_controllable), OSC::instance());
254                                 send_change_message (X_("/strip/pan_stereo_position"), pan_controllable);
255                         }
256                 } else {
257                         _osc.float_message_with_id (X_("/strip/pan_stereo_position"), ssid, 0.5, in_line, addr);
258                 }
259         }
260         _init = false;
261         tick();
262
263 }
264
265 void
266 OSCRouteObserver::set_expand (uint32_t expand)
267 {
268         if (expand != _expand) {
269                 _expand = expand;
270                 if (expand == ssid) {
271                         _osc.float_message_with_id (X_("/strip/expand"), ssid, 1.0, in_line, addr);
272                 } else {
273                         _osc.float_message_with_id (X_("/strip/expand"), ssid, 0.0, in_line, addr);
274                 }
275         }
276 }
277
278 void
279 OSCRouteObserver::set_link_ready (uint32_t not_ready)
280 {
281         if (not_ready) {
282                 clear_strip ();
283                 switch (ssid) {
284                         case 1:
285                                 _osc.text_message_with_id (X_("/strip/name"), ssid, "Device", in_line, addr);
286                                 break;
287                         case 2:
288                                 _osc.text_message_with_id (X_("/strip/name"), ssid, string_compose ("%1", not_ready), in_line, addr);
289                                 break;
290                         case 3:
291                                 _osc.text_message_with_id (X_("/strip/name"), ssid, "Missing", in_line, addr);
292                                 break;
293                         case 4:
294                                 _osc.text_message_with_id (X_("/strip/name"), ssid, "from", in_line, addr);
295                                 break;
296                         case 5:
297                                 _osc.text_message_with_id (X_("/strip/name"), ssid, "Linkset", in_line, addr);
298                                 break;
299                         default:
300                                 break;
301                 }
302         } else {
303                 refresh_strip (_strip, true);
304         }
305 }
306
307 void
308 OSCRouteObserver::clear_strip ()
309 {
310         send_clear ();
311         if (feedback[0]) { // buttons are separate feedback
312                 _osc.text_message_with_id (X_("/strip/name"), ssid, " ", in_line, addr);
313         }
314         if (feedback[1]) { // level controls
315                 if (gainmode) {
316                         _osc.float_message_with_id (X_("/strip/fader"), ssid, 0, in_line, addr);
317                 } else {
318                         _osc.float_message_with_id (X_("/strip/gain"), ssid, -193, in_line, addr);
319                 }
320                 _osc.float_message_with_id (X_("/strip/pan_stereo_position"), ssid, 0.5, in_line, addr);
321         }
322 }
323
324 void
325 OSCRouteObserver::send_clear ()
326 {
327         _init = true;
328
329         strip_connections.drop_connections ();
330
331         // all strip buttons should be off and faders 0 and etc.
332         _osc.float_message_with_id (X_("/strip/expand"), ssid, 0, in_line, addr);
333         if (feedback[0]) { // buttons are separate feedback
334                 _osc.text_message_with_id (X_("/strip/group"), ssid, "none", in_line, addr);
335                 _osc.float_message_with_id (X_("/strip/mute"), ssid, 0, in_line, addr);
336                 _osc.float_message_with_id (X_("/strip/solo"), ssid, 0, in_line, addr);
337                 _osc.float_message_with_id (X_("/strip/recenable"), ssid, 0, in_line, addr);
338                 _osc.float_message_with_id (X_("/strip/record_safe"), ssid, 0, in_line, addr);
339                 _osc.float_message_with_id (X_("/strip/monitor_input"), ssid, 0, in_line, addr);
340                 _osc.float_message_with_id (X_("/strip/monitor_disk"), ssid, 0, in_line, addr);
341                 _osc.float_message_with_id (X_("/strip/gui_select"), ssid, 0, in_line, addr);
342                 _osc.float_message_with_id (X_("/strip/select"), ssid, 0, in_line, addr);
343         }
344         if (feedback[1]) { // level controls
345                 _osc.float_message_with_id (X_("/strip/trimdB"), ssid, 0, in_line, addr);
346         }
347         if (feedback[9]) {
348                 _osc.float_message_with_id (X_("/strip/signal"), ssid, 0, in_line, addr);
349         }
350         if (feedback[7]) {
351                 if (gainmode) {
352                         _osc.float_message_with_id (X_("/strip/meter"), ssid, 0, in_line, addr);
353                 } else {
354                         _osc.float_message_with_id (X_("/strip/meter"), ssid, -193, in_line, addr);
355                 }
356         }else if (feedback[8]) {
357                 _osc.float_message_with_id (X_("/strip/meter"), ssid, 0, in_line, addr);
358         }
359 }
360
361
362 void
363 OSCRouteObserver::tick ()
364 {
365         if (_init) {
366                 return;
367         }
368         _tick_busy = true;
369         if (feedback[7] || feedback[8] || feedback[9]) { // meters enabled
370                 // the only meter here is master
371                 /* XXXX need to add send meter for send mode or
372                  * disable for send mode
373                  */
374                 float now_meter;
375                 if (_strip->peak_meter()) {
376                         now_meter = _strip->peak_meter()->meter_level(0, MeterMCP);
377                 } else {
378                         now_meter = -193;
379                 }
380                 if (now_meter < -120) now_meter = -193;
381                 if (_last_meter != now_meter) {
382                         if (feedback[7] || feedback[8]) {
383                                 if (gainmode && feedback[7]) {
384                                         _osc.float_message_with_id (X_("/strip/meter"), ssid, ((now_meter + 94) / 100), in_line, addr);
385                                 } else if ((!gainmode) && feedback[7]) {
386                                         _osc.float_message_with_id (X_("/strip/meter"), ssid, now_meter, in_line, addr);
387                                 } else if (feedback[8]) {
388                                         uint32_t ledlvl = (uint32_t)(((now_meter + 54) / 3.75)-1);
389                                         uint16_t ledbits = ~(0xfff<<ledlvl);
390                                         _osc.int_message_with_id (X_("/strip/meter"), ssid, ledbits, in_line, addr);
391                                 }
392                         }
393                         if (feedback[9]) {
394                                 float signal;
395                                 if (now_meter < -40) {
396                                         signal = 0;
397                                 } else {
398                                         signal = 1;
399                                 }
400                                 _osc.float_message_with_id (X_("/strip/signal"), ssid, signal, in_line, addr);
401                         }
402                 }
403                 _last_meter = now_meter;
404
405         }
406         if (feedback[1]) {
407                 if (gain_timeout) {
408                         if (gain_timeout == 1) {
409                                 name_changed (ARDOUR::Properties::name);
410                         }
411                         gain_timeout--;
412                 }
413                 if (as == ARDOUR::Play ||  as == ARDOUR::Touch) {
414                         if(_last_gain != _gain_control->get_value()) {
415                                 _last_gain = _gain_control->get_value();
416                                 send_gain_message ();
417                         }
418                 }
419         }
420         _tick_busy = false;
421 }
422
423 void
424 OSCRouteObserver::name_changed (const PBD::PropertyChange& what_changed)
425 {
426         if (!what_changed.contains (ARDOUR::Properties::name)) {
427             return;
428         }
429         string name = "";
430         if (!_send) {
431                 name = _strip->name();
432         } else {
433                 name = string_compose ("%1-Send", _strip->name());
434         }
435
436         if (_strip) {
437                 _osc.text_message_with_id (X_("/strip/name"), ssid, name, in_line, addr);
438         }
439 }
440
441 void
442 OSCRouteObserver::group_name ()
443 {
444         boost::shared_ptr<Route> rt = boost::dynamic_pointer_cast<Route> (_strip);
445
446         RouteGroup *rg = rt->route_group();
447         if (rg) {
448                 _osc.text_message_with_id (X_("/strip/group"), ssid, rg->name(), in_line, addr);
449         } else {
450                 _osc.text_message_with_id (X_("/strip/group"), ssid, " ", in_line, addr);
451         }
452 }
453
454 void
455 OSCRouteObserver::pi_changed (PBD::PropertyChange const& what_changed)
456 {
457         if (!what_changed.contains (ARDOUR::Properties::hidden)) {
458                 return;
459         }
460         _osc.int_message_with_id (X_("/strip/hide"), ssid, _strip->is_hidden (), in_line, addr);
461 }
462
463 void
464 OSCRouteObserver::send_change_message (string path, boost::shared_ptr<Controllable> controllable)
465 {
466         float val = controllable->get_value();
467         _osc.float_message_with_id (path, ssid, (float) controllable->internal_to_interface (val), in_line, addr);
468 }
469
470 void
471 OSCRouteObserver::send_monitor_status (boost::shared_ptr<Controllable> controllable)
472 {
473         int disk, input;
474         float val = controllable->get_value();
475         switch ((int) val) {
476                 case 1:
477                         disk = 0;
478                         input = 1;
479                         break;
480                 case 2:
481                         disk = 1;
482                         input = 0;
483                         break;
484                 case 3:
485                         disk = 1;
486                         input = 1;
487                         break;
488                 default:
489                         disk = 0;
490                         input = 0;
491         }
492         _osc.int_message_with_id (X_("/strip/monitor_input"), ssid, input, in_line, addr);
493         _osc.int_message_with_id (X_("/strip/monitor_disk"), ssid, disk, in_line, addr);
494
495 }
496
497 void
498 OSCRouteObserver::send_trim_message ()
499 {
500         if (_last_trim != _strip->trim_control()->get_value()) {
501                 _last_trim = _strip->trim_control()->get_value();
502         } else {
503                 return;
504         }
505         _osc.float_message_with_id (X_("/strip/trimdB"), ssid, (float) accurate_coefficient_to_dB (_last_trim), in_line, addr);
506 }
507
508 void
509 OSCRouteObserver::send_gain_message ()
510 {
511         if (_last_gain != _gain_control->get_value()) {
512                 _last_gain = _gain_control->get_value();
513         } else {
514                 return;
515         }
516
517         if (gainmode) {
518                 _osc.float_message_with_id (X_("/strip/fader"), ssid, _gain_control->internal_to_interface (_last_gain), in_line, addr);
519                 if (gainmode == 1) {
520                         _osc.text_message_with_id (X_("/strip/name"), ssid, string_compose ("%1%2%3", std::fixed, std::setprecision(2), accurate_coefficient_to_dB (_last_gain)), in_line, addr);
521                         gain_timeout = 8;
522                 }
523         }
524         if (!gainmode || gainmode == 2) {
525                 if (_last_gain < 1e-15) {
526                         _osc.float_message_with_id (X_("/strip/gain"), ssid, -200, in_line, addr);
527                 } else {
528                         _osc.float_message_with_id (X_("/strip/gain"), ssid, accurate_coefficient_to_dB (_last_gain), in_line, addr);
529                 }
530         }
531 }
532
533 void
534 OSCRouteObserver::gain_automation ()
535 {
536         string path = X_("/strip/gain");
537         if (gainmode) {
538                 path = X_("/strip/fader");
539         }
540         send_gain_message ();
541         as = _gain_control->alist()->automation_state();
542         string auto_name;
543         float output = 0;
544         switch (as) {
545                 case ARDOUR::Off:
546                         output = 0;
547                         auto_name = "Manual";
548                         break;
549                 case ARDOUR::Play:
550                         output = 1;
551                         auto_name = "Play";
552                         break;
553                 case ARDOUR::Write:
554                         output = 2;
555                         auto_name = "Write";
556                         break;
557                 case ARDOUR::Touch:
558                         output = 3;
559                         auto_name = "Touch";
560                         break;
561                 case ARDOUR::Latch:
562                         output = 4;
563                         auto_name = "Latch";
564                         break;
565                 default:
566                         break;
567         }
568         _osc.float_message_with_id (string_compose (X_("%1/automation"), path), ssid, output, in_line, addr);
569         _osc.text_message_with_id (string_compose (X_("%1/automation_name"), path), ssid, auto_name, in_line, addr);
570 }
571
572 void
573 OSCRouteObserver::send_select_status (const PropertyChange& what)
574 {
575         if (what == PropertyChange(ARDOUR::Properties::selected)) {
576                 if (_strip) {
577                         _osc.float_message_with_id (X_("/strip/select"), ssid, _strip->is_selected(), in_line, addr);
578                 }
579         }
580 }