change Controllable::set_value() API to include grouped control consideration.
[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/dB.h"
42 #include "ardour/filesystem_paths.h"
43 #include "ardour/panner.h"
44 #include "ardour/plugin.h"
45 #include "ardour/plugin_insert.h"
46 #include "ardour/send.h"
47
48 #include "osc.h"
49 #include "osc_controllable.h"
50 #include "osc_route_observer.h"
51 #include "i18n.h"
52
53 using namespace ARDOUR;
54 using namespace std;
55 using namespace Glib;
56 using namespace ArdourSurface;
57
58 #include "pbd/abstract_ui.cc" // instantiate template
59
60 OSC* OSC::_instance = 0;
61
62 #ifdef DEBUG
63 static void error_callback(int num, const char *m, const char *path)
64 {
65         fprintf(stderr, "liblo server error %d in path %s: %s\n", num, path, m);
66 }
67 #else
68 static void error_callback(int, const char *, const char *)
69 {
70
71 }
72 #endif
73
74 OSC::OSC (Session& s, uint32_t port)
75         : ControlProtocol (s, X_("Open Sound Control (OSC)"))
76         , AbstractUI<OSCUIRequest> (name())
77         , local_server (0)
78         , remote_server (0)
79         , _port(port)
80         , _ok (true)
81         , _shutdown (false)
82         , _osc_server (0)
83         , _osc_unix_server (0)
84         , _namespace_root ("/ardour")
85         , _send_route_changes (true)
86 {
87         _instance = this;
88
89         session_loaded (s);
90         session->Exported.connect (*this, MISSING_INVALIDATOR, boost::bind (&OSC::session_exported, this, _1, _2), this);
91 }
92
93 OSC::~OSC()
94 {
95         stop ();
96         _instance = 0;
97 }
98
99 void*
100 OSC::request_factory (uint32_t num_requests)
101 {
102         /* AbstractUI<T>::request_buffer_factory() is a template method only
103            instantiated in this source module. To provide something visible for
104            use in the interface/descriptor, we have this static method that is
105            template-free.
106         */
107         return request_buffer_factory (num_requests);
108 }
109
110 void
111 OSC::do_request (OSCUIRequest* req)
112 {
113         if (req->type == CallSlot) {
114
115                 call_slot (MISSING_INVALIDATOR, req->the_slot);
116
117         } else if (req->type == Quit) {
118
119                 stop ();
120         }
121 }
122
123 int
124 OSC::set_active (bool yn)
125 {
126         if (yn != active()) {
127
128                 if (yn) {
129                         if (start ()) {
130                                 return -1;
131                         }
132                 } else {
133                         if (stop ()) {
134                                 return -1;
135                         }
136                 }
137
138         }
139
140         return ControlProtocol::set_active (yn);
141 }
142
143 bool
144 OSC::get_active () const
145 {
146         return _osc_server != 0;
147 }
148
149 int
150 OSC::set_feedback (bool yn)
151 {
152         _send_route_changes = yn;
153         return 0;
154 }
155
156 bool
157 OSC::get_feedback () const
158 {
159         return _send_route_changes;
160 }
161
162 int
163 OSC::start ()
164 {
165         char tmpstr[255];
166
167         if (_osc_server) {
168                 /* already started */
169                 return 0;
170         }
171
172         for (int j=0; j < 20; ++j) {
173                 snprintf(tmpstr, sizeof(tmpstr), "%d", _port);
174
175                 //if ((_osc_server = lo_server_new_with_proto (tmpstr, LO_TCP, error_callback))) {
176                 //      break;
177                 //}
178
179                 if ((_osc_server = lo_server_new (tmpstr, error_callback))) {
180                         break;
181                 }
182
183 #ifdef DEBUG
184                 cerr << "can't get osc at port: " << _port << endl;
185 #endif
186                 _port++;
187                 continue;
188         }
189
190         if (!_osc_server) {
191                 return 1;
192         }
193
194 #ifdef ARDOUR_OSC_UNIX_SERVER
195
196         // APPEARS sluggish for now
197
198         // attempt to create unix socket server too
199
200         snprintf(tmpstr, sizeof(tmpstr), "/tmp/sooperlooper_XXXXXX");
201         int fd = mkstemp(tmpstr);
202
203         if (fd >= 0 ) {
204                 ::g_unlink (tmpstr);
205                 close (fd);
206
207                 _osc_unix_server = lo_server_new (tmpstr, error_callback);
208
209                 if (_osc_unix_server) {
210                         _osc_unix_socket_path = tmpstr;
211                 }
212         }
213 #endif
214
215         PBD::info << "OSC @ " << get_server_url () << endmsg;
216
217         std::string url_file;
218
219         if (find_file (ardour_config_search_path(), "osc_url", url_file)) {
220                 _osc_url_file = url_file;
221                 if (g_file_set_contents (_osc_url_file.c_str(), get_server_url().c_str(), -1, NULL)) {
222                         cerr << "Couldn't write '" <<  _osc_url_file << "'" <<endl;
223                 }
224         }
225
226         register_callbacks();
227
228         // lo_server_thread_add_method(_sthread, NULL, NULL, OSC::_dummy_handler, this);
229
230         /* startup the event loop thread */
231
232         BaseUI::run ();
233
234         return 0;
235 }
236
237 void
238 OSC::thread_init ()
239 {
240         pthread_set_name (event_loop_name().c_str());
241
242         if (_osc_unix_server) {
243                 Glib::RefPtr<IOSource> src = IOSource::create (lo_server_get_socket_fd (_osc_unix_server), IO_IN|IO_HUP|IO_ERR);
244                 src->connect (sigc::bind (sigc::mem_fun (*this, &OSC::osc_input_handler), _osc_unix_server));
245                 src->attach (_main_loop->get_context());
246                 local_server = src->gobj();
247                 g_source_ref (local_server);
248         }
249
250         if (_osc_server) {
251                 Glib::RefPtr<IOSource> src  = IOSource::create (lo_server_get_socket_fd (_osc_server), IO_IN|IO_HUP|IO_ERR);
252                 src->connect (sigc::bind (sigc::mem_fun (*this, &OSC::osc_input_handler), _osc_server));
253                 src->attach (_main_loop->get_context());
254                 remote_server = src->gobj();
255                 g_source_ref (remote_server);
256         }
257
258         PBD::notify_event_loops_about_thread_creation (pthread_self(), event_loop_name(), 2048);
259         SessionEvent::create_per_thread_pool (event_loop_name(), 128);
260 }
261
262 int
263 OSC::stop ()
264 {
265         /* stop main loop */
266
267         if (local_server) {
268                 g_source_destroy (local_server);
269                 g_source_unref (local_server);
270                 local_server = 0;
271         }
272
273         if (remote_server) {
274                 g_source_destroy (remote_server);
275                 g_source_unref (remote_server);
276                 remote_server = 0;
277         }
278
279         BaseUI::quit ();
280
281         if (_osc_server) {
282                 lo_server_free (_osc_server);
283                 _osc_server = 0;
284         }
285
286         if (_osc_unix_server) {
287                 lo_server_free (_osc_unix_server);
288                 _osc_unix_server = 0;
289         }
290
291         if (!_osc_unix_socket_path.empty()) {
292                 ::g_unlink (_osc_unix_socket_path.c_str());
293         }
294
295         if (!_osc_url_file.empty() ) {
296                 ::g_unlink (_osc_url_file.c_str() );
297         }
298
299         // Delete any active route observers
300         for (RouteObservers::iterator x = route_observers.begin(); x != route_observers.end();) {
301
302                 OSCRouteObserver* rc;
303
304                 if ((rc = dynamic_cast<OSCRouteObserver*>(*x)) != 0) {
305                         delete *x;
306                         x = route_observers.erase (x);
307                 } else {
308                         ++x;
309                 }
310         }
311
312         return 0;
313 }
314
315 void
316 OSC::register_callbacks()
317 {
318         lo_server srvs[2];
319         lo_server serv;
320
321         srvs[0] = _osc_server;
322         srvs[1] = _osc_unix_server;
323
324         for (size_t i = 0; i < 2; ++i) {
325
326                 if (!srvs[i]) {
327                         continue;
328                 }
329
330                 serv = srvs[i];
331
332                 /* this is a special catchall handler */
333
334                 lo_server_add_method (serv, 0, 0, _catchall, this);
335
336 #define REGISTER_CALLBACK(serv,path,types, function) lo_server_add_method (serv, path, types, OSC::_ ## function, this)
337
338                 REGISTER_CALLBACK (serv, "/routes/list", "", routes_list);
339                 REGISTER_CALLBACK (serv, "/ardour/add_marker", "", add_marker);
340                 REGISTER_CALLBACK (serv, "/ardour/access_action", "s", access_action);
341                 REGISTER_CALLBACK (serv, "/ardour/loop_toggle", "", loop_toggle);
342                 REGISTER_CALLBACK (serv, "/ardour/loop_location", "ii", loop_location);
343                 REGISTER_CALLBACK (serv, "/ardour/goto_start", "", goto_start);
344                 REGISTER_CALLBACK (serv, "/ardour/goto_end", "", goto_end);
345                 REGISTER_CALLBACK (serv, "/ardour/rewind", "", rewind);
346                 REGISTER_CALLBACK (serv, "/ardour/ffwd", "", ffwd);
347                 REGISTER_CALLBACK (serv, "/ardour/transport_stop", "", transport_stop);
348                 REGISTER_CALLBACK (serv, "/ardour/transport_play", "", transport_play);
349                 REGISTER_CALLBACK (serv, "/ardour/transport_frame", "", transport_frame);
350                 REGISTER_CALLBACK (serv, "/ardour/transport_speed", "", transport_speed);
351                 REGISTER_CALLBACK (serv, "/ardour/record_enabled", "", record_enabled);
352                 REGISTER_CALLBACK (serv, "/ardour/set_transport_speed", "f", set_transport_speed);
353                 REGISTER_CALLBACK (serv, "/ardour/locate", "ii", locate);
354                 REGISTER_CALLBACK (serv, "/ardour/save_state", "", save_state);
355                 REGISTER_CALLBACK (serv, "/ardour/prev_marker", "", prev_marker);
356                 REGISTER_CALLBACK (serv, "/ardour/next_marker", "", next_marker);
357                 REGISTER_CALLBACK (serv, "/ardour/undo", "", undo);
358                 REGISTER_CALLBACK (serv, "/ardour/redo", "", redo);
359                 REGISTER_CALLBACK (serv, "/ardour/toggle_punch_in", "", toggle_punch_in);
360                 REGISTER_CALLBACK (serv, "/ardour/toggle_punch_out", "", toggle_punch_out);
361                 REGISTER_CALLBACK (serv, "/ardour/rec_enable_toggle", "", rec_enable_toggle);
362                 REGISTER_CALLBACK (serv, "/ardour/toggle_all_rec_enables", "", toggle_all_rec_enables);
363
364                 /*
365                  * NOTE:  these messages are provided for (arguably broken) apps
366                  *   that MUST send float args ( TouchOSC and Lemur ).
367                  * Normally these ardour transport messages don't require an argument,
368                  * so we're providing redundant calls with vestigial "float" args.
369                  *
370                  * Is it really useful to ignore the parameter?
371                  *  http://hexler.net/docs/touchosc-controls-reference suggests that
372                  *  push buttons do send 0,1. We will have to provide semantic equivalents
373                  *  rather than simply ignore the parameter.
374                  *  e.g  push & release the button will send
375                  *    .../undo f 1
376                  *    .../undo f 0
377                  *  resulting in two undos.
378                  */
379                 REGISTER_CALLBACK (serv, "/ardour/unused_argument/loop_toggle", "f", loop_toggle);
380                 REGISTER_CALLBACK (serv, "/ardour/unused_argument/add_marker", "f", add_marker);
381                 REGISTER_CALLBACK (serv, "/ardour/unused_argument/goto_start", "f", goto_start);
382                 REGISTER_CALLBACK (serv, "/ardour/unused_argument/goto_end", "f", goto_end);
383                 REGISTER_CALLBACK (serv, "/ardour/unused_argument/rewind", "f", rewind);
384                 REGISTER_CALLBACK (serv, "/ardour/unused_argument/ffwd", "f", ffwd);
385                 REGISTER_CALLBACK (serv, "/ardour/unused_argument/transport_stop", "f", transport_stop);
386                 REGISTER_CALLBACK (serv, "/ardour/unused_argument/transport_play", "f", transport_play);
387                 REGISTER_CALLBACK (serv, "/ardour/unused_argument/save_state", "f", save_state);
388                 REGISTER_CALLBACK (serv, "/ardour/unused_argument/prev_marker", "f", prev_marker);
389                 REGISTER_CALLBACK (serv, "/ardour/unused_argument/next_marker", "f", next_marker);
390                 REGISTER_CALLBACK (serv, "/ardour/unused_argument/undo", "f", undo);
391                 REGISTER_CALLBACK (serv, "/ardour/unused_argument/redo", "f", redo);
392                 REGISTER_CALLBACK (serv, "/ardour/unused_argument/toggle_punch_in", "f", toggle_punch_in);
393                 REGISTER_CALLBACK (serv, "/ardour/unused_argument/toggle_punch_out", "f", toggle_punch_out);
394                 REGISTER_CALLBACK (serv, "/ardour/unused_argument/rec_enable_toggle", "f", rec_enable_toggle);
395                 REGISTER_CALLBACK (serv, "/ardour/unused_argument/toggle_all_rec_enables", "f", toggle_all_rec_enables);
396
397                 REGISTER_CALLBACK (serv, "/ardour/routes/mute", "ii", route_mute);
398                 REGISTER_CALLBACK (serv, "/ardour/routes/solo", "ii", route_solo);
399                 REGISTER_CALLBACK (serv, "/ardour/routes/recenable", "ii", route_recenable);
400                 REGISTER_CALLBACK (serv, "/ardour/routes/gainabs", "if", route_set_gain_abs);
401                 REGISTER_CALLBACK (serv, "/ardour/routes/gaindB", "if", route_set_gain_dB);
402                 REGISTER_CALLBACK (serv, "/ardour/routes/trimabs", "if", route_set_trim_abs);
403                 REGISTER_CALLBACK (serv, "/ardour/routes/trimdB", "if", route_set_trim_dB);
404                 REGISTER_CALLBACK (serv, "/ardour/routes/pan_stereo_position", "if", route_set_pan_stereo_position);
405                 REGISTER_CALLBACK (serv, "/ardour/routes/pan_stereo_width", "if", route_set_pan_stereo_width);
406                 REGISTER_CALLBACK (serv, "/ardour/routes/plugin/parameter", "iiif", route_plugin_parameter);
407                 REGISTER_CALLBACK (serv, "/ardour/routes/plugin/parameter/print", "iii", route_plugin_parameter_print);
408                 REGISTER_CALLBACK (serv, "/ardour/routes/send/gainabs", "iif", route_set_send_gain_abs);
409                 REGISTER_CALLBACK (serv, "/ardour/routes/send/gaindB", "iif", route_set_send_gain_dB);
410
411                 /* still not-really-standardized query interface */
412                 //REGISTER_CALLBACK (serv, "/ardour/*/#current_value", "", current_value);
413                 //REGISTER_CALLBACK (serv, "/ardour/set", "", set);
414
415                 // un/register_update args= s:ctrl s:returl s:retpath
416                 //lo_server_add_method(serv, "/register_update", "sss", OSC::global_register_update_handler, this);
417                 //lo_server_add_method(serv, "/unregister_update", "sss", OSC::global_unregister_update_handler, this);
418                 //lo_server_add_method(serv, "/register_auto_update", "siss", OSC::global_register_auto_update_handler, this);
419                 //lo_server_add_method(serv, "/unregister_auto_update", "sss", OSC::_global_unregister_auto_update_handler, this);
420
421         }
422 }
423
424 bool
425 OSC::osc_input_handler (IOCondition ioc, lo_server srv)
426 {
427         if (ioc & ~IO_IN) {
428                 return false;
429         }
430
431         if (ioc & IO_IN) {
432                 lo_server_recv (srv);
433         }
434
435         return true;
436 }
437
438 std::string
439 OSC::get_server_url()
440 {
441         string url;
442         char * urlstr;
443
444         if (_osc_server) {
445                 urlstr = lo_server_get_url (_osc_server);
446                 url = urlstr;
447                 free (urlstr);
448         }
449
450         return url;
451 }
452
453 std::string
454 OSC::get_unix_server_url()
455 {
456         string url;
457         char * urlstr;
458
459         if (_osc_unix_server) {
460                 urlstr = lo_server_get_url (_osc_unix_server);
461                 url = urlstr;
462                 free (urlstr);
463         }
464
465         return url;
466 }
467
468 void
469 OSC::listen_to_route (boost::shared_ptr<Route> route, lo_address addr)
470 {
471         /* avoid duplicate listens */
472
473         for (RouteObservers::iterator x = route_observers.begin(); x != route_observers.end(); ++x) {
474
475                 OSCRouteObserver* ro;
476
477                 if ((ro = dynamic_cast<OSCRouteObserver*>(*x)) != 0) {
478
479                         int res = strcmp(lo_address_get_hostname(ro->address()), lo_address_get_hostname(addr));
480
481                         if (ro->route() == route && res == 0) {
482                                 return;
483                         }
484                 }
485         }
486
487         OSCRouteObserver* o = new OSCRouteObserver (route, addr);
488         route_observers.push_back (o);
489
490         route->DropReferences.connect (*this, MISSING_INVALIDATOR, boost::bind (&OSC::drop_route, this, boost::weak_ptr<Route> (route)), this);
491 }
492
493 void
494 OSC::drop_route (boost::weak_ptr<Route> wr)
495 {
496         boost::shared_ptr<Route> r = wr.lock ();
497
498         if (!r) {
499                 return;
500         }
501
502         for (RouteObservers::iterator x = route_observers.begin(); x != route_observers.end();) {
503
504                 OSCRouteObserver* rc;
505
506                 if ((rc = dynamic_cast<OSCRouteObserver*>(*x)) != 0) {
507
508                         if (rc->route() == r) {
509                                 delete *x;
510                                 x = route_observers.erase (x);
511                         } else {
512                                 ++x;
513                         }
514                 } else {
515                         ++x;
516                 }
517         }
518 }
519
520 void
521 OSC::end_listen (boost::shared_ptr<Route> r, lo_address addr)
522 {
523         RouteObservers::iterator x;
524
525         // Remove the route observers
526         for (x = route_observers.begin(); x != route_observers.end();) {
527
528                 OSCRouteObserver* ro;
529
530                 if ((ro = dynamic_cast<OSCRouteObserver*>(*x)) != 0) {
531
532                         int res = strcmp(lo_address_get_hostname(ro->address()), lo_address_get_hostname(addr));
533
534                         if (ro->route() == r && res == 0) {
535                                 delete *x;
536                                 x = route_observers.erase (x);
537                         }
538                         else {
539                                 ++x;
540                         }
541                 }
542                 else {
543                         ++x;
544                 }
545         }
546 }
547
548 void
549 OSC::current_value_query (const char* path, size_t len, lo_arg **argv, int argc, lo_message msg)
550 {
551         char* subpath;
552
553         subpath = (char*) malloc (len-15+1);
554         memcpy (subpath, path, len-15);
555         subpath[len-15] = '\0';
556
557         send_current_value (subpath, argv, argc, msg);
558
559         free (subpath);
560 }
561
562 void
563 OSC::send_current_value (const char* path, lo_arg** argv, int argc, lo_message msg)
564 {
565         if (!session) {
566                 return;
567         }
568
569         lo_message reply = lo_message_new ();
570         boost::shared_ptr<Route> r;
571         int id;
572
573         lo_message_add_string (reply, path);
574
575         if (argc == 0) {
576                 lo_message_add_string (reply, "bad syntax");
577         } else {
578                 id = argv[0]->i;
579                 r = session->route_by_remote_id (id);
580
581                 if (!r) {
582                         lo_message_add_string (reply, "not found");
583                 } else {
584
585                         if (strcmp (path, "/routes/state") == 0) {
586
587                                 if (boost::dynamic_pointer_cast<AudioTrack>(r)) {
588                                         lo_message_add_string (reply, "AT");
589                                 } else if (boost::dynamic_pointer_cast<MidiTrack>(r)) {
590                                         lo_message_add_string (reply, "MT");
591                                 } else {
592                                         lo_message_add_string (reply, "B");
593                                 }
594
595                                 lo_message_add_string (reply, r->name().c_str());
596                                 lo_message_add_int32 (reply, r->n_inputs().n_audio());
597                                 lo_message_add_int32 (reply, r->n_outputs().n_audio());
598                                 lo_message_add_int32 (reply, r->muted());
599                                 lo_message_add_int32 (reply, r->soloed());
600
601                         } else if (strcmp (path, "/routes/mute") == 0) {
602
603                                 lo_message_add_int32 (reply, (float) r->muted());
604
605                         } else if (strcmp (path, "/routes/solo") == 0) {
606
607                                 lo_message_add_int32 (reply, r->soloed());
608                         }
609                 }
610         }
611
612         lo_send_message (lo_message_get_source (msg), "#reply", reply);
613         lo_message_free (reply);
614 }
615
616 int
617 OSC::_catchall (const char *path, const char *types, lo_arg **argv, int argc, void *data, void *user_data)
618 {
619         return ((OSC*)user_data)->catchall (path, types, argv, argc, data);
620 }
621
622 int
623 OSC::catchall (const char *path, const char* /*types*/, lo_arg **argv, int argc, lo_message msg)
624 {
625         size_t len;
626         int ret = 1; /* unhandled */
627
628         //cerr << "Received a message, path = " << path << " types = \""
629         //     << (types ? types : "NULL") << '"' << endl;
630
631         /* 15 for /#current_value plus 2 for /<path> */
632
633         len = strlen (path);
634
635         if (len >= 17 && !strcmp (&path[len-15], "/#current_value")) {
636                 current_value_query (path, len, argv, argc, msg);
637                 ret = 0;
638
639         } else if (strcmp (path, "/routes/listen") == 0) {
640
641                 cerr << "set up listener\n";
642
643                 lo_message reply = lo_message_new ();
644
645                 if (argc <= 0) {
646                         lo_message_add_string (reply, "syntax error");
647                 } else {
648                         for (int n = 0; n < argc; ++n) {
649
650                                 boost::shared_ptr<Route> r = session->route_by_remote_id (argv[n]->i);
651
652                                 if (!r) {
653                                         lo_message_add_string (reply, "not found");
654                                         cerr << "no such route\n";
655                                         break;
656                                 } else {
657                                         cerr << "add listener\n";
658                                         listen_to_route (r, lo_message_get_source (msg));
659                                         lo_message_add_int32 (reply, argv[n]->i);
660                                 }
661                         }
662                 }
663
664                 lo_send_message (lo_message_get_source (msg), "#reply", reply);
665                 lo_message_free (reply);
666
667                 ret = 0;
668
669         } else if (strcmp (path, "/routes/ignore") == 0) {
670
671                 for (int n = 0; n < argc; ++n) {
672
673                         boost::shared_ptr<Route> r = session->route_by_remote_id (argv[n]->i);
674
675                         if (r) {
676                                 end_listen (r, lo_message_get_source (msg));
677                         }
678                 }
679
680                 ret = 0;
681         }
682
683         return ret;
684 }
685
686 void
687 OSC::update_clock ()
688 {
689
690 }
691
692 // "Application Hook" Handlers //
693 void
694 OSC::session_loaded (Session& s)
695 {
696         lo_address listener = lo_address_new (NULL, "7770");
697         lo_send (listener, "/session/loaded", "ss", s.path().c_str(), s.name().c_str());
698 }
699
700 void
701 OSC::session_exported (std::string path, std::string name)
702 {
703         lo_address listener = lo_address_new (NULL, "7770");
704         lo_send (listener, "/session/exported", "ss", path.c_str(), name.c_str());
705 }
706
707 // end "Application Hook" Handlers //
708
709 /* path callbacks */
710
711 int
712 OSC::current_value (const char */*path*/, const char */*types*/, lo_arg **/*argv*/, int /*argc*/, void */*data*/, void* /*user_data*/)
713 {
714 #if 0
715         const char* returl;
716
717         if (argc < 3 || types == 0 || strlen (types) < 3 || types[0] != 's' || types[1] != 's' || types[2] != s) {
718                 return 1;
719         }
720
721         const char *returl = argv[1]->s;
722         lo_address addr = find_or_cache_addr (returl);
723
724         const char *retpath = argv[2]->s;
725
726
727         if (strcmp (argv[0]->s, "transport_frame") == 0) {
728
729                 if (session) {
730                         lo_send (addr, retpath, "i", session->transport_frame());
731                 }
732
733         } else if (strcmp (argv[0]->s, "transport_speed") == 0) {
734
735                 if (session) {
736                         lo_send (addr, retpath, "i", session->transport_frame());
737                 }
738
739         } else if (strcmp (argv[0]->s, "transport_locked") == 0) {
740
741                 if (session) {
742                         lo_send (addr, retpath, "i", session->transport_frame());
743                 }
744
745         } else if (strcmp (argv[0]->s, "punch_in") == 0) {
746
747                 if (session) {
748                         lo_send (addr, retpath, "i", session->transport_frame());
749                 }
750
751         } else if (strcmp (argv[0]->s, "punch_out") == 0) {
752
753                 if (session) {
754                         lo_send (addr, retpath, "i", session->transport_frame());
755                 }
756
757         } else if (strcmp (argv[0]->s, "rec_enable") == 0) {
758
759                 if (session) {
760                         lo_send (addr, retpath, "i", session->transport_frame());
761                 }
762
763         } else {
764
765                 /* error */
766         }
767 #endif
768         return 0;
769 }
770
771 void
772 OSC::routes_list (lo_message msg)
773 {
774         if (!session) {
775                 return;
776         }
777         for (int n = 0; n < (int) session->nroutes(); ++n) {
778
779                 boost::shared_ptr<Route> r = session->route_by_remote_id (n);
780
781                 if (r) {
782
783                         lo_message reply = lo_message_new ();
784
785                         if (boost::dynamic_pointer_cast<AudioTrack>(r)) {
786                                 lo_message_add_string (reply, "AT");
787                         } else if (boost::dynamic_pointer_cast<MidiTrack>(r)) {
788                                 lo_message_add_string (reply, "MT");
789                         } else {
790                                 lo_message_add_string (reply, "B");
791                         }
792
793                         lo_message_add_string (reply, r->name().c_str());
794                         lo_message_add_int32 (reply, r->n_inputs().n_audio());
795                         lo_message_add_int32 (reply, r->n_outputs().n_audio());
796                         lo_message_add_int32 (reply, r->muted());
797                         lo_message_add_int32 (reply, r->soloed());
798                         lo_message_add_int32 (reply, r->remote_control_id());
799
800                         if (boost::dynamic_pointer_cast<AudioTrack>(r)
801                                         || boost::dynamic_pointer_cast<MidiTrack>(r)) {
802
803                                 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(r);
804                                 lo_message_add_int32 (reply, t->record_enabled());
805                         }
806
807                         //Automatically listen to routes listed
808                         listen_to_route(r, lo_message_get_source (msg));
809
810                         lo_send_message (lo_message_get_source (msg), "#reply", reply);
811                         lo_message_free (reply);
812                 }
813         }
814
815         // Send end of listing message
816         lo_message reply = lo_message_new ();
817
818         lo_message_add_string (reply, "end_route_list");
819         lo_message_add_int64 (reply, session->frame_rate());
820         lo_message_add_int64 (reply, session->current_end_frame());
821
822         lo_send_message (lo_message_get_source (msg), "#reply", reply);
823
824         lo_message_free (reply);
825 }
826
827 void
828 OSC::transport_frame (lo_message msg)
829 {
830         if (!session) {
831                 return;
832         }
833         framepos_t pos = session->transport_frame ();
834
835         lo_message reply = lo_message_new ();
836         lo_message_add_int64 (reply, pos);
837
838         lo_send_message (lo_message_get_source (msg), "/ardour/transport_frame", reply);
839
840         lo_message_free (reply);
841 }
842
843 void
844 OSC::transport_speed (lo_message msg)
845 {
846         if (!session) {
847                 return;
848         }
849         double ts = session->transport_speed ();
850
851         lo_message reply = lo_message_new ();
852         lo_message_add_double (reply, ts);
853
854         lo_send_message (lo_message_get_source (msg), "/ardour/transport_speed", reply);
855
856         lo_message_free (reply);
857 }
858
859 void
860 OSC::record_enabled (lo_message msg)
861 {
862         if (!session) {
863                 return;
864         }
865         int re = (int)session->get_record_enabled ();
866
867         lo_message reply = lo_message_new ();
868         lo_message_add_int32 (reply, re);
869
870         lo_send_message (lo_message_get_source (msg), "/ardour/record_enabled", reply);
871
872         lo_message_free (reply);
873 }
874
875
876 int
877 OSC::route_mute (int rid, int yn)
878 {
879         if (!session) return -1;
880
881         boost::shared_ptr<Route> r = session->route_by_remote_id (rid);
882
883         if (r) {
884                 r->set_mute (yn, this);
885         }
886
887         return 0;
888 }
889
890 int
891 OSC::route_solo (int rid, int yn)
892 {
893         if (!session) return -1;
894
895         boost::shared_ptr<Route> r = session->route_by_remote_id (rid);
896
897         if (r) {
898                 boost::shared_ptr<RouteList> rl (new RouteList);
899                 rl->push_back (r);
900                 session->set_solo (rl, yn);
901         }
902
903         return 0;
904 }
905
906 int
907 OSC::route_recenable (int rid, int yn)
908 {
909         if (!session) return -1;
910
911         boost::shared_ptr<Route> r = session->route_by_remote_id (rid);
912
913         if (r) {
914                 r->set_record_enabled (yn, this);
915         }
916
917         return 0;
918 }
919
920 int
921 OSC::route_set_gain_abs (int rid, float level)
922 {
923         if (!session) return -1;
924
925         boost::shared_ptr<Route> r = session->route_by_remote_id (rid);
926
927         if (r) {
928                 r->set_gain (level, this);
929         }
930
931         return 0;
932 }
933
934 int
935 OSC::route_set_gain_dB (int rid, float dB)
936 {
937         return route_set_gain_abs (rid, dB_to_coefficient (dB));
938 }
939
940
941 int
942 OSC::route_set_trim_abs (int rid, float level)
943 {
944         if (!session) return -1;
945
946         boost::shared_ptr<Route> r = session->route_by_remote_id (rid);
947
948         if (r) {
949                 r->set_trim (level, this);
950         }
951
952         return 0;
953 }
954
955 int
956 OSC::route_set_trim_dB (int rid, float dB)
957 {
958         return route_set_trim_abs(rid, dB_to_coefficient (dB));
959 }
960
961
962 int
963 OSC::route_set_pan_stereo_position (int rid, float pos)
964 {
965         if (!session) return -1;
966
967         boost::shared_ptr<Route> r = session->route_by_remote_id (rid);
968
969         if (r) {
970                 boost::shared_ptr<Panner> panner = r->panner();
971                 if (panner) {
972                         panner->set_position (pos);
973                 }
974         }
975
976         return 0;
977
978 }
979
980 int
981 OSC::route_set_pan_stereo_width (int rid, float pos)
982 {
983         if (!session) return -1;
984
985         boost::shared_ptr<Route> r = session->route_by_remote_id (rid);
986
987         if (r) {
988                 boost::shared_ptr<Panner> panner = r->panner();
989                 if (panner) {
990                         panner->set_width (pos);
991                 }
992         }
993
994         return 0;
995
996 }
997
998 int
999 OSC::route_set_send_gain_abs (int rid, int sid, float val)
1000 {
1001         if (!session) {
1002                 return -1;
1003         }
1004
1005         boost::shared_ptr<Route> r = session->route_by_remote_id (rid);
1006
1007         if (!r) {
1008                 return -1;
1009         }
1010
1011         /* revert to zero-based counting */
1012
1013         if (sid > 0) {
1014                 --sid;
1015         }
1016
1017         boost::shared_ptr<Processor> p = r->nth_send (sid);
1018
1019         if (p) {
1020                 boost::shared_ptr<Send> s = boost::dynamic_pointer_cast<Send>(p);
1021                 boost::shared_ptr<Amp> a = s->amp();
1022
1023                 if (a) {
1024                         a->set_gain (val, this);
1025                 }
1026         }
1027         return 0;
1028 }
1029
1030 int
1031 OSC::route_set_send_gain_dB (int rid, int sid, float val)
1032 {
1033         if (!session) {
1034                 return -1;
1035         }
1036
1037         boost::shared_ptr<Route> r = session->route_by_remote_id (rid);
1038
1039         if (!r) {
1040                 return -1;
1041         }
1042
1043         /* revert to zero-based counting */
1044
1045         if (sid > 0) {
1046                 --sid;
1047         }
1048
1049         boost::shared_ptr<Processor> p = r->nth_send (sid);
1050
1051         if (p) {
1052                 boost::shared_ptr<Send> s = boost::dynamic_pointer_cast<Send>(p);
1053                 boost::shared_ptr<Amp> a = s->amp();
1054
1055                 if (a) {
1056                         a->set_gain (dB_to_coefficient (val), this);
1057                 }
1058         }
1059         return 0;
1060 }
1061
1062 int
1063 OSC::route_plugin_parameter (int rid, int piid, int par, float val)
1064 {
1065         if (!session)
1066                 return -1;
1067
1068         boost::shared_ptr<Route> r = session->route_by_remote_id (rid);
1069
1070         if (!r) {
1071                 PBD::error << "OSC: Invalid Remote Control ID '" << rid << "'" << endmsg;
1072                 return -1;
1073         }
1074
1075         boost::shared_ptr<Processor> redi=r->nth_plugin (piid);
1076
1077         if (!redi) {
1078                 PBD::error << "OSC: cannot find plugin # " << piid << " for RID '" << rid << "'" << endmsg;
1079                 return -1;
1080         }
1081
1082         boost::shared_ptr<PluginInsert> pi;
1083
1084         if (!(pi = boost::dynamic_pointer_cast<PluginInsert>(redi))) {
1085                 PBD::error << "OSC: given processor # " << piid << " on RID '" << rid << "' is not a Plugin." << endmsg;
1086                 return -1;
1087         }
1088
1089         boost::shared_ptr<ARDOUR::Plugin> pip = pi->plugin();
1090         bool ok=false;
1091
1092         uint32_t controlid = pip->nth_parameter (par,ok);
1093
1094         if (!ok) {
1095                 PBD::error << "OSC: Cannot find parameter # " << par <<  " for plugin # " << piid << " on RID '" << rid << "'" << endmsg;
1096                 return -1;
1097         }
1098
1099         if (!pip->parameter_is_input(controlid)) {
1100                 PBD::error << "OSC: Parameter # " << par <<  " for plugin # " << piid << " on RID '" << rid << "' is not a control input" << endmsg;
1101                 return -1;
1102         }
1103
1104         ParameterDescriptor pd;
1105         pi->plugin()->get_parameter_descriptor (controlid,pd);
1106
1107         if (val >= pd.lower && val < pd.upper) {
1108
1109                 boost::shared_ptr<AutomationControl> c = pi->automation_control (Evoral::Parameter(PluginAutomation, 0, controlid));
1110                 // cerr << "parameter:" << redi->describe_parameter(controlid) << " val:" << val << "\n";
1111                 c->set_value (val, PBD::Controllable::NoGroup);
1112         } else {
1113                 PBD::warning << "OSC: Parameter # " << par <<  " for plugin # " << piid << " on RID '" << rid << "' is out of range" << endmsg;
1114                 PBD::info << "OSC: Valid range min=" << pd.lower << " max=" << pd.upper << endmsg;
1115         }
1116
1117         return 0;
1118 }
1119
1120 int
1121 OSC::route_plugin_parameter_print (int rid, int piid, int par)
1122 {
1123         if (!session) {
1124                 return -1;
1125         }
1126
1127         boost::shared_ptr<Route> r = session->route_by_remote_id (rid);
1128
1129         if (!r) {
1130                 return -1;
1131         }
1132
1133         boost::shared_ptr<Processor> redi=r->nth_processor (piid);
1134
1135         if (!redi) {
1136                 return -1;
1137         }
1138
1139         boost::shared_ptr<PluginInsert> pi;
1140
1141         if (!(pi = boost::dynamic_pointer_cast<PluginInsert>(redi))) {
1142                 return -1;
1143         }
1144
1145         boost::shared_ptr<ARDOUR::Plugin> pip = pi->plugin();
1146         bool ok=false;
1147
1148         uint32_t controlid = pip->nth_parameter (par,ok);
1149
1150         if (!ok) {
1151                 return -1;
1152         }
1153
1154         ParameterDescriptor pd;
1155
1156         if (pi->plugin()->get_parameter_descriptor (controlid, pd) == 0) {
1157                 boost::shared_ptr<AutomationControl> c = pi->automation_control (Evoral::Parameter(PluginAutomation, 0, controlid));
1158
1159                 cerr << "parameter:     " << redi->describe_parameter(controlid)  << "\n";
1160                 cerr << "current value: " << c->get_value ();
1161                 cerr << "lower value:   " << pd.lower << "\n";
1162                 cerr << "upper value:   " << pd.upper << "\n";
1163         }
1164
1165         return 0;
1166 }
1167
1168 XMLNode&
1169 OSC::get_state ()
1170 {
1171         return ControlProtocol::get_state();
1172 }
1173
1174 int
1175 OSC::set_state (const XMLNode& node, int version)
1176 {
1177         if (ControlProtocol::set_state (node, version)) {
1178                 return -1;
1179         }
1180
1181         return 0;
1182 }