OSC: Added feedback for /select
[ardour.git] / libs / surfaces / osc / osc.cc
1 /*
2  * Copyright (C) 2006 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17  *
18  */
19
20 #include <cstdio>
21 #include <cstdlib>
22 #include <cerrno>
23 #include <algorithm>
24
25 #include <unistd.h>
26 #include <fcntl.h>
27
28 #include "pbd/gstdio_compat.h"
29 #include <glibmm/miscutils.h>
30
31 #include <pbd/convert.h>
32 #include <pbd/pthread_utils.h>
33 #include <pbd/file_utils.h>
34 #include <pbd/failed_constructor.h>
35
36 #include "ardour/amp.h"
37 #include "ardour/session.h"
38 #include "ardour/route.h"
39 #include "ardour/audio_track.h"
40 #include "ardour/midi_track.h"
41 #include "ardour/monitor_control.h"
42 #include "ardour/dB.h"
43 #include "ardour/filesystem_paths.h"
44 #include "ardour/panner.h"
45 #include "ardour/plugin.h"
46 #include "ardour/plugin_insert.h"
47 #include "ardour/presentation_info.h"
48 #include "ardour/send.h"
49
50 #include "osc_select_observer.h"
51 #include "osc.h"
52 #include "osc_controllable.h"
53 #include "osc_route_observer.h"
54 #include "osc_global_observer.h"
55 #include "i18n.h"
56
57 using namespace ARDOUR;
58 using namespace std;
59 using namespace Glib;
60 using namespace ArdourSurface;
61
62 #include "pbd/abstract_ui.cc" // instantiate template
63
64 OSC* OSC::_instance = 0;
65
66 #ifdef DEBUG
67 static void error_callback(int num, const char *m, const char *path)
68 {
69         fprintf(stderr, "liblo server error %d in path %s: %s\n", num, path, m);
70 }
71 #else
72 static void error_callback(int, const char *, const char *)
73 {
74
75 }
76 #endif
77
78 OSC::OSC (Session& s, uint32_t port)
79         : ControlProtocol (s, X_("Open Sound Control (OSC)"))
80         , AbstractUI<OSCUIRequest> (name())
81         , local_server (0)
82         , remote_server (0)
83         , _port(port)
84         , _ok (true)
85         , _shutdown (false)
86         , _osc_server (0)
87         , _osc_unix_server (0)
88         , _send_route_changes (true)
89         , _debugmode (Off)
90         , gui (0)
91 {
92         _instance = this;
93
94         session->Exported.connect (*this, MISSING_INVALIDATOR, boost::bind (&OSC::session_exported, this, _1, _2), this);
95 }
96
97 OSC::~OSC()
98 {
99         stop ();
100         _instance = 0;
101 }
102
103 void*
104 OSC::request_factory (uint32_t num_requests)
105 {
106         /* AbstractUI<T>::request_buffer_factory() is a template method only
107            instantiated in this source module. To provide something visible for
108            use in the interface/descriptor, we have this static method that is
109            template-free.
110         */
111         return request_buffer_factory (num_requests);
112 }
113
114 void
115 OSC::do_request (OSCUIRequest* req)
116 {
117         if (req->type == CallSlot) {
118
119                 call_slot (MISSING_INVALIDATOR, req->the_slot);
120
121         } else if (req->type == Quit) {
122
123                 stop ();
124         }
125 }
126
127 int
128 OSC::set_active (bool yn)
129 {
130         if (yn != active()) {
131
132                 if (yn) {
133                         if (start ()) {
134                                 return -1;
135                         }
136                 } else {
137                         if (stop ()) {
138                                 return -1;
139                         }
140                 }
141
142         }
143
144         return ControlProtocol::set_active (yn);
145 }
146
147 bool
148 OSC::get_active () const
149 {
150         return _osc_server != 0;
151 }
152
153 int
154 OSC::set_feedback (bool yn)
155 {
156         _send_route_changes = yn;
157         return 0;
158 }
159
160 bool
161 OSC::get_feedback () const
162 {
163         return _send_route_changes;
164 }
165
166 int
167 OSC::start ()
168 {
169         char tmpstr[255];
170
171         if (_osc_server) {
172                 /* already started */
173                 return 0;
174         }
175
176         for (int j=0; j < 20; ++j) {
177                 snprintf(tmpstr, sizeof(tmpstr), "%d", _port);
178
179                 //if ((_osc_server = lo_server_new_with_proto (tmpstr, LO_TCP, error_callback))) {
180                 //      break;
181                 //}
182
183                 if ((_osc_server = lo_server_new (tmpstr, error_callback))) {
184                         break;
185                 }
186
187 #ifdef DEBUG
188                 cerr << "can't get osc at port: " << _port << endl;
189 #endif
190                 _port++;
191                 continue;
192         }
193
194         if (!_osc_server) {
195                 return 1;
196         }
197
198 #ifdef ARDOUR_OSC_UNIX_SERVER
199
200         // APPEARS sluggish for now
201
202         // attempt to create unix socket server too
203
204         snprintf(tmpstr, sizeof(tmpstr), "/tmp/sooperlooper_XXXXXX");
205         int fd = mkstemp(tmpstr);
206
207         if (fd >= 0 ) {
208                 ::g_unlink (tmpstr);
209                 close (fd);
210
211                 _osc_unix_server = lo_server_new (tmpstr, error_callback);
212
213                 if (_osc_unix_server) {
214                         _osc_unix_socket_path = tmpstr;
215                 }
216         }
217 #endif
218
219         PBD::info << "OSC @ " << get_server_url () << endmsg;
220
221         std::string url_file;
222
223         if (find_file (ardour_config_search_path(), "osc_url", url_file)) {
224                 _osc_url_file = url_file;
225                 if (g_file_set_contents (_osc_url_file.c_str(), get_server_url().c_str(), -1, NULL)) {
226                         cerr << "Couldn't write '" <<  _osc_url_file << "'" <<endl;
227                 }
228         }
229
230         register_callbacks();
231
232         session_loaded (*session);
233
234         // lo_server_thread_add_method(_sthread, NULL, NULL, OSC::_dummy_handler, this);
235
236         /* startup the event loop thread */
237
238         BaseUI::run ();
239
240         // start timers for metering, timecode and heartbeat.
241         // timecode and metering run at 100
242         Glib::RefPtr<Glib::TimeoutSource> periodic_timeout = Glib::TimeoutSource::create (100); // milliseconds
243         periodic_connection = periodic_timeout->connect (sigc::mem_fun (*this, &OSC::periodic));
244         periodic_timeout->attach (main_loop()->get_context());
245
246         return 0;
247 }
248
249 void
250 OSC::thread_init ()
251 {
252         pthread_set_name (event_loop_name().c_str());
253
254         if (_osc_unix_server) {
255                 Glib::RefPtr<IOSource> src = IOSource::create (lo_server_get_socket_fd (_osc_unix_server), IO_IN|IO_HUP|IO_ERR);
256                 src->connect (sigc::bind (sigc::mem_fun (*this, &OSC::osc_input_handler), _osc_unix_server));
257                 src->attach (_main_loop->get_context());
258                 local_server = src->gobj();
259                 g_source_ref (local_server);
260         }
261
262         if (_osc_server) {
263 #ifdef PLATFORM_WINDOWS
264                 Glib::RefPtr<IOChannel> chan = Glib::IOChannel::create_from_win32_socket (lo_server_get_socket_fd (_osc_server));
265                 Glib::RefPtr<IOSource> src  = IOSource::create (chan, IO_IN|IO_HUP|IO_ERR);
266 #else
267                 Glib::RefPtr<IOSource> src  = IOSource::create (lo_server_get_socket_fd (_osc_server), IO_IN|IO_HUP|IO_ERR);
268 #endif
269                 src->connect (sigc::bind (sigc::mem_fun (*this, &OSC::osc_input_handler), _osc_server));
270                 src->attach (_main_loop->get_context());
271                 remote_server = src->gobj();
272                 g_source_ref (remote_server);
273         }
274
275         PBD::notify_event_loops_about_thread_creation (pthread_self(), event_loop_name(), 2048);
276         SessionEvent::create_per_thread_pool (event_loop_name(), 128);
277 }
278
279 int
280 OSC::stop ()
281 {
282         /* stop main loop */
283
284         if (local_server) {
285                 g_source_destroy (local_server);
286                 g_source_unref (local_server);
287                 local_server = 0;
288         }
289
290         if (remote_server) {
291                 g_source_destroy (remote_server);
292                 g_source_unref (remote_server);
293                 remote_server = 0;
294         }
295
296         BaseUI::quit ();
297
298         if (_osc_server) {
299                 lo_server_free (_osc_server);
300                 _osc_server = 0;
301         }
302
303         if (_osc_unix_server) {
304                 lo_server_free (_osc_unix_server);
305                 _osc_unix_server = 0;
306         }
307
308         if (!_osc_unix_socket_path.empty()) {
309                 ::g_unlink (_osc_unix_socket_path.c_str());
310         }
311
312         if (!_osc_url_file.empty() ) {
313                 ::g_unlink (_osc_url_file.c_str() );
314         }
315
316         periodic_connection.disconnect ();
317         // Delete any active route observers
318         for (RouteObservers::iterator x = route_observers.begin(); x != route_observers.end();) {
319
320                 OSCRouteObserver* rc;
321
322                 if ((rc = dynamic_cast<OSCRouteObserver*>(*x)) != 0) {
323                         delete *x;
324                         x = route_observers.erase (x);
325                 } else {
326                         ++x;
327                 }
328         }
329 // Should maybe do global_observers too
330         for (GlobalObservers::iterator x = global_observers.begin(); x != global_observers.end();) {
331
332                 OSCGlobalObserver* gc;
333
334                 if ((gc = dynamic_cast<OSCGlobalObserver*>(*x)) != 0) {
335                         delete *x;
336                         x = global_observers.erase (x);
337                 } else {
338                         ++x;
339                 }
340         }
341 // delete select observers
342         for (uint32_t it = 0; it < _surface.size(); ++it) {
343                 OSCSurface* sur = &_surface[it];
344                 OSCSelectObserver* so;
345                 if ((so = dynamic_cast<OSCSelectObserver*>(sur->sel_obs)) != 0) {
346                         delete so;
347                 }
348         }
349
350         return 0;
351 }
352
353 void
354 OSC::register_callbacks()
355 {
356         lo_server srvs[2];
357         lo_server serv;
358
359         srvs[0] = _osc_server;
360         srvs[1] = _osc_unix_server;
361
362         for (size_t i = 0; i < 2; ++i) {
363
364                 if (!srvs[i]) {
365                         continue;
366                 }
367
368                 serv = srvs[i];
369
370
371 #define REGISTER_CALLBACK(serv,path,types, function) lo_server_add_method (serv, path, types, OSC::_ ## function, this)
372
373                 // Some controls have optional "f" for feedback or touchosc
374                 // http://hexler.net/docs/touchosc-controls-reference
375
376                 REGISTER_CALLBACK (serv, "/set_surface", "iiii", set_surface);
377                 REGISTER_CALLBACK (serv, "/set_surface/feedback", "i", set_surface_feedback);
378                 REGISTER_CALLBACK (serv, "/set_surface/bank_size", "i", set_surface_bank_size);
379                 REGISTER_CALLBACK (serv, "/set_surface/gainmode", "i", set_surface_gainmode);
380                 REGISTER_CALLBACK (serv, "/set_surface/strip_types", "i", set_surface_strip_types);
381                 REGISTER_CALLBACK (serv, "/strip/list", "", routes_list);
382                 REGISTER_CALLBACK (serv, "/add_marker", "", add_marker);
383                 REGISTER_CALLBACK (serv, "/add_marker", "f", add_marker);
384                 REGISTER_CALLBACK (serv, "/access_action", "s", access_action);
385                 REGISTER_CALLBACK (serv, "/loop_toggle", "", loop_toggle);
386                 REGISTER_CALLBACK (serv, "/loop_toggle", "f", loop_toggle);
387                 REGISTER_CALLBACK (serv, "/loop_location", "ii", loop_location);
388                 REGISTER_CALLBACK (serv, "/goto_start", "", goto_start);
389                 REGISTER_CALLBACK (serv, "/goto_start", "f", goto_start);
390                 REGISTER_CALLBACK (serv, "/goto_end", "", goto_end);
391                 REGISTER_CALLBACK (serv, "/goto_end", "f", goto_end);
392                 REGISTER_CALLBACK (serv, "/rewind", "", rewind);
393                 REGISTER_CALLBACK (serv, "/rewind", "f", rewind);
394                 REGISTER_CALLBACK (serv, "/ffwd", "", ffwd);
395                 REGISTER_CALLBACK (serv, "/ffwd", "f", ffwd);
396                 REGISTER_CALLBACK (serv, "/transport_stop", "", transport_stop);
397                 REGISTER_CALLBACK (serv, "/transport_stop", "f", transport_stop);
398                 REGISTER_CALLBACK (serv, "/transport_play", "", transport_play);
399                 REGISTER_CALLBACK (serv, "/transport_play", "f", transport_play);
400                 REGISTER_CALLBACK (serv, "/transport_frame", "", transport_frame);
401                 REGISTER_CALLBACK (serv, "/transport_speed", "", transport_speed);
402                 REGISTER_CALLBACK (serv, "/record_enabled", "", record_enabled);
403                 REGISTER_CALLBACK (serv, "/set_transport_speed", "f", set_transport_speed);
404                 // locate ii is position and bool roll
405                 REGISTER_CALLBACK (serv, "/locate", "ii", locate);
406                 REGISTER_CALLBACK (serv, "/save_state", "", save_state);
407                 REGISTER_CALLBACK (serv, "/save_state", "f", save_state);
408                 REGISTER_CALLBACK (serv, "/prev_marker", "", prev_marker);
409                 REGISTER_CALLBACK (serv, "/prev_marker", "f", prev_marker);
410                 REGISTER_CALLBACK (serv, "/next_marker", "", next_marker);
411                 REGISTER_CALLBACK (serv, "/next_marker", "f", next_marker);
412                 REGISTER_CALLBACK (serv, "/undo", "", undo);
413                 REGISTER_CALLBACK (serv, "/undo", "f", undo);
414                 REGISTER_CALLBACK (serv, "/redo", "", redo);
415                 REGISTER_CALLBACK (serv, "/redo", "f", redo);
416                 REGISTER_CALLBACK (serv, "/toggle_punch_in", "", toggle_punch_in);
417                 REGISTER_CALLBACK (serv, "/toggle_punch_in", "f", toggle_punch_in);
418                 REGISTER_CALLBACK (serv, "/toggle_punch_out", "", toggle_punch_out);
419                 REGISTER_CALLBACK (serv, "/toggle_punch_out", "f", toggle_punch_out);
420                 REGISTER_CALLBACK (serv, "/rec_enable_toggle", "", rec_enable_toggle);
421                 REGISTER_CALLBACK (serv, "/rec_enable_toggle", "f", rec_enable_toggle);
422                 REGISTER_CALLBACK (serv, "/toggle_all_rec_enables", "", toggle_all_rec_enables);
423                 REGISTER_CALLBACK (serv, "/toggle_all_rec_enables", "f", toggle_all_rec_enables);
424                 REGISTER_CALLBACK (serv, "/all_tracks_rec_in", "f", all_tracks_rec_in);
425                 REGISTER_CALLBACK (serv, "/all_tracks_rec_out", "f", all_tracks_rec_out);
426                 REGISTER_CALLBACK (serv, "/remove_marker", "", remove_marker_at_playhead);
427                 REGISTER_CALLBACK (serv, "/remove_marker", "f", remove_marker_at_playhead);
428                 REGISTER_CALLBACK (serv, "/jump_bars", "f", jump_by_bars);
429                 REGISTER_CALLBACK (serv, "/jump_seconds", "f", jump_by_seconds);
430                 REGISTER_CALLBACK (serv, "/mark_in", "", mark_in);
431                 REGISTER_CALLBACK (serv, "/mark_in", "f", mark_in);
432                 REGISTER_CALLBACK (serv, "/mark_out", "", mark_out);
433                 REGISTER_CALLBACK (serv, "/mark_out", "f", mark_out);
434                 REGISTER_CALLBACK (serv, "/toggle_click", "", toggle_click);
435                 REGISTER_CALLBACK (serv, "/toggle_click", "f", toggle_click);
436                 REGISTER_CALLBACK (serv, "/midi_panic", "", midi_panic);
437                 REGISTER_CALLBACK (serv, "/midi_panic", "f", midi_panic);
438                 REGISTER_CALLBACK (serv, "/toggle_roll", "", toggle_roll);
439                 REGISTER_CALLBACK (serv, "/toggle_roll", "f", toggle_roll);
440                 REGISTER_CALLBACK (serv, "/stop_forget", "", stop_forget);
441                 REGISTER_CALLBACK (serv, "/stop_forget", "f", stop_forget);
442                 REGISTER_CALLBACK (serv, "/set_punch_range", "", set_punch_range);
443                 REGISTER_CALLBACK (serv, "/set_punch_range", "f", set_punch_range);
444                 REGISTER_CALLBACK (serv, "/set_loop_range", "", set_loop_range);
445                 REGISTER_CALLBACK (serv, "/set_loop_range", "f", set_loop_range);
446                 REGISTER_CALLBACK (serv, "/set_session_range", "", set_session_range);
447                 REGISTER_CALLBACK (serv, "/set_session_range", "f", set_session_range);
448                 // /toggle_monitor_* not working (comented out)
449                 REGISTER_CALLBACK (serv, "/toggle_monitor_mute", "", toggle_monitor_mute);
450                 REGISTER_CALLBACK (serv, "/toggle_monitor_mute", "f", toggle_monitor_mute);
451                 REGISTER_CALLBACK (serv, "/toggle_monitor_dim", "", toggle_monitor_dim);
452                 REGISTER_CALLBACK (serv, "/toggle_monitor_dim", "f", toggle_monitor_dim);
453                 REGISTER_CALLBACK (serv, "/toggle_monitor_mono", "", toggle_monitor_mono);
454                 REGISTER_CALLBACK (serv, "/toggle_monitor_mono", "f", toggle_monitor_mono);
455                 REGISTER_CALLBACK (serv, "/quick_snapshot_switch", "", quick_snapshot_switch);
456                 REGISTER_CALLBACK (serv, "/quick_snapshot_switch", "f", quick_snapshot_switch);
457                 REGISTER_CALLBACK (serv, "/quick_snapshot_stay", "", quick_snapshot_stay);
458                 REGISTER_CALLBACK (serv, "/quick_snapshot_stay", "f", quick_snapshot_stay);
459                 REGISTER_CALLBACK (serv, "/fit_1_track", "", fit_1_track);
460                 REGISTER_CALLBACK (serv, "/fit_1_track", "f", fit_1_track);
461                 REGISTER_CALLBACK (serv, "/fit_2_tracks", "", fit_2_tracks);
462                 REGISTER_CALLBACK (serv, "/fit_2_tracks", "f", fit_2_tracks);
463                 REGISTER_CALLBACK (serv, "/fit_4_tracks", "", fit_4_tracks);
464                 REGISTER_CALLBACK (serv, "/fit_4_tracks", "f", fit_4_tracks);
465                 REGISTER_CALLBACK (serv, "/fit_8_tracks", "", fit_8_tracks);
466                 REGISTER_CALLBACK (serv, "/fit_8_tracks", "f", fit_8_tracks);
467                 REGISTER_CALLBACK (serv, "/fit_16_tracks", "", fit_16_tracks);
468                 REGISTER_CALLBACK (serv, "/fit_16_tracks", "f", fit_16_tracks);
469                 REGISTER_CALLBACK (serv, "/fit_32_tracks", "", fit_32_tracks);
470                 REGISTER_CALLBACK (serv, "/fit_32_tracks", "f", fit_32_tracks);
471                 REGISTER_CALLBACK (serv, "/fit_all_tracks", "", fit_all_tracks);
472                 REGISTER_CALLBACK (serv, "/fit_all_tracks", "f", fit_all_tracks);
473                 REGISTER_CALLBACK (serv, "/zoom_100_ms", "", zoom_100_ms);
474                 REGISTER_CALLBACK (serv, "/zoom_100_ms", "f", zoom_100_ms);
475                 REGISTER_CALLBACK (serv, "/zoom_1_sec", "", zoom_1_sec);
476                 REGISTER_CALLBACK (serv, "/zoom_1_sec", "f", zoom_1_sec);
477                 REGISTER_CALLBACK (serv, "/zoom_10_sec", "", zoom_10_sec);
478                 REGISTER_CALLBACK (serv, "/zoom_10_sec", "f", zoom_10_sec);
479                 REGISTER_CALLBACK (serv, "/zoom_1_min", "", zoom_1_min);
480                 REGISTER_CALLBACK (serv, "/zoom_1_min", "f", zoom_1_min);
481                 REGISTER_CALLBACK (serv, "/zoom_5_min", "", zoom_5_min);
482                 REGISTER_CALLBACK (serv, "/zoom_5_min", "f", zoom_5_min);
483                 REGISTER_CALLBACK (serv, "/zoom_10_min", "", zoom_10_min);
484                 REGISTER_CALLBACK (serv, "/zoom_10_min", "f", zoom_10_min);
485                 REGISTER_CALLBACK (serv, "/zoom_to_session", "", zoom_to_session);
486                 REGISTER_CALLBACK (serv, "/zoom_to_session", "f", zoom_to_session);
487                 REGISTER_CALLBACK (serv, "/temporal_zoom_in", "f", temporal_zoom_in);
488                 REGISTER_CALLBACK (serv, "/temporal_zoom_in", "", temporal_zoom_in);
489                 REGISTER_CALLBACK (serv, "/temporal_zoom_out", "", temporal_zoom_out);
490                 REGISTER_CALLBACK (serv, "/temporal_zoom_out", "f", temporal_zoom_out);
491                 REGISTER_CALLBACK (serv, "/scroll_up_1_track", "f", scroll_up_1_track);
492                 REGISTER_CALLBACK (serv, "/scroll_up_1_track", "", scroll_up_1_track);
493                 REGISTER_CALLBACK (serv, "/scroll_dn_1_track", "f", scroll_dn_1_track);
494                 REGISTER_CALLBACK (serv, "/scroll_dn_1_track", "", scroll_dn_1_track);
495                 REGISTER_CALLBACK (serv, "/scroll_up_1_page", "f", scroll_up_1_page);
496                 REGISTER_CALLBACK (serv, "/scroll_up_1_page", "", scroll_up_1_page);
497                 REGISTER_CALLBACK (serv, "/scroll_dn_1_page", "f", scroll_dn_1_page);
498                 REGISTER_CALLBACK (serv, "/scroll_dn_1_page", "", scroll_dn_1_page);
499                 REGISTER_CALLBACK (serv, "/bank_up", "", bank_up);
500                 REGISTER_CALLBACK (serv, "/bank_up", "f", bank_up);
501                 REGISTER_CALLBACK (serv, "/bank_down", "", bank_down);
502                 REGISTER_CALLBACK (serv, "/bank_down", "f", bank_down);
503                 REGISTER_CALLBACK (serv, "/master/gain", "f", master_set_gain);
504                 REGISTER_CALLBACK (serv, "/master/fader", "i", master_set_fader);
505                 REGISTER_CALLBACK (serv, "/master/mute", "i", master_set_mute);
506                 REGISTER_CALLBACK (serv, "/master/trimdB", "f", master_set_trim);
507                 REGISTER_CALLBACK (serv, "/master/pan_stereo_position", "f", master_set_pan_stereo_position);
508                 REGISTER_CALLBACK (serv, "/monitor/gain", "f", monitor_set_gain);
509                 REGISTER_CALLBACK (serv, "/monitor/fader", "i", monitor_set_fader);
510                 REGISTER_CALLBACK (serv, "/select/recenable", "i", sel_recenable);
511                 REGISTER_CALLBACK (serv, "/select/record_safe", "i", sel_recsafe);
512
513
514                 /* These commands require the route index in addition to the arg; TouchOSC (et al) can't use these  */ 
515                 REGISTER_CALLBACK (serv, "/strip/mute", "ii", route_mute);
516                 REGISTER_CALLBACK (serv, "/strip/solo", "ii", route_solo);
517                 REGISTER_CALLBACK (serv, "/strip/recenable", "ii", route_recenable);
518                 REGISTER_CALLBACK (serv, "/strip/record_safe", "ii", route_recsafe);
519                 REGISTER_CALLBACK (serv, "/strip/monitor_input", "ii", route_monitor_input);
520                 REGISTER_CALLBACK (serv, "/strip/monitor_disk", "ii", route_monitor_disk);
521                 REGISTER_CALLBACK (serv, "/strip/select", "ii", strip_select);
522                 REGISTER_CALLBACK (serv, "/strip/gui_select", "ii", strip_gui_select);
523                 REGISTER_CALLBACK (serv, "/strip/gain", "if", route_set_gain_dB);
524                 REGISTER_CALLBACK (serv, "/strip/fader", "if", route_set_gain_fader);
525                 REGISTER_CALLBACK (serv, "/strip/trimabs", "if", route_set_trim_abs);
526                 REGISTER_CALLBACK (serv, "/strip/trimdB", "if", route_set_trim_dB);
527                 REGISTER_CALLBACK (serv, "/strip/pan_stereo_position", "if", route_set_pan_stereo_position);
528                 REGISTER_CALLBACK (serv, "/strip/pan_stereo_width", "if", route_set_pan_stereo_width);
529                 REGISTER_CALLBACK (serv, "/strip/plugin/parameter", "iiif", route_plugin_parameter);
530                 // prints to cerr only
531                 REGISTER_CALLBACK (serv, "/strip/plugin/parameter/print", "iii", route_plugin_parameter_print);
532                 REGISTER_CALLBACK (serv, "/strip/send/gainabs", "iif", route_set_send_gain_abs);
533                 REGISTER_CALLBACK (serv, "/strip/send/gaindB", "iif", route_set_send_gain_dB);
534
535                 /* still not-really-standardized query interface */
536                 //REGISTER_CALLBACK (serv, "/ardour/*/#current_value", "", current_value);
537                 //REGISTER_CALLBACK (serv, "/ardour/set", "", set);
538
539                 // un/register_update args= s:ctrl s:returl s:retpath
540                 //lo_server_add_method(serv, "/register_update", "sss", OSC::global_register_update_handler, this);
541                 //lo_server_add_method(serv, "/unregister_update", "sss", OSC::global_unregister_update_handler, this);
542                 //lo_server_add_method(serv, "/register_auto_update", "siss", OSC::global_register_auto_update_handler, this);
543                 //lo_server_add_method(serv, "/unregister_auto_update", "sss", OSC::_global_unregister_auto_update_handler, this);
544
545                 /* this is a special catchall handler,
546                  * register at the end so this is only called if no
547                  * other handler matches (used for debug) */
548                 lo_server_add_method (serv, 0, 0, _catchall, this);
549         }
550 }
551
552 bool
553 OSC::osc_input_handler (IOCondition ioc, lo_server srv)
554 {
555         if (ioc & ~IO_IN) {
556                 return false;
557         }
558
559         if (ioc & IO_IN) {
560                 lo_server_recv (srv);
561         }
562
563         return true;
564 }
565
566 std::string
567 OSC::get_server_url()
568 {
569         string url;
570         char * urlstr;
571
572         if (_osc_server) {
573                 urlstr = lo_server_get_url (_osc_server);
574                 url = urlstr;
575                 free (urlstr);
576         }
577
578         return url;
579 }
580
581 std::string
582 OSC::get_unix_server_url()
583 {
584         string url;
585         char * urlstr;
586
587         if (_osc_unix_server) {
588                 urlstr = lo_server_get_url (_osc_unix_server);
589                 url = urlstr;
590                 free (urlstr);
591         }
592
593         return url;
594 }
595
596 void
597 OSC::listen_to_route (boost::shared_ptr<Stripable> strip, lo_address addr)
598 {
599         /* avoid duplicate listens */
600
601         for (RouteObservers::iterator x = route_observers.begin(); x != route_observers.end(); ++x) {
602
603                 OSCRouteObserver* ro;
604
605                 if ((ro = dynamic_cast<OSCRouteObserver*>(*x)) != 0) {
606
607                         int res = strcmp(lo_address_get_url(ro->address()), lo_address_get_url(addr));
608
609                         if (ro->strip() == strip && res == 0) {
610                                 return;
611                         }
612                 }
613         }
614
615         OSCSurface *s = get_surface(addr);
616         uint32_t sid = get_sid (strip->presentation_info().order(), addr);
617         // above is zero based add 1
618         OSCRouteObserver* o = new OSCRouteObserver (strip, addr, sid + 1, s->gainmode, s->feedback);
619         route_observers.push_back (o);
620
621         strip->DropReferences.connect (*this, MISSING_INVALIDATOR, boost::bind (&OSC::drop_route, this, boost::weak_ptr<Stripable> (strip)), this);
622 }
623
624 void
625 OSC::drop_route (boost::weak_ptr<Stripable> wr)
626 {
627         boost::shared_ptr<Stripable> r = wr.lock ();
628
629         if (!r) {
630                 return;
631         }
632
633         for (RouteObservers::iterator x = route_observers.begin(); x != route_observers.end();) {
634
635                 OSCRouteObserver* rc;
636
637                 if ((rc = dynamic_cast<OSCRouteObserver*>(*x)) != 0) {
638
639                         if (rc->strip() == r) {
640                                 delete *x;
641                                 x = route_observers.erase (x);
642                         } else {
643                                 ++x;
644                         }
645                 } else {
646                         ++x;
647                 }
648         }
649 }
650
651 void
652 OSC::end_listen (boost::shared_ptr<Stripable> r, lo_address addr)
653 {
654         RouteObservers::iterator x;
655
656         // Remove the route observers
657         for (x = route_observers.begin(); x != route_observers.end();) {
658
659                 OSCRouteObserver* ro;
660
661                 if ((ro = dynamic_cast<OSCRouteObserver*>(*x)) != 0) {
662
663                         int res = strcmp(lo_address_get_url(ro->address()), lo_address_get_url(addr));
664
665                         if (ro->strip() == r && res == 0) {
666                                 delete *x;
667                                 x = route_observers.erase (x);
668                         }
669                         else {
670                                 ++x;
671                         }
672                 }
673                 else {
674                         ++x;
675                 }
676         }
677 }
678
679 void
680 OSC::current_value_query (const char* path, size_t len, lo_arg **argv, int argc, lo_message msg)
681 {
682         char* subpath;
683
684         subpath = (char*) malloc (len-15+1);
685         memcpy (subpath, path, len-15);
686         subpath[len-15] = '\0';
687
688         send_current_value (subpath, argv, argc, msg);
689
690         free (subpath);
691 }
692
693 void
694 OSC::send_current_value (const char* path, lo_arg** argv, int argc, lo_message msg)
695 {
696         if (!session) {
697                 return;
698         }
699
700         lo_message reply = lo_message_new ();
701         boost::shared_ptr<Route> r;
702         int id;
703
704         lo_message_add_string (reply, path);
705
706         if (argc == 0) {
707                 lo_message_add_string (reply, "bad syntax");
708         } else {
709                 id = argv[0]->i;
710                 r = session->get_remote_nth_route (id);
711
712                 if (!r) {
713                         lo_message_add_string (reply, "not found");
714                 } else {
715
716                         if (strcmp (path, "/strip/state") == 0) {
717
718                                 if (boost::dynamic_pointer_cast<AudioTrack>(r)) {
719                                         lo_message_add_string (reply, "AT");
720                                 } else if (boost::dynamic_pointer_cast<MidiTrack>(r)) {
721                                         lo_message_add_string (reply, "MT");
722                                 } else {
723                                         lo_message_add_string (reply, "B");
724                                 }
725
726                                 lo_message_add_string (reply, r->name().c_str());
727                                 lo_message_add_int32 (reply, r->n_inputs().n_audio());
728                                 lo_message_add_int32 (reply, r->n_outputs().n_audio());
729                                 lo_message_add_int32 (reply, r->muted());
730                                 lo_message_add_int32 (reply, r->soloed());
731
732                         } else if (strcmp (path, "/strip/mute") == 0) {
733
734                                 lo_message_add_int32 (reply, (float) r->muted());
735
736                         } else if (strcmp (path, "/strip/solo") == 0) {
737
738                                 lo_message_add_int32 (reply, r->soloed());
739                         }
740                 }
741         }
742
743         lo_send_message (lo_message_get_source (msg), "#reply", reply);
744         lo_message_free (reply);
745 }
746
747 int
748 OSC::_catchall (const char *path, const char *types, lo_arg **argv, int argc, void *data, void *user_data)
749 {
750         return ((OSC*)user_data)->catchall (path, types, argv, argc, data);
751 }
752
753 int
754 OSC::catchall (const char *path, const char* types, lo_arg **argv, int argc, lo_message msg)
755 {
756         size_t len;
757         int ret = 1; /* unhandled */
758
759         //cerr << "Received a message, path = " << path << " types = \""
760         //     << (types ? types : "NULL") << '"' << endl;
761
762         /* 15 for /#current_value plus 2 for /<path> */
763
764         len = strlen (path);
765
766         if (len >= 17 && !strcmp (&path[len-15], "/#current_value")) {
767                 current_value_query (path, len, argv, argc, msg);
768                 ret = 0;
769
770         } else if (strcmp (path, "/strip/listen") == 0) {
771
772                 cerr << "set up listener\n";
773
774                 lo_message reply = lo_message_new ();
775
776                 if (argc <= 0) {
777                         lo_message_add_string (reply, "syntax error");
778                 } else {
779                         for (int n = 0; n < argc; ++n) {
780
781                                 boost::shared_ptr<Route> r = session->get_remote_nth_route (argv[n]->i);
782
783                                 if (!r) {
784                                         lo_message_add_string (reply, "not found");
785                                         cerr << "no such route\n";
786                                         break;
787                                 } else {
788                                         cerr << "add listener\n";
789                                         listen_to_route (r, lo_message_get_source (msg));
790                                         lo_message_add_int32 (reply, argv[n]->i);
791                                 }
792                         }
793                 }
794
795                 lo_send_message (lo_message_get_source (msg), "#reply", reply);
796                 lo_message_free (reply);
797
798                 ret = 0;
799
800         } else if (strcmp (path, "/strip/ignore") == 0) {
801
802                 for (int n = 0; n < argc; ++n) {
803
804                         boost::shared_ptr<Route> r = session->get_remote_nth_route (argv[n]->i);
805
806                         if (r) {
807                                 end_listen (r, lo_message_get_source (msg));
808                         }
809                 }
810
811                 ret = 0;
812         } else if (argc == 1 && types[0] == 'f') { // single float -- probably TouchOSC
813                 if (!strncmp (path, "/strip/gain/", 12) && strlen (path) > 12) {
814                         // in dB
815                         int ssid = atoi (&path[12]);
816                         route_set_gain_dB (ssid, argv[0]->f, msg);
817                         ret = 0;
818                 }
819                 else if (!strncmp (path, "/strip/fader/", 13) && strlen (path) > 13) {
820                         // in fader position
821                         int ssid = atoi (&path[13]);
822                         route_set_gain_fader (ssid, argv[0]->f, msg);
823                         ret = 0;
824                 }
825                 else if (!strncmp (path, "/strip/trimdB/", 14) && strlen (path) > 14) {
826                         int ssid = atoi (&path[14]);
827                         route_set_trim_dB (ssid, argv[0]->f, msg);
828                         ret = 0;
829                 }
830                 else if (!strncmp (path, "/strip/mute/", 12) && strlen (path) > 12) {
831                         int ssid = atoi (&path[12]);
832                         route_mute (ssid, argv[0]->f == 1.0, msg);
833                         ret = 0;
834                 }
835                 else if (!strncmp (path, "/strip/solo/", 12) && strlen (path) > 12) {
836                         int ssid = atoi (&path[12]);
837                         route_solo (ssid, argv[0]->f == 1.0, msg);
838                         ret = 0;
839                 }
840                 else if (!strncmp (path, "/strip/monitor_input/", 21) && strlen (path) > 21) {
841                         int ssid = atoi (&path[21]);
842                         route_monitor_input (ssid, argv[0]->f == 1.0, msg);
843                         ret = 0;
844                 }
845                 else if (!strncmp (path, "/strip/monitor_disk/", 20) && strlen (path) > 20) {
846                         int ssid = atoi (&path[20]);
847                         route_monitor_disk (ssid, argv[0]->f == 1.0, msg);
848                         ret = 0;
849                 }
850                 else if (!strncmp (path, "/strip/recenable/", 17) && strlen (path) > 17) {
851                         int ssid = atoi (&path[17]);
852                         route_recenable (ssid, argv[0]->f == 1.0, msg);
853                         ret = 0;
854                 }
855                 else if (!strncmp (path, "/strip/record_safe/", 19) && strlen (path) > 19) {
856                         int ssid = atoi (&path[19]);
857                         route_recsafe (ssid, argv[0]->f == 1.0, msg);
858                         ret = 0;
859                 }
860                 else if (!strncmp (path, "/strip/select/", 14) && strlen (path) > 14) {
861                         int ssid = atoi (&path[14]);
862                         strip_select (ssid, argv[0]->f == 1.0, msg);
863                         ret = 0;
864                 }
865                 else if (!strncmp (path, "/strip/gui_select/", 18) && strlen (path) > 18) {
866                         int ssid = atoi (&path[18]);
867                         strip_gui_select (ssid, argv[0]->f == 1.0, msg);
868                         ret = 0;
869                 }
870         }
871
872         if ((ret && _debugmode == Unhandled)) {
873                 debugmsg (_("Unhandled OSC message"), path, types, argv, argc);
874         }
875
876         return ret;
877 }
878
879 void
880 OSC::debugmsg (const char *prefix, const char *path, const char* types, lo_arg **argv, int argc)
881 {
882         std::stringstream ss;
883         for (int i = 0; i < argc; ++i) {
884                 lo_type type = (lo_type)types[i];
885                         ss << " ";
886                 switch (type) {
887                         case LO_INT32:
888                                 ss << "i:" << argv[i]->i;
889                                 break;
890                         case LO_FLOAT:
891                                 ss << "f:" << argv[i]->f;
892                                 break;
893                         case LO_DOUBLE:
894                                 ss << "d:" << argv[i]->d;
895                                 break;
896                         case LO_STRING:
897                                 ss << "s:" << &argv[i]->s;
898                                 break;
899                         case LO_INT64:
900                                 ss << "h:" << argv[i]->h;
901                                 break;
902                         case LO_CHAR:
903                                 ss << "c:" << argv[i]->s;
904                                 break;
905                         case LO_TIMETAG:
906                                 ss << "<Timetag>";
907                                 break;
908                         case LO_BLOB:
909                                 ss << "<BLOB>";
910                                 break;
911                         case LO_TRUE:
912                                 ss << "#T";
913                                 break;
914                         case LO_FALSE:
915                                 ss << "#F";
916                                 break;
917                         case LO_NIL:
918                                 ss << "NIL";
919                                 break;
920                         case LO_INFINITUM:
921                                 ss << "#inf";
922                                 break;
923                         case LO_MIDI:
924                                 ss << "<MIDI>";
925                                 break;
926                         case LO_SYMBOL:
927                                 ss << "<SYMBOL>";
928                                 break;
929                         default:
930                                 ss << "< ?? >";
931                                 break;
932                 }
933         }
934         PBD::info << prefix << ": " << path << ss.str() << endmsg;
935 }
936
937 void
938 OSC::update_clock ()
939 {
940
941 }
942
943 // "Application Hook" Handlers //
944 void
945 OSC::session_loaded (Session& s)
946 {
947 //      lo_address listener = lo_address_new (NULL, "7770");
948 //      lo_send (listener, "/session/loaded", "ss", s.path().c_str(), s.name().c_str());
949 }
950
951 void
952 OSC::session_exported (std::string path, std::string name)
953 {
954         lo_address listener = lo_address_new (NULL, "7770");
955         lo_send (listener, "/session/exported", "ss", path.c_str(), name.c_str());
956         lo_address_free (listener);
957 }
958
959 // end "Application Hook" Handlers //
960
961 /* path callbacks */
962
963 int
964 OSC::current_value (const char */*path*/, const char */*types*/, lo_arg **/*argv*/, int /*argc*/, void */*data*/, void* /*user_data*/)
965 {
966 #if 0
967         const char* returl;
968
969         if (argc < 3 || types == 0 || strlen (types) < 3 || types[0] != 's' || types[1] != 's' || types[2] != s) {
970                 return 1;
971         }
972
973         const char *returl = argv[1]->s;
974         lo_address addr = find_or_cache_addr (returl);
975
976         const char *retpath = argv[2]->s;
977
978
979         if (strcmp (argv[0]->s, "transport_frame") == 0) {
980
981                 if (session) {
982                         lo_send (addr, retpath, "i", session->transport_frame());
983                 }
984
985         } else if (strcmp (argv[0]->s, "transport_speed") == 0) {
986
987                 if (session) {
988                         lo_send (addr, retpath, "i", session->transport_frame());
989                 }
990
991         } else if (strcmp (argv[0]->s, "transport_locked") == 0) {
992
993                 if (session) {
994                         lo_send (addr, retpath, "i", session->transport_frame());
995                 }
996
997         } else if (strcmp (argv[0]->s, "punch_in") == 0) {
998
999                 if (session) {
1000                         lo_send (addr, retpath, "i", session->transport_frame());
1001                 }
1002
1003         } else if (strcmp (argv[0]->s, "punch_out") == 0) {
1004
1005                 if (session) {
1006                         lo_send (addr, retpath, "i", session->transport_frame());
1007                 }
1008
1009         } else if (strcmp (argv[0]->s, "rec_enable") == 0) {
1010
1011                 if (session) {
1012                         lo_send (addr, retpath, "i", session->transport_frame());
1013                 }
1014
1015         } else {
1016
1017                 /* error */
1018         }
1019 #endif
1020         return 0;
1021 }
1022
1023 void
1024 OSC::routes_list (lo_message msg)
1025 {
1026         if (!session) {
1027                 return;
1028         }
1029         for (int n = 0; n < (int) session->nroutes(); ++n) {
1030
1031                 boost::shared_ptr<Route> r = session->get_remote_nth_route (n);
1032
1033                 if (r) {
1034
1035                         lo_message reply = lo_message_new ();
1036
1037                         if (boost::dynamic_pointer_cast<AudioTrack>(r)) {
1038                                 lo_message_add_string (reply, "AT");
1039                         } else if (boost::dynamic_pointer_cast<MidiTrack>(r)) {
1040                                 lo_message_add_string (reply, "MT");
1041                         } else {
1042                                 lo_message_add_string (reply, "B");
1043                         }
1044
1045                         lo_message_add_string (reply, r->name().c_str());
1046                         lo_message_add_int32 (reply, r->n_inputs().n_audio());
1047                         lo_message_add_int32 (reply, r->n_outputs().n_audio());
1048                         lo_message_add_int32 (reply, r->muted());
1049                         lo_message_add_int32 (reply, r->soloed());
1050                         /* XXX Can only use order at this point */
1051                         lo_message_add_int32 (reply, r->presentation_info().order());
1052
1053                         if (boost::dynamic_pointer_cast<AudioTrack>(r)
1054                                         || boost::dynamic_pointer_cast<MidiTrack>(r)) {
1055
1056                                 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(r);
1057                                 lo_message_add_int32 (reply, (int32_t) t->rec_enable_control()->get_value());
1058                         }
1059
1060                         //Automatically listen to routes listed
1061                         listen_to_route(r, lo_message_get_source (msg));
1062
1063                         lo_send_message (lo_message_get_source (msg), "#reply", reply);
1064                         lo_message_free (reply);
1065                 }
1066         }
1067
1068         // Send end of listing message
1069         lo_message reply = lo_message_new ();
1070
1071         lo_message_add_string (reply, "end_route_list");
1072         lo_message_add_int64 (reply, session->frame_rate());
1073         lo_message_add_int64 (reply, session->current_end_frame());
1074
1075         lo_send_message (lo_message_get_source (msg), "#reply", reply);
1076
1077         lo_message_free (reply);
1078 }
1079
1080 int
1081 OSC::set_surface (uint32_t b_size, uint32_t strips, uint32_t fb, uint32_t gm, lo_message msg)
1082 {
1083         OSCSurface *s = get_surface(lo_message_get_source (msg));
1084         s->bank_size = b_size;
1085         s->strip_types = strips;
1086         //next line could be a call that finds out how many strips there are
1087         s->nstrips = session->nroutes(); // need to do this for strips
1088         s->feedback = fb;
1089         s->gainmode = gm;
1090         // set bank and strip feedback
1091         set_bank(s->bank, msg);
1092
1093         global_feedback (s->feedback, msg, s->gainmode);
1094         return 0;
1095 }
1096
1097 int
1098 OSC::set_surface_bank_size (uint32_t bs, lo_message msg)
1099 {
1100         OSCSurface *s = get_surface(lo_message_get_source (msg));
1101         s->bank_size = bs;
1102
1103         // set bank and strip feedback
1104         set_bank(s->bank, msg);
1105         return 0;
1106 }
1107
1108
1109 int
1110 OSC::set_surface_strip_types (uint32_t st, lo_message msg)
1111 {
1112         OSCSurface *s = get_surface(lo_message_get_source (msg));
1113         s->strip_types = st;
1114         //next line could be a call that finds out how many strips there are
1115         s->nstrips = session->nroutes(); // need to do this for strips
1116
1117         // set bank and strip feedback
1118         set_bank(s->bank, msg);
1119         return 0;
1120 }
1121
1122
1123 int
1124 OSC::set_surface_feedback (uint32_t fb, lo_message msg)
1125 {
1126         OSCSurface *s = get_surface(lo_message_get_source (msg));
1127         s->feedback = fb;
1128
1129         // set bank and strip feedback
1130         set_bank(s->bank, msg);
1131
1132         // Set global/master feedback
1133         global_feedback (s->feedback, msg, s->gainmode);
1134         return 0;
1135 }
1136
1137
1138 int
1139 OSC::set_surface_gainmode (uint32_t gm, lo_message msg)
1140 {
1141         OSCSurface *s = get_surface(lo_message_get_source (msg));
1142         s->gainmode = gm;
1143
1144         // set bank and strip feedback
1145         set_bank(s->bank, msg);
1146
1147         // Set global/master feedback
1148         global_feedback (s->feedback, msg, s->gainmode);
1149         return 0;
1150 }
1151
1152 OSC::OSCSurface *
1153 OSC::get_surface (lo_address addr)
1154 {
1155         string r_url;
1156         char * rurl;
1157         rurl = lo_address_get_url (addr);
1158         r_url = rurl;
1159         free (rurl);
1160         for (uint32_t it = 0; it < _surface.size(); ++it) {
1161                 //find setup for this server
1162                 if (!_surface[it].remote_url.find(r_url)){
1163                         return &_surface[it];
1164                 }
1165         }
1166         // No surface create one with default values
1167         OSCSurface s;
1168         s.remote_url = r_url;
1169         s.bank = 1;
1170         s.bank_size = 0; // need to find out how many strips there are
1171         s.nstrips = session->nroutes(); // may need to do this after MARK below
1172         s.strip_types = 31; // 31 is tracks, busses, and VCAs (no master/monitor)
1173         s.feedback = 0;
1174         s.gainmode = 0;
1175         //get sorted should go here
1176         _surface.push_back (s);
1177         //MARK
1178         return &_surface[_surface.size() - 1];
1179 }
1180
1181 // setup global feedback for a surface
1182 void
1183 OSC::global_feedback (bitset<32> feedback, lo_address msg, uint32_t gainmode)
1184 {
1185         // first destroy global observer for this surface
1186         GlobalObservers::iterator x;
1187
1188         for (x = global_observers.begin(); x != global_observers.end();) {
1189
1190                 OSCGlobalObserver* ro;
1191
1192                 if ((ro = dynamic_cast<OSCGlobalObserver*>(*x)) != 0) {
1193
1194                         int res = strcmp(lo_address_get_url(ro->address()), lo_address_get_url(lo_message_get_source (msg)));
1195
1196                         if (res == 0) {
1197                                 delete *x;
1198                                 x = global_observers.erase (x);
1199                         } else {
1200                                 ++x;
1201                         }
1202                 } else {
1203                         ++x;
1204                 }
1205         }
1206         if (feedback[4] || feedback[3] || feedback[5] || feedback[6]) {
1207                 // create a new Global Observer for this surface
1208                 //OSCSurface *s = get_surface (lo_message_get_source (msg));
1209                 OSCGlobalObserver* o = new OSCGlobalObserver (*session, lo_message_get_source (msg), gainmode, /*s->*/feedback);
1210                 global_observers.push_back (o);
1211         }
1212 }
1213
1214 /*
1215  * This gets called not only when bank changes but also:
1216  *  - bank size change
1217  *  - feedback change
1218  *  - strip types changes
1219  *  - fadermode changes
1220  *  - stripable creation/deletion/flag
1221  *  - to refresh what is "displayed"
1222  * Basically any time the bank needs to be rebuilt
1223  */
1224 int
1225 OSC::set_bank (uint32_t bank_start, lo_message msg)
1226 {
1227         if (!session) {
1228                 return -1;
1229         }
1230         //StripableList strips;
1231         //session->get_stripables (strips);
1232         // no nstripables yet
1233         if (!session->nroutes()) {
1234                 return -1;
1235         }
1236         // don't include monitor or master in count for now
1237         uint32_t nstrips;
1238         if (session->monitor_out ()) {
1239                 nstrips = session->nroutes() - 2;
1240         } else {
1241                 nstrips = session->nroutes() - 1;
1242         }
1243         // undo all listeners for this url
1244         for (int n = 1; n <= (int) nstrips; ++n) {
1245
1246                 boost::shared_ptr<Stripable> stp = session->get_remote_nth_stripable (n, PresentationInfo::Route);
1247
1248                 if (stp) {
1249                         end_listen (stp, lo_message_get_source (msg));
1250                 }
1251         }
1252
1253         OSCSurface *s = get_surface (lo_message_get_source (msg));
1254         uint32_t b_size;
1255
1256         if (!s->bank_size) {
1257                 // no banking
1258                 b_size = nstrips;
1259         } else {
1260                 b_size = s->bank_size;
1261         }
1262
1263         // Do limits checking - high end still not quite right
1264         if (bank_start < 1) bank_start = 1;
1265         if (b_size >= nstrips)  {
1266                 bank_start = 1;
1267         } else if ((bank_start > nstrips)) {
1268                 bank_start = (uint32_t)((nstrips - b_size) + 1);
1269         }
1270         //save bank in case we have had to change it
1271         s->bank = bank_start;
1272
1273         if (s->feedback[0] || s->feedback[1]) {
1274                 for (int n = bank_start; n < (int) (b_size + bank_start); ++n) {
1275                         // this next will eventually include strip types
1276                         boost::shared_ptr<Stripable> stp = session->get_remote_nth_stripable (n, PresentationInfo::Route);
1277
1278                         if (stp) {
1279                         listen_to_route(stp, lo_message_get_source (msg));
1280                         }
1281                 }
1282         }
1283         return 0;
1284 }
1285
1286 int
1287 OSC::bank_up (lo_message msg)
1288 {
1289         if (!session) {
1290                 return -1;
1291         }
1292         OSCSurface *s = get_surface(lo_message_get_source (msg));
1293         set_bank (s->bank + s->bank_size, msg);
1294         return 0;
1295 }
1296
1297 int
1298 OSC::bank_down (lo_message msg)
1299 {
1300         if (!session) {
1301                 return -1;
1302         }
1303         OSCSurface *s = get_surface(lo_message_get_source (msg));
1304         if (s->bank < s->bank_size) {
1305                 set_bank (1, msg);
1306         } else {
1307                 set_bank (s->bank - s->bank_size, msg);
1308         }
1309         return 0;
1310 }
1311
1312 uint32_t
1313 OSC::get_sid (uint32_t rid, lo_address addr)
1314 {
1315         OSCSurface *s = get_surface(addr);
1316         return rid - s->bank + 1;
1317 }
1318
1319 uint32_t
1320 OSC::get_rid (uint32_t sid, lo_address addr)
1321 {
1322         OSCSurface *s = get_surface(addr);
1323         return sid + s->bank - 1;
1324 }
1325
1326 void
1327 OSC::transport_frame (lo_message msg)
1328 {
1329         if (!session) {
1330                 return;
1331         }
1332         framepos_t pos = session->transport_frame ();
1333
1334         lo_message reply = lo_message_new ();
1335         lo_message_add_int64 (reply, pos);
1336
1337         lo_send_message (lo_message_get_source (msg), "/transport_frame", reply);
1338
1339         lo_message_free (reply);
1340 }
1341
1342 void
1343 OSC::transport_speed (lo_message msg)
1344 {
1345         if (!session) {
1346                 return;
1347         }
1348         double ts = session->transport_speed ();
1349
1350         lo_message reply = lo_message_new ();
1351         lo_message_add_double (reply, ts);
1352
1353         lo_send_message (lo_message_get_source (msg), "/transport_speed", reply);
1354
1355         lo_message_free (reply);
1356 }
1357
1358 void
1359 OSC::record_enabled (lo_message msg)
1360 {
1361         if (!session) {
1362                 return;
1363         }
1364         int re = (int)session->get_record_enabled ();
1365
1366         lo_message reply = lo_message_new ();
1367         lo_message_add_int32 (reply, re);
1368
1369         lo_send_message (lo_message_get_source (msg), "/record_enabled", reply);
1370
1371         lo_message_free (reply);
1372 }
1373
1374 // master and monitor calls
1375 int
1376 OSC::master_set_gain (float dB)
1377 {
1378         if (!session) return -1;
1379         boost::shared_ptr<Stripable> s = session->master_out();
1380         if (s) {
1381                 if (dB < -192) {
1382                         s->gain_control()->set_value (0.0, PBD::Controllable::NoGroup);
1383                 } else {
1384                         s->gain_control()->set_value (dB_to_coefficient (dB), PBD::Controllable::NoGroup);
1385                 }
1386         }
1387         return 0;
1388 }
1389
1390 int
1391 OSC::master_set_fader (uint32_t position)
1392 {
1393         if (!session) return -1;
1394         boost::shared_ptr<Stripable> s = session->master_out();
1395         if (s) {
1396                 if ((position > 799.5) && (position < 800.5)) {
1397                         s->gain_control()->set_value (1.0, PBD::Controllable::NoGroup);
1398                 } else {
1399                         s->gain_control()->set_value (slider_position_to_gain_with_max (((float)position/1023), 2.0), PBD::Controllable::NoGroup);
1400                 }
1401         }
1402         return 0;
1403 }
1404
1405 int
1406 OSC::master_set_trim (float dB)
1407 {
1408         if (!session) return -1;
1409         boost::shared_ptr<Stripable> s = session->master_out();
1410
1411         if (s) {
1412                 s->trim_control()->set_value (dB_to_coefficient (dB), PBD::Controllable::NoGroup);
1413         }
1414
1415         return 0;
1416 }
1417
1418 int
1419 OSC::master_set_pan_stereo_position (float position)
1420 {
1421         if (!session) return -1;
1422
1423         boost::shared_ptr<Stripable> s = session->master_out();
1424
1425         if (s) {
1426                 if (s->pan_azimuth_control()) {
1427                         s->pan_azimuth_control()->set_value (position, PBD::Controllable::NoGroup);
1428                 }
1429         }
1430
1431         return 0;
1432 }
1433
1434 int
1435 OSC::master_set_mute (uint32_t state)
1436 {
1437         if (!session) return -1;
1438
1439         boost::shared_ptr<Stripable> s = session->master_out();
1440
1441         if (s) {
1442                 s->mute_control()->set_value (state, PBD::Controllable::NoGroup);
1443         }
1444
1445         return 0;
1446 }
1447
1448 int
1449 OSC::monitor_set_gain (float dB)
1450 {
1451         if (!session) return -1;
1452         boost::shared_ptr<Stripable> s = session->monitor_out();
1453
1454         if (s) {
1455                 if (dB < -192) {
1456                         s->gain_control()->set_value (0.0, PBD::Controllable::NoGroup);
1457                 } else {
1458                         s->gain_control()->set_value (dB_to_coefficient (dB), PBD::Controllable::NoGroup);
1459                 }
1460         }
1461         return 0;
1462 }
1463
1464 int
1465 OSC::monitor_set_fader (uint32_t position)
1466 {
1467         if (!session) return -1;
1468         boost::shared_ptr<Stripable> s = session->monitor_out();
1469         if (s) {
1470                 if ((position > 799.5) && (position < 800.5)) {
1471                         s->gain_control()->set_value (1.0, PBD::Controllable::NoGroup);
1472                 } else {
1473                         s->gain_control()->set_value (slider_position_to_gain_with_max (((float)position/1023), 2.0), PBD::Controllable::NoGroup);
1474                 }
1475         }
1476         return 0;
1477 }
1478
1479 // strip calls
1480 int
1481 OSC::route_mute (int ssid, int yn, lo_message msg)
1482 {
1483         if (!session) return -1;
1484         int rid = get_rid (ssid, lo_message_get_source (msg));
1485
1486         boost::shared_ptr<Stripable> s = session->get_remote_nth_stripable (rid, PresentationInfo::Route);
1487
1488         if (s) {
1489                 s->mute_control()->set_value (yn ? 1.0 : 0.0, PBD::Controllable::NoGroup);
1490         }
1491
1492         return 0;
1493 }
1494
1495 int
1496 OSC::route_solo (int ssid, int yn, lo_message msg)
1497 {
1498         if (!session) return -1;
1499         int rid = get_rid (ssid, lo_message_get_source (msg));
1500
1501         boost::shared_ptr<Stripable> s = session->get_remote_nth_stripable (rid, PresentationInfo::Route);
1502
1503         if (s) {
1504                 s->solo_control()->set_value (yn ? 1.0 : 0.0, PBD::Controllable::NoGroup);
1505         }
1506
1507         return 0;
1508 }
1509
1510 int
1511 OSC::sel_recenable (uint32_t yn, lo_message msg)
1512 {
1513         OSCSurface *sur = get_surface(lo_message_get_source (msg));
1514         return route_recenable(sur->surface_sel, yn, msg);
1515 }
1516
1517 int
1518 OSC::route_recenable (int ssid, int yn, lo_message msg)
1519 {
1520         if (!session) return -1;
1521         int rid = get_rid (ssid, lo_message_get_source (msg));
1522
1523         boost::shared_ptr<Stripable> s = session->get_remote_nth_stripable (rid, PresentationInfo::Route);
1524
1525         if (s) {
1526                 if (s->rec_enable_control()) {
1527                         s->rec_enable_control()->set_value (yn, PBD::Controllable::UseGroup);
1528                         if (s->rec_enable_control()->get_value()) {
1529                                 return 0;
1530                         }
1531                 }
1532         }
1533         // hmm, not set for whatever reason tell surface
1534         return route_send_fail ("/strip/recenable", ssid, msg);
1535 }
1536
1537 int
1538 OSC::sel_recsafe (uint32_t yn, lo_message msg)
1539 {
1540         OSCSurface *sur = get_surface(lo_message_get_source (msg));
1541         return route_recsafe(sur->surface_sel, yn, msg);
1542 }
1543
1544 int
1545 OSC::route_recsafe (int ssid, int yn, lo_message msg)
1546 {
1547         if (!session) return -1;
1548         int rid = get_rid (ssid, lo_message_get_source (msg));
1549
1550         boost::shared_ptr<Stripable> s = session->get_remote_nth_stripable (rid, PresentationInfo::Route);
1551         if (s) {
1552                 if (s->rec_safe_control()) {
1553                         s->rec_safe_control()->set_value (yn, PBD::Controllable::UseGroup);
1554                         if (s->rec_safe_control()->get_value()) {
1555                                 return 0;
1556                         }
1557                 }
1558         }
1559         // hmm, not set for whatever reason tell surface
1560         return route_send_fail ("/strip/record_safe", ssid, msg);
1561 }
1562
1563 int
1564 OSC::route_monitor_input (int ssid, int yn, lo_message msg)
1565 {
1566         if (!session) return -1;
1567         int rid = get_rid (ssid, lo_message_get_source (msg));
1568
1569         boost::shared_ptr<Stripable> s = session->get_remote_nth_stripable (rid, PresentationInfo::Route);
1570
1571         if (s) {
1572                 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (s);
1573                 if (track) {
1574                         track->monitoring_control()->set_value (yn ? 1.0 : 0.0, PBD::Controllable::NoGroup);
1575                 } else {
1576                         route_send_fail ("/strip/monitor_input", ssid, msg);
1577                 }
1578
1579         }
1580
1581         return 0;
1582 }
1583
1584 int
1585 OSC::route_monitor_disk (int ssid, int yn, lo_message msg)
1586 {
1587         if (!session) return -1;
1588         int rid = get_rid (ssid, lo_message_get_source (msg));
1589
1590         boost::shared_ptr<Stripable> s = session->get_remote_nth_stripable (rid, PresentationInfo::Route);
1591
1592         if (s) {
1593                 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (s);
1594                 if (track) {
1595                         track->monitoring_control()->set_value (yn ? 2.0 : 0.0, PBD::Controllable::NoGroup);
1596                 } else {
1597                         route_send_fail ("/strip/monitor_disk", ssid, msg);
1598                 }
1599
1600         }
1601
1602         return 0;
1603 }
1604
1605 int
1606 OSC::strip_select (int ssid, int yn, lo_message msg)
1607 {
1608         //ignore button release
1609         if (!yn) return 0;
1610
1611         if (!session) {
1612                 route_send_fail ("/strip/select", ssid, msg);
1613                 return -1;
1614         }
1615         int rid = get_rid (ssid, lo_message_get_source (msg));
1616         boost::shared_ptr<Stripable> s = session->get_remote_nth_stripable (rid, PresentationInfo::Route);
1617         OSCSurface *sur = get_surface(lo_message_get_source (msg));
1618         delete sur->sel_obs;
1619
1620         if (s) {
1621                 sur->surface_sel = ssid;
1622                 OSCSelectObserver* sel_fb = new OSCSelectObserver (s, lo_message_get_source (msg), ssid, sur->gainmode, sur->feedback);
1623                 sur->sel_obs = sel_fb;
1624         } else {
1625                 route_send_fail ("/strip/select", ssid, msg);
1626         }
1627         int b_s = sur->bank_size;
1628         if (!b_s) { // bank size 0 means we need to know how many strips there are.
1629                 b_s = sur->nstrips;
1630         }
1631         for (int i = 1;  i <= b_s; i++) {
1632                         if (i==ssid) {
1633                                 string path = "/strip/select";
1634                                 lo_message reply = lo_message_new ();
1635                                 if (sur->feedback[2]) {
1636                                         ostringstream os;
1637                                         os << path << "/" << ssid;
1638                                         path = os.str();
1639                                 } else {
1640                                 lo_message_add_int32 (reply, ssid);
1641                                 }
1642                                 lo_message_add_float (reply, (float) 1);
1643
1644                                 lo_send_message (lo_message_get_source (msg), path.c_str(), reply);
1645                                 lo_message_free (reply);
1646                         } else {
1647                                 route_send_fail ("/strip/select", i, msg);
1648                         }
1649         }
1650
1651         return 0;
1652 }
1653
1654 int
1655 OSC::strip_gui_select (int ssid, int yn, lo_message msg)
1656 {
1657         //ignore button release
1658         if (!yn) return 0;
1659
1660         if (!session) {
1661                 route_send_fail ("/strip/gui_select", ssid, msg);
1662                 return -1;
1663         }
1664         int rid = get_rid (ssid, lo_message_get_source (msg));
1665         boost::shared_ptr<Stripable> s = session->get_remote_nth_stripable (rid, PresentationInfo::Route);
1666         OSCSurface *sur = get_surface(lo_message_get_source (msg));
1667
1668         if (s) {
1669                 sur->surface_sel = ssid;
1670         } else {
1671                 route_send_fail ("/strip/gui_select", ssid, msg);
1672         }
1673
1674         return 0;
1675 }
1676
1677 int
1678 OSC::route_set_gain_abs (int rid, float level, lo_message msg)
1679 {
1680         if (!session) return -1;
1681         boost::shared_ptr<Stripable> s = session->get_remote_nth_stripable (rid, PresentationInfo::Route);
1682
1683         if (s) {
1684                 s->gain_control()->set_value (level, PBD::Controllable::NoGroup);
1685         }
1686
1687         return 0;
1688 }
1689
1690 int
1691 OSC::route_set_gain_dB (int ssid, float dB, lo_message msg)
1692 {
1693         if (!session) return -1;
1694         int rid = get_rid (ssid, lo_message_get_source (msg));
1695         if (dB < -192) {
1696                 return route_set_gain_abs (rid, 0.0, msg);
1697         }
1698         return route_set_gain_abs (rid, dB_to_coefficient (dB), msg);
1699 }
1700
1701 int
1702 OSC::route_set_gain_fader (int ssid, float pos, lo_message msg)
1703 {
1704         if (!session) return -1;
1705         int rid = get_rid (ssid, lo_message_get_source (msg));
1706         if ((pos > 799.5) && (pos < 800.5)) {
1707                 return route_set_gain_abs (rid, 1.0, msg);
1708         } else {
1709                 return route_set_gain_abs (rid, slider_position_to_gain_with_max ((pos/1023), 2.0), msg);
1710         }
1711 }
1712
1713
1714 int
1715 OSC::route_set_trim_abs (int ssid, float level, lo_message msg)
1716 {
1717         if (!session) return -1;
1718         int rid = get_rid (ssid, lo_message_get_source (msg));
1719
1720         boost::shared_ptr<Stripable> s = session->get_remote_nth_stripable (rid, PresentationInfo::Route);
1721
1722         if (s) {
1723                 if (s->trim_control()) {
1724                         s->trim_control()->set_value (level, PBD::Controllable::NoGroup);
1725                 }
1726
1727         }
1728
1729         return 0;
1730 }
1731
1732 int
1733 OSC::route_set_trim_dB (int ssid, float dB, lo_message msg)
1734 {
1735         return route_set_trim_abs(ssid, dB_to_coefficient (dB), msg);
1736 }
1737
1738
1739 int
1740 OSC::route_set_pan_stereo_position (int ssid, float pos, lo_message msg)
1741 {
1742         if (!session) return -1;
1743         int rid = get_rid (ssid, lo_message_get_source (msg));
1744
1745         boost::shared_ptr<Stripable> s = session->get_remote_nth_stripable (rid, PresentationInfo::Route);
1746
1747         if (s) {
1748                 if(s->pan_azimuth_control()) {
1749                         s->pan_azimuth_control()->set_value (pos, PBD::Controllable::NoGroup);
1750                 }
1751         }
1752
1753         return 0;
1754
1755 }
1756
1757 int
1758 OSC::route_set_pan_stereo_width (int ssid, float pos, lo_message msg)
1759 {
1760         if (!session) return -1;
1761         int rid = get_rid (ssid, lo_message_get_source (msg));
1762
1763         boost::shared_ptr<Stripable> s = session->get_remote_nth_stripable (rid, PresentationInfo::Route);
1764
1765         if (s) {
1766                 if (s->pan_width_control()) {
1767                         s->pan_width_control()->set_value (pos, PBD::Controllable::NoGroup);
1768                 }
1769         }
1770
1771         return 0;
1772
1773 }
1774
1775 int
1776 OSC::route_set_send_gain_abs (int ssid, int sid, float val, lo_message msg)
1777 {
1778         if (!session) {
1779                 return -1;
1780         }
1781         int rid = get_rid (ssid, lo_message_get_source (msg));
1782
1783         boost::shared_ptr<Stripable> s = session->get_remote_nth_stripable (rid, PresentationInfo::Route);
1784
1785         if (!s) {
1786                 return -1;
1787         }
1788
1789         /* revert to zero-based counting */
1790
1791         if (sid > 0) {
1792                 --sid;
1793         }
1794
1795         if (s->send_level_controllable (sid)) {
1796                 s->send_level_controllable (sid)->set_value (val, PBD::Controllable::NoGroup);
1797         }
1798
1799         return 0;
1800 }
1801
1802 int
1803 OSC::route_set_send_gain_dB (int ssid, int sid, float val, lo_message msg)
1804 {
1805         return route_set_send_gain_abs (ssid, sid, dB_to_coefficient (val), msg);
1806 }
1807
1808 int
1809 OSC::route_plugin_parameter (int ssid, int piid, int par, float val, lo_message msg)
1810 {
1811         if (!session)
1812                 return -1;
1813         int rid = get_rid (ssid, lo_message_get_source (msg));
1814
1815         boost::shared_ptr<Route> r = session->get_remote_nth_route (rid);
1816
1817         if (!r) {
1818                 PBD::error << "OSC: Invalid Remote Control ID '" << rid << "'" << endmsg;
1819                 return -1;
1820         }
1821
1822         boost::shared_ptr<Processor> redi=r->nth_plugin (piid);
1823
1824         if (!redi) {
1825                 PBD::error << "OSC: cannot find plugin # " << piid << " for RID '" << rid << "'" << endmsg;
1826                 return -1;
1827         }
1828
1829         boost::shared_ptr<PluginInsert> pi;
1830
1831         if (!(pi = boost::dynamic_pointer_cast<PluginInsert>(redi))) {
1832                 PBD::error << "OSC: given processor # " << piid << " on RID '" << rid << "' is not a Plugin." << endmsg;
1833                 return -1;
1834         }
1835
1836         boost::shared_ptr<ARDOUR::Plugin> pip = pi->plugin();
1837         bool ok=false;
1838
1839         uint32_t controlid = pip->nth_parameter (par,ok);
1840
1841         if (!ok) {
1842                 PBD::error << "OSC: Cannot find parameter # " << par <<  " for plugin # " << piid << " on RID '" << rid << "'" << endmsg;
1843                 return -1;
1844         }
1845
1846         if (!pip->parameter_is_input(controlid)) {
1847                 PBD::error << "OSC: Parameter # " << par <<  " for plugin # " << piid << " on RID '" << rid << "' is not a control input" << endmsg;
1848                 return -1;
1849         }
1850
1851         ParameterDescriptor pd;
1852         pi->plugin()->get_parameter_descriptor (controlid,pd);
1853
1854         if (val >= pd.lower && val <= pd.upper) {
1855
1856                 boost::shared_ptr<AutomationControl> c = pi->automation_control (Evoral::Parameter(PluginAutomation, 0, controlid));
1857                 // cerr << "parameter:" << redi->describe_parameter(controlid) << " val:" << val << "\n";
1858                 c->set_value (val, PBD::Controllable::NoGroup);
1859         } else {
1860                 PBD::warning << "OSC: Parameter # " << par <<  " for plugin # " << piid << " on RID '" << rid << "' is out of range" << endmsg;
1861                 PBD::info << "OSC: Valid range min=" << pd.lower << " max=" << pd.upper << endmsg;
1862         }
1863
1864         return 0;
1865 }
1866
1867 //prints to cerr only
1868 int
1869 OSC::route_plugin_parameter_print (int ssid, int piid, int par, lo_message msg)
1870 {
1871         if (!session) {
1872                 return -1;
1873         }
1874         int rid = get_rid (ssid, lo_message_get_source (msg));
1875
1876         boost::shared_ptr<Route> r = session->get_remote_nth_route (rid);
1877
1878         if (!r) {
1879                 return -1;
1880         }
1881
1882         boost::shared_ptr<Processor> redi=r->nth_processor (piid);
1883
1884         if (!redi) {
1885                 return -1;
1886         }
1887
1888         boost::shared_ptr<PluginInsert> pi;
1889
1890         if (!(pi = boost::dynamic_pointer_cast<PluginInsert>(redi))) {
1891                 return -1;
1892         }
1893
1894         boost::shared_ptr<ARDOUR::Plugin> pip = pi->plugin();
1895         bool ok=false;
1896
1897         uint32_t controlid = pip->nth_parameter (par,ok);
1898
1899         if (!ok) {
1900                 return -1;
1901         }
1902
1903         ParameterDescriptor pd;
1904
1905         if (pi->plugin()->get_parameter_descriptor (controlid, pd) == 0) {
1906                 boost::shared_ptr<AutomationControl> c = pi->automation_control (Evoral::Parameter(PluginAutomation, 0, controlid));
1907
1908                 cerr << "parameter:     " << redi->describe_parameter(controlid)  << "\n";
1909                 cerr << "current value: " << c->get_value ();
1910                 cerr << "lower value:   " << pd.lower << "\n";
1911                 cerr << "upper value:   " << pd.upper << "\n";
1912         }
1913
1914         return 0;
1915 }
1916
1917 // timer callbacks
1918 bool
1919 OSC::periodic (void)
1920 {
1921         for (GlobalObservers::iterator x = global_observers.begin(); x != global_observers.end(); x++) {
1922
1923                 OSCGlobalObserver* go;
1924
1925                 if ((go = dynamic_cast<OSCGlobalObserver*>(*x)) != 0) {
1926                         go->tick();
1927                 }
1928         }
1929         for (RouteObservers::iterator x = route_observers.begin(); x != route_observers.end(); x++) {
1930
1931                 OSCRouteObserver* ro;
1932
1933                 if ((ro = dynamic_cast<OSCRouteObserver*>(*x)) != 0) {
1934                         ro->tick();
1935                 }
1936         }
1937         for (uint32_t it = 0; it < _surface.size(); ++it) {
1938                 OSCSurface* sur = &_surface[it];
1939                 OSCSelectObserver* so;
1940                 if ((so = dynamic_cast<OSCSelectObserver*>(sur->sel_obs)) != 0) {
1941                         so->tick();
1942                 }
1943         }
1944         return true;
1945 }
1946
1947 int
1948 OSC::route_send_fail (string path, uint32_t ssid, lo_message msg)
1949 {
1950         OSCSurface *sur = get_surface(lo_message_get_source (msg));
1951
1952         lo_message reply = lo_message_new ();
1953         if (sur->feedback[2]) {
1954                 ostringstream os;
1955                 os << path << "/" << ssid;
1956                 path = os.str();
1957         } else {
1958                 lo_message_add_int32 (reply, ssid);
1959         }
1960         lo_message_add_float (reply, (float) 0);
1961
1962         lo_send_message (lo_message_get_source (msg), path.c_str(), reply);
1963         lo_message_free (reply);
1964         return 0;
1965 }
1966
1967 XMLNode&
1968 OSC::get_state ()
1969 {
1970         XMLNode& node (ControlProtocol::get_state());
1971         node.add_property("debugmode", (int) _debugmode); // TODO: enum2str
1972         return node;
1973 }
1974
1975 int
1976 OSC::set_state (const XMLNode& node, int version)
1977 {
1978         if (ControlProtocol::set_state (node, version)) {
1979                 return -1;
1980         }
1981         XMLProperty const * p = node.property (X_("debugmode"));
1982         if (p) {
1983                 _debugmode = OSCDebugMode (PBD::atoi(p->value ()));
1984         }
1985
1986         return 0;
1987 }