1d3921066cc2c906483104d9768ec97100ba285f
[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
24 #include "ardour/session.h"
25 #include "ardour/track.h"
26 #include "ardour/monitor_control.h"
27 #include "ardour/dB.h"
28 #include "ardour/meter.h"
29 #include "ardour/solo_isolate_control.h"
30
31 #include "osc.h"
32 #include "osc_route_observer.h"
33
34 #include "pbd/i18n.h"
35
36 using namespace std;
37 using namespace PBD;
38 using namespace ARDOUR;
39 using namespace ArdourSurface;
40
41 OSCRouteObserver::OSCRouteObserver (OSC& o, uint32_t ss, ArdourSurface::OSC::OSCSurface* su)
42         : _osc (o)
43         ,ssid (ss)
44         ,sur (su)
45         ,_last_gain (-1.0)
46         ,_last_trim (-1.0)
47         ,_init (true)
48         ,_expand (false)
49 {
50         addr = lo_address_new_from_url  (sur->remote_url.c_str());
51         refresh_strip (true);
52 }
53
54 OSCRouteObserver::~OSCRouteObserver ()
55 {
56         _init = true;
57         strip_connections.drop_connections ();
58
59         lo_address_free (addr);
60 }
61
62 void
63 OSCRouteObserver::no_strip ()
64 {
65         // This gets called on drop references
66         _init = true;
67
68         strip_connections.drop_connections ();
69         /*
70          * The strip will sit idle at this point doing nothing until
71          * the surface has recalculated it's strip list and then calls
72          * refresh_strip. Otherwise refresh strip will get a strip address
73          * that does not exist... Crash
74          */
75  }
76         
77 void
78 OSCRouteObserver::refresh_strip (bool force)
79 {
80         _init = true;
81         gainmode = sur->gainmode;
82         feedback = sur->feedback;
83         in_line = feedback[2];
84         uint32_t sid = sur->bank + ssid - 2;
85         if (sid >= sur->strips.size ()) {
86                 // this _should_ only occure if the number of strips is less than banksize
87                 clear_strip ();
88                 return;
89         }
90         // future
91         /*if (sur->linkset) {
92                 //to be added with linkset stuff
93                 if (_osc.linksets[sur->linkset]->not_ready)
94                         clear_strip ();
95                         switch (ssid) {
96                                 case 1:
97                                         _osc.text_message_with_id ("/strip/name", ssid, "Device", addr);
98                                         break;
99                                 case 2:
100                                         _osc.text_message_with_id ("/strip/name", ssid, string_compose ("%1", not_ready), addr);
101                                         break;
102                                 case 3:
103                                         _osc.text_message_with_id ("/strip/name", ssid, "Missing", addr);
104                                         break;
105                                 case 4:
106                                         _osc.text_message_with_id ("/strip/name", ssid, "from", addr);
107                                         break;
108                                 case 5:
109                                         _osc.text_message_with_id ("/strip/name", ssid, "Linkset", addr);
110                                         break;
111                                 default:
112                                         break;
113                         }
114                         return;
115                 }
116         }*/
117
118         // this has to be done first because expand may change with no strip change
119         bool new_expand;
120         if (sur->expand_enable && sur->expand == ssid) {
121                 new_expand = true;
122         } else {
123                 new_expand = false;
124         }
125         if (new_expand != _expand) {
126                 _expand = new_expand;
127                 if (_expand) {
128                         _osc.float_message_with_id ("/strip/expand", ssid, 1.0, in_line, addr);
129                 } else {
130                         _osc.float_message_with_id ("/strip/expand", ssid, 0.0, in_line, addr);
131                 }
132         }
133         send_select_status (ARDOUR::Properties::selected);
134
135         boost::shared_ptr<ARDOUR::Stripable> new_strip = sur->strips[sur->bank + ssid - 2];
136         if (_strip && (new_strip == _strip) && !force) {
137                 _init = false;
138                 return;
139         }
140         strip_connections.drop_connections ();
141         _strip = new_strip;
142         _strip->DropReferences.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCRouteObserver::no_strip, this), OSC::instance());
143         as = ARDOUR::Off;
144
145         if (feedback[0]) { // buttons are separate feedback
146                 _strip->PropertyChanged.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCRouteObserver::name_changed, this, boost::lambda::_1), OSC::instance());
147                 name_changed (ARDOUR::Properties::name);
148
149                 _strip->mute_control()->Changed.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCRouteObserver::send_change_message, this, X_("/strip/mute"), _strip->mute_control()), OSC::instance());
150                 send_change_message ("/strip/mute", _strip->mute_control());
151
152                 _strip->solo_control()->Changed.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCRouteObserver::send_change_message, this, X_("/strip/solo"), _strip->solo_control()), OSC::instance());
153                 send_change_message ("/strip/solo", _strip->solo_control());
154
155                 if (_strip->solo_isolate_control()) {
156                         _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());
157                         send_change_message ("/strip/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, bind (&OSCRouteObserver::send_change_message, this, X_("/strip/solo_safe"), _strip->solo_safe_control()), OSC::instance());
162                         send_change_message ("/strip/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 (&OSCRouteObserver::send_monitor_status, this, track->monitoring_control()), OSC::instance());
168                         send_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 (&OSCRouteObserver::send_change_message, this, X_("/strip/recenable"), _strip->rec_enable_control()), OSC::instance());
174                         send_change_message ("/strip/recenable", _strip->rec_enable_control());
175                 }
176                 boost::shared_ptr<AutomationControl> recsafe_controllable = _strip->rec_safe_control ();
177                 if (rec_controllable) {
178                         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());
179                         send_change_message ("/strip/record_safe", _strip->rec_safe_control());
180                 }
181                 _strip->presentation_info().PropertyChanged.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCRouteObserver::send_select_status, this, _1), OSC::instance());
182                 send_select_status (ARDOUR::Properties::selected);
183         }
184
185         if (feedback[1]) { // level controls
186                 boost::shared_ptr<GainControl> gain_cont = _strip->gain_control();
187                 gain_cont->alist()->automation_state_changed.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCRouteObserver::gain_automation, this), OSC::instance());
188                 gain_cont->Changed.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCRouteObserver::send_gain_message, this), OSC::instance());
189                 gain_automation ();
190
191                 boost::shared_ptr<Controllable> trim_controllable = boost::dynamic_pointer_cast<Controllable>(_strip->trim_control());
192                 if (trim_controllable) {
193                         trim_controllable->Changed.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCRouteObserver::send_trim_message, this), OSC::instance());
194                         send_trim_message ();
195                 }
196
197                 boost::shared_ptr<Controllable> pan_controllable = boost::dynamic_pointer_cast<Controllable>(_strip->pan_azimuth_control());
198                 if (pan_controllable) {
199                         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());
200                         send_change_message ("/strip/pan_stereo_position", _strip->pan_azimuth_control());
201                 }
202         }
203         _init = false;
204         tick();
205
206 }
207
208 void
209 OSCRouteObserver::clear_strip ()
210 {
211         _init = true;
212
213         strip_connections.drop_connections ();
214
215         // all strip buttons should be off and faders 0 and etc.
216         _osc.float_message_with_id ("/strip/expand", ssid, 0, in_line, addr);
217         if (sur->feedback[0]) { // buttons are separate feedback
218                 _osc.text_message_with_id ("/strip/name", ssid, " ", in_line, addr);
219                 _osc.float_message_with_id ("/strip/mute", ssid, 0, in_line, addr);
220                 _osc.float_message_with_id ("/strip/solo", ssid, 0, in_line, addr);
221                 _osc.float_message_with_id ("/strip/recenable", ssid, 0, in_line, addr);
222                 _osc.float_message_with_id ("/strip/record_safe", ssid, 0, in_line, addr);
223                 _osc.float_message_with_id ("/strip/monitor_input", ssid, 0, in_line, addr);
224                 _osc.float_message_with_id ("/strip/monitor_disk", ssid, 0, in_line, addr);
225                 _osc.float_message_with_id ("/strip/gui_select", ssid, 0, in_line, addr);
226                 _osc.float_message_with_id ("/strip/select", ssid, 0, in_line, addr);
227         }
228         if (sur->feedback[1]) { // level controls
229                 if (sur->gainmode) {
230                         _osc.float_message_with_id ("/strip/fader", ssid, 0, in_line, addr);
231                 } else {
232                         _osc.float_message_with_id ("/strip/gain", ssid, -193, in_line, addr);
233                 }
234                 _osc.float_message_with_id ("/strip/trimdB", ssid, 0, in_line, addr);
235                 _osc.float_message_with_id ("/strip/pan_stereo_position", ssid, 0.5, in_line, addr);
236         }
237         if (sur->feedback[9]) {
238                 _osc.float_message_with_id ("/strip/signal", ssid, 0, in_line, addr);
239         }
240         if (sur->feedback[7]) {
241                 if (sur->gainmode) {
242                         _osc.float_message_with_id ("/strip/meter", ssid, 0, in_line, addr);
243                 } else {
244                         _osc.float_message_with_id ("/strip/meter", ssid, -193, in_line, addr);
245                 }
246         }else if (sur->feedback[8]) {
247                 _osc.float_message_with_id ("/strip/meter", ssid, 0, in_line, addr);
248         }
249 }
250
251
252 void
253 OSCRouteObserver::tick ()
254 {
255         if (_init) {
256                 return;
257         }
258         if (sur->feedback[7] || sur->feedback[8] || sur->feedback[9]) { // meters enabled
259                 // the only meter here is master
260                 float now_meter;
261                 if (_strip->peak_meter()) {
262                         now_meter = _strip->peak_meter()->meter_level(0, MeterMCP);
263                 } else {
264                         now_meter = -193;
265                 }
266                 if (now_meter < -120) now_meter = -193;
267                 if (_last_meter != now_meter) {
268                         if (sur->feedback[7] || sur->feedback[8]) {
269                                 if (sur->gainmode && sur->feedback[7]) {
270                                         _osc.float_message_with_id ("/strip/meter", ssid, ((now_meter + 94) / 100), in_line, addr);
271                                 } else if ((!sur->gainmode) && sur->feedback[7]) {
272                                         _osc.float_message_with_id ("/strip/meter", ssid, now_meter, in_line, addr);
273                                 } else if (sur->feedback[8]) {
274                                         uint32_t ledlvl = (uint32_t)(((now_meter + 54) / 3.75)-1);
275                                         uint16_t ledbits = ~(0xfff<<ledlvl);
276                                         _osc.int_message_with_id ("/strip/meter", ssid, ledbits, in_line, addr);
277                                 }
278                         }
279                         if (sur->feedback[9]) {
280                                 float signal;
281                                 if (now_meter < -40) {
282                                         signal = 0;
283                                 } else {
284                                         signal = 1;
285                                 }
286                                 _osc.float_message_with_id ("/strip/signal", ssid, signal, in_line, addr);
287                         }
288                 }
289                 _last_meter = now_meter;
290
291         }
292         if (sur->feedback[1]) {
293                 if (gain_timeout) {
294                         if (gain_timeout == 1) {
295                                 _osc.text_message_with_id ("/strip/name", ssid, _strip->name(), in_line, addr);
296                         }
297                         gain_timeout--;
298                 }
299                 if (trim_timeout) {
300                         if (trim_timeout == 1) {
301                                 _osc.text_message_with_id ("/strip/name", ssid, _strip->name(), in_line, addr);
302                         }
303                         trim_timeout--;
304                 }
305                 if (as == ARDOUR::Play ||  as == ARDOUR::Touch) {
306                         if(_last_gain != _strip->gain_control()->get_value()) {
307                                 _last_gain = _strip->gain_control()->get_value();
308                                 send_gain_message ();
309                         }
310                 }
311         }
312
313 }
314
315 void
316 OSCRouteObserver::name_changed (const PBD::PropertyChange& what_changed)
317 {
318         if (!what_changed.contains (ARDOUR::Properties::name)) {
319             return;
320         }
321
322         if (_strip) {
323                 _osc.text_message_with_id ("/strip/name", ssid, _strip->name(), in_line, addr);
324         }
325 }
326
327 void
328 OSCRouteObserver::send_change_message (string path, boost::shared_ptr<Controllable> controllable)
329 {
330         float val = controllable->get_value();
331         _osc.float_message_with_id (path, ssid, (float) controllable->internal_to_interface (val), in_line, addr);
332 }
333
334 void
335 OSCRouteObserver::send_monitor_status (boost::shared_ptr<Controllable> controllable)
336 {
337         int disk, input;
338         float val = controllable->get_value();
339         switch ((int) val) {
340                 case 1:
341                         disk = 0;
342                         input = 1;
343                         break;
344                 case 2:
345                         disk = 1;
346                         input = 0;
347                         break;
348                 case 3:
349                         disk = 1;
350                         input = 1;
351                         break;
352                 default:
353                         disk = 0;
354                         input = 0;
355         }
356         _osc.int_message_with_id ("/strip/monitor_input", ssid, input, in_line, addr);
357         _osc.int_message_with_id ("/strip/monitor_disk", ssid, disk, in_line, addr);
358
359 }
360
361 void
362 OSCRouteObserver::send_trim_message ()
363 {
364         if (_last_trim != _strip->trim_control()->get_value()) {
365                 _last_trim = _strip->trim_control()->get_value();
366         } else {
367                 return;
368         }
369         if (sur->gainmode) {
370                 _osc.text_message_with_id ("/strip/name", ssid, string_compose ("%1%2%3", std::fixed, std::setprecision(2), accurate_coefficient_to_dB (_last_trim)), in_line, addr);
371                 trim_timeout = 8;
372         }
373
374         _osc.float_message_with_id ("/strip/trimdB", ssid, (float) accurate_coefficient_to_dB (_last_trim), in_line, addr);
375 }
376
377 void
378 OSCRouteObserver::send_gain_message ()
379 {
380         boost::shared_ptr<Controllable> controllable = _strip->gain_control();
381         if (_last_gain != controllable->get_value()) {
382                 _last_gain = controllable->get_value();
383         } else {
384                 return;
385         }
386
387         if (sur->gainmode) {
388                 _osc.float_message_with_id ("/strip/fader", ssid, controllable->internal_to_interface (_last_gain), in_line, addr);
389                 _osc.text_message_with_id ("/strip/name", ssid, string_compose ("%1%2%3", std::fixed, std::setprecision(2), accurate_coefficient_to_dB (controllable->get_value())), in_line, addr);
390                 gain_timeout = 8;
391         } else {
392                 if (controllable->get_value() < 1e-15) {
393                         _osc.float_message_with_id ("/strip/gain", ssid, -200, in_line, addr);
394                 } else {
395                         _osc.float_message_with_id ("/strip/gain", ssid, accurate_coefficient_to_dB (_last_gain), in_line, addr);
396                 }
397         }
398 }
399
400 void
401 OSCRouteObserver::gain_automation ()
402 {
403         string path = "/strip/gain";
404         if (sur->gainmode) {
405                 path = "/strip/fader";
406         }
407         send_gain_message ();
408         as = _strip->gain_control()->alist()->automation_state();
409         string auto_name;
410         float output = 0;
411         switch (as) {
412                 case ARDOUR::Off:
413                         output = 0;
414                         auto_name = "Manual";
415                         break;
416                 case ARDOUR::Play:
417                         output = 1;
418                         auto_name = "Play";
419                         break;
420                 case ARDOUR::Write:
421                         output = 2;
422                         auto_name = "Write";
423                         break;
424                 case ARDOUR::Touch:
425                         output = 3;
426                         auto_name = "Touch";
427                         break;
428                 case ARDOUR::Latch:
429                         output = 4;
430                         auto_name = "Latch";
431                         break;
432                 default:
433                         break;
434         }
435         _osc.float_message_with_id (string_compose ("%1/automation", path), ssid, output, in_line, addr);
436         _osc.text_message_with_id (string_compose ("%1/automation_name", path), ssid, auto_name, in_line, addr);
437 }
438
439 void
440 OSCRouteObserver::send_select_status (const PropertyChange& what)
441 {
442         if (what == PropertyChange(ARDOUR::Properties::selected)) {
443                 if (_strip) {
444                         _osc.float_message_with_id ("/strip/select", ssid, _strip->is_selected(), in_line, addr);
445                 }
446         }
447 }