2 Copyright (C) 2009 Paul Davis
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.
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.
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.
20 #include "boost/lambda/lambda.hpp"
22 #include "pbd/control_math.h"
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"
32 #include "osc_route_observer.h"
38 using namespace ARDOUR;
39 using namespace ArdourSurface;
41 OSCRouteObserver::OSCRouteObserver (boost::shared_ptr<Stripable> s, uint32_t ss, ArdourSurface::OSC::OSCSurface* su)
49 addr = lo_address_new_from_url (sur->remote_url.c_str());
50 gainmode = sur->gainmode;
51 feedback = sur->feedback;
54 if (feedback[0]) { // buttons are separate feedback
55 _strip->PropertyChanged.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCRouteObserver::name_changed, this, boost::lambda::_1), OSC::instance());
56 name_changed (ARDOUR::Properties::name);
58 _strip->mute_control()->Changed.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCRouteObserver::send_change_message, this, X_("/strip/mute"), _strip->mute_control()), OSC::instance());
59 send_change_message ("/strip/mute", _strip->mute_control());
61 _strip->solo_control()->Changed.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCRouteObserver::send_change_message, this, X_("/strip/solo"), _strip->solo_control()), OSC::instance());
62 send_change_message ("/strip/solo", _strip->solo_control());
64 if (_strip->solo_isolate_control()) {
65 _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());
66 send_change_message ("/strip/solo_iso", _strip->solo_isolate_control());
69 if (_strip->solo_safe_control()) {
70 _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());
71 send_change_message ("/strip/solo_safe", _strip->solo_safe_control());
74 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (_strip);
76 track->monitoring_control()->Changed.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCRouteObserver::send_monitor_status, this, track->monitoring_control()), OSC::instance());
77 send_monitor_status (track->monitoring_control());
80 boost::shared_ptr<AutomationControl> rec_controllable = _strip->rec_enable_control ();
81 if (rec_controllable) {
82 rec_controllable->Changed.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCRouteObserver::send_change_message, this, X_("/strip/recenable"), _strip->rec_enable_control()), OSC::instance());
83 send_change_message ("/strip/recenable", _strip->rec_enable_control());
85 boost::shared_ptr<AutomationControl> recsafe_controllable = _strip->rec_safe_control ();
86 if (rec_controllable) {
87 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());
88 send_change_message ("/strip/record_safe", _strip->rec_safe_control());
90 _strip->presentation_info().PropertyChanged.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCRouteObserver::send_select_status, this, _1), OSC::instance());
91 send_select_status (ARDOUR::Properties::selected);
94 if (feedback[1]) { // level controls
95 boost::shared_ptr<GainControl> gain_cont = _strip->gain_control();
97 gain_cont->alist()->automation_state_changed.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCRouteObserver::gain_automation, this, X_("/strip/fader")), OSC::instance());
98 gain_cont->Changed.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCRouteObserver::send_gain_message, this, X_("/strip/fader"), gain_cont), OSC::instance());
99 gain_automation ("/strip/fader");
101 gain_cont->alist()->automation_state_changed.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCRouteObserver::gain_automation, this, X_("/strip/gain")), OSC::instance());
102 gain_cont->Changed.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCRouteObserver::send_gain_message, this, X_("/strip/gain"), gain_cont), OSC::instance());
103 gain_automation ("/strip/gain");
106 boost::shared_ptr<Controllable> trim_controllable = boost::dynamic_pointer_cast<Controllable>(_strip->trim_control());
107 if (trim_controllable) {
108 trim_controllable->Changed.connect (strip_connections, MISSING_INVALIDATOR, boost::bind (&OSCRouteObserver::send_trim_message, this, X_("/strip/trimdB"), _strip->trim_control()), OSC::instance());
109 send_trim_message ("/strip/trimdB", _strip->trim_control());
112 boost::shared_ptr<Controllable> pan_controllable = boost::dynamic_pointer_cast<Controllable>(_strip->pan_azimuth_control());
113 if (pan_controllable) {
114 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());
115 send_change_message ("/strip/pan_stereo_position", _strip->pan_azimuth_control());
122 OSCRouteObserver::~OSCRouteObserver ()
126 strip_connections.drop_connections ();
128 // some surfaces destroy their own strips and don't need the extra noise
129 lo_address_free (addr);
133 // all strip buttons should be off and faders 0 and etc.
134 clear_strip ("/strip/expand", 0);
135 if (feedback[0]) { // buttons are separate feedback
136 text_with_id ("/strip/name", ssid, " ");
137 clear_strip ("/strip/mute", 0);
138 clear_strip ("/strip/solo", 0);
139 clear_strip ("/strip/recenable", 0);
140 clear_strip ("/strip/record_safe", 0);
141 clear_strip ("/strip/monitor_input", 0);
142 clear_strip ("/strip/monitor_disk", 0);
143 clear_strip ("/strip/gui_select", 0);
144 clear_strip ("/strip/select", 0);
146 if (feedback[1]) { // level controls
148 clear_strip ("/strip/fader", 0);
150 clear_strip ("/strip/gain", -193);
152 clear_strip ("/strip/trimdB", 0);
153 clear_strip ("/strip/pan_stereo_position", 0.5);
156 clear_strip ("/strip/signal", 0);
160 clear_strip ("/strip/meter", 0);
162 clear_strip ("/strip/meter", -193);
164 }else if (feedback[8]) {
165 clear_strip ("/strip/meter", 0);
168 lo_address_free (addr);
172 OSCRouteObserver::tick ()
177 if (feedback[7] || feedback[8] || feedback[9]) { // meters enabled
178 // the only meter here is master
180 if (_strip->peak_meter()) {
181 now_meter = _strip->peak_meter()->meter_level(0, MeterMCP);
185 if (now_meter < -120) now_meter = -193;
186 if (_last_meter != now_meter) {
187 if (feedback[7] || feedback[8]) {
188 string path = "/strip/meter";
189 lo_message msg = lo_message_new ();
191 path = set_path (path);
193 lo_message_add_int32 (msg, ssid);
195 if (gainmode && feedback[7]) {
196 lo_message_add_float (msg, ((now_meter + 94) / 100));
197 lo_send_message (addr, path.c_str(), msg);
198 } else if ((!gainmode) && feedback[7]) {
199 lo_message_add_float (msg, now_meter);
200 lo_send_message (addr, path.c_str(), msg);
201 } else if (feedback[8]) {
202 uint32_t ledlvl = (uint32_t)(((now_meter + 54) / 3.75)-1);
203 uint16_t ledbits = ~(0xfff<<ledlvl);
204 lo_message_add_int32 (msg, ledbits);
205 lo_send_message (addr, path.c_str(), msg);
207 lo_message_free (msg);
210 string path = "/strip/signal";
211 lo_message msg = lo_message_new ();
213 path = set_path (path);
215 lo_message_add_int32 (msg, ssid);
218 if (now_meter < -40) {
223 lo_message_add_float (msg, signal);
224 lo_send_message (addr, path.c_str(), msg);
225 lo_message_free (msg);
228 _last_meter = now_meter;
233 if (gain_timeout == 1) {
234 text_with_id ("/strip/name", ssid, _strip->name());
239 if (trim_timeout == 1) {
240 text_with_id ("/strip/name", ssid, _strip->name());
244 if (as == ARDOUR::Play || as == ARDOUR::Touch) {
245 if(_last_gain != _strip->gain_control()->get_value()) {
246 _last_gain = _strip->gain_control()->get_value();
248 send_gain_message ("/strip/fader", _strip->gain_control());
251 send_gain_message ("/strip/gain", _strip->gain_control());
260 OSCRouteObserver::name_changed (const PBD::PropertyChange& what_changed)
262 if (!what_changed.contains (ARDOUR::Properties::name)) {
269 text_with_id ("/strip/name", ssid, _strip->name());
273 OSCRouteObserver::send_change_message (string path, boost::shared_ptr<Controllable> controllable)
275 lo_message msg = lo_message_new ();
278 path = set_path (path);
280 lo_message_add_int32 (msg, ssid);
282 float val = controllable->get_value();
283 lo_message_add_float (msg, (float) controllable->internal_to_interface (val));
285 lo_send_message (addr, path.c_str(), msg);
286 lo_message_free (msg);
290 OSCRouteObserver::text_with_id (string path, uint32_t id, string name)
292 lo_message msg = lo_message_new ();
294 path = set_path (path);
296 lo_message_add_int32 (msg, id);
299 lo_message_add_string (msg, name.c_str());
301 lo_send_message (addr, path.c_str(), msg);
302 lo_message_free (msg);
306 OSCRouteObserver::send_monitor_status (boost::shared_ptr<Controllable> controllable)
309 float val = controllable->get_value();
324 lo_message msg = lo_message_new ();
325 string path = "/strip/monitor_input";
327 path = set_path (path);
329 lo_message_add_int32 (msg, ssid);
331 lo_message_add_int32 (msg, (float) input);
332 lo_send_message (addr, path.c_str(), msg);
333 lo_message_free (msg);
335 msg = lo_message_new ();
336 path = "/strip/monitor_disk";
338 path = set_path (path);
340 lo_message_add_int32 (msg, ssid);
342 lo_message_add_int32 (msg, (float) disk);
343 lo_send_message (addr, path.c_str(), msg);
344 lo_message_free (msg);
349 OSCRouteObserver::send_trim_message (string path, boost::shared_ptr<Controllable> controllable)
351 if (_last_trim != controllable->get_value()) {
352 _last_trim = controllable->get_value();
357 text_with_id ("/strip/name", ssid, string_compose ("%1%2%3", std::fixed, std::setprecision(2), accurate_coefficient_to_dB (controllable->get_value())));
361 lo_message msg = lo_message_new ();
364 path = set_path (path);
366 lo_message_add_int32 (msg, ssid);
369 lo_message_add_float (msg, (float) accurate_coefficient_to_dB (controllable->get_value()));
371 lo_send_message (addr, path.c_str(), msg);
372 lo_message_free (msg);
376 OSCRouteObserver::send_gain_message (string path, boost::shared_ptr<Controllable> controllable)
378 if (_last_gain != controllable->get_value()) {
379 _last_gain = controllable->get_value();
383 lo_message msg = lo_message_new ();
386 path = set_path (path);
388 lo_message_add_int32 (msg, ssid);
392 lo_message_add_float (msg, controllable->internal_to_interface (controllable->get_value()));
393 text_with_id ("/strip/name", ssid, string_compose ("%1%2%3", std::fixed, std::setprecision(2), accurate_coefficient_to_dB (controllable->get_value())));
396 if (controllable->get_value() < 1e-15) {
397 lo_message_add_float (msg, -200);
399 lo_message_add_float (msg, accurate_coefficient_to_dB (controllable->get_value()));
403 lo_send_message (addr, path.c_str(), msg);
404 lo_message_free (msg);
408 OSCRouteObserver::gain_automation (string path)
410 lo_message msg = lo_message_new ();
411 string apath = string_compose ("%1/automation", path);
412 string npath = string_compose ("%1/automation_name", path);
415 apath = set_path (apath);
417 lo_message_add_int32 (msg, ssid);
420 boost::shared_ptr<GainControl> control = _strip->gain_control();
421 send_gain_message (path, control);
422 as = control->alist()->automation_state();
428 auto_name = "Manual";
446 lo_message_add_float (msg, output);
447 lo_send_message (addr, apath.c_str(), msg);
448 lo_message_free (msg);
449 text_with_id (npath, ssid, auto_name);
453 OSCRouteObserver::set_path (string path)
456 path = string_compose ("%1/%2", path, ssid);
462 OSCRouteObserver::clear_strip (string path, float val)
464 lo_message msg = lo_message_new ();
466 path = set_path (path);
468 lo_message_add_int32 (msg, ssid);
470 lo_message_add_float (msg, val);
472 lo_send_message (addr, path.c_str(), msg);
473 lo_message_free (msg);
478 OSCRouteObserver::send_select_status (const PropertyChange& what)
480 if (what == PropertyChange(ARDOUR::Properties::selected)) {
482 string path = "/strip/select";
484 lo_message msg = lo_message_new ();
486 path = set_path (path);
488 lo_message_add_int32 (msg, ssid);
490 lo_message_add_float (msg, _strip->is_selected());
491 lo_send_message (addr, path.c_str(), msg);
492 lo_message_free (msg);