1 /*
2  * Copyright (C) 2009-2012 Carl Hetherington <carl@carlh.net>
3  * Copyright (C) 2009-2014 David Robillard <d@drobilla.net>
4  * Copyright (C) 2009-2017 Paul Davis <paul@linuxaudiosystems.com>
5  * Copyright (C) 2012-2016 Tim Mayberry <mojofunk@gmail.com>
6  * Copyright (C) 2013-2019 Robin Gareus <robin@gareus.org>
7  * Copyright (C) 2015-2016 Ben Loftis <ben@harrisonconsoles.com>
8  * Copyright (C) 2015-2018 John Emmas <john@creativepost.co.uk>
9  * Copyright (C) 2015 Johannes Mueller <github@johannes-mueller.org>
10  * Copyright (C) 2016-2018 Len Ovens <len@ovenwerks.net>
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License along
23  * with this program; if not, write to the Free Software Foundation, Inc.,
24  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25  */
26 
27 #include <cstdio>
28 #include <cstdlib>
29 #include <cerrno>
30 #include <algorithm>
31 
32 #include <unistd.h>
33 #include <fcntl.h>
34 
35 #include "pbd/gstdio_compat.h"
36 #include <glibmm.h>
37 
38 #include "pbd/control_math.h"
39 #include "pbd/controllable.h"
40 #include <pbd/convert.h>
41 #include <pbd/pthread_utils.h>
42 #include <pbd/file_utils.h>
43 #include <pbd/failed_constructor.h>
44 
45 #include "ardour/amp.h"
46 #include "ardour/session.h"
47 #include "ardour/route.h"
48 #include "ardour/route_group.h"
49 #include "ardour/audio_track.h"
50 #include "ardour/midi_track.h"
51 #include "ardour/vca.h"
52 #include "ardour/monitor_control.h"
53 #include "ardour/dB.h"
54 #include "ardour/filesystem_paths.h"
55 #include "ardour/panner.h"
56 #include "ardour/panner_shell.h"
57 #include "ardour/pannable.h"
58 #include "ardour/plugin.h"
59 #include "ardour/plugin_insert.h"
60 #include "ardour/presentation_info.h"
61 #include "ardour/profile.h"
62 #include "ardour/send.h"
63 #include "ardour/internal_send.h"
64 #include "ardour/phase_control.h"
65 #include "ardour/solo_isolate_control.h"
66 #include "ardour/solo_safe_control.h"
67 #include "ardour/vca_manager.h"
68 
69 #include "osc_select_observer.h"
70 #include "osc.h"
71 #include "osc_controllable.h"
72 #include "osc_route_observer.h"
73 #include "osc_global_observer.h"
74 #include "osc_cue_observer.h"
75 #include "pbd/i18n.h"
76 
77 using namespace ARDOUR;
78 using namespace std;
79 using namespace Glib;
80 using namespace ArdourSurface;
81 
82 #include "pbd/abstract_ui.cc" // instantiate template
83 
84 OSC* OSC::_instance = 0;
85 
86 #ifdef DEBUG
error_callback(int num,const char * m,const char * path)87 static void error_callback(int num, const char *m, const char *path)
88 {
89 	fprintf(stderr, "liblo server error %d in path %s: %s\n", num, path, m);
90 }
91 #else
error_callback(int,const char *,const char *)92 static void error_callback(int, const char *, const char *)
93 {
94 
95 }
96 #endif
97 
OSC(Session & s,uint32_t port)98 OSC::OSC (Session& s, uint32_t port)
99 	: ControlProtocol (s, X_("Open Sound Control (OSC)"))
100 	, AbstractUI<OSCUIRequest> (name())
101 	, local_server (0)
102 	, remote_server (0)
103 	, _port(port)
104 	, _ok (true)
105 	, _shutdown (false)
106 	, _osc_server (0)
107 	, _osc_unix_server (0)
108 	, _debugmode (Off)
109 	, address_only (true)
110 	, remote_port ("8000")
111 	, default_banksize (0)
112 	, default_strip (31)
113 	, default_feedback (0)
114 	, default_gainmode (0)
115 	, default_send_size (0)
116 	, default_plugin_size (0)
117 	, tick (true)
118 	, bank_dirty (false)
119 	, observer_busy (true)
120 	, scrub_speed (0)
121 	, gui (0)
122 {
123 	_instance = this;
124 
125 	session->Exported.connect (*this, MISSING_INVALIDATOR, boost::bind (&OSC::session_exported, this, _1, _2), this);
126 }
127 
~OSC()128 OSC::~OSC()
129 {
130 	tick = false;
131 	stop ();
132 	tear_down_gui ();
133 	_instance = 0;
134 }
135 
136 void*
request_factory(uint32_t num_requests)137 OSC::request_factory (uint32_t num_requests)
138 {
139 	/* AbstractUI<T>::request_buffer_factory() is a template method only
140 	   instantiated in this source module. To provide something visible for
141 	   use in the interface/descriptor, we have this static method that is
142 	   template-free.
143 	*/
144 	return request_buffer_factory (num_requests);
145 }
146 
147 void
do_request(OSCUIRequest * req)148 OSC::do_request (OSCUIRequest* req)
149 {
150 	if (req->type == CallSlot) {
151 
152 		call_slot (MISSING_INVALIDATOR, req->the_slot);
153 
154 	} else if (req->type == Quit) {
155 
156 		stop ();
157 	}
158 }
159 
160 int
set_active(bool yn)161 OSC::set_active (bool yn)
162 {
163 	if (yn != active()) {
164 
165 		if (yn) {
166 			if (start ()) {
167 				return -1;
168 			}
169 		} else {
170 			if (stop ()) {
171 				return -1;
172 			}
173 		}
174 
175 	}
176 
177 	return ControlProtocol::set_active (yn);
178 }
179 
180 bool
get_active() const181 OSC::get_active () const
182 {
183 	return _osc_server != 0;
184 }
185 
186 int
start()187 OSC::start ()
188 {
189 	char tmpstr[255];
190 
191 	if (_osc_server) {
192 		/* already started */
193 		return 0;
194 	}
195 
196 	for (int j=0; j < 20; ++j) {
197 		snprintf(tmpstr, sizeof(tmpstr), "%d", _port);
198 
199 		//if ((_osc_server = lo_server_new_with_proto (tmpstr, LO_TCP, error_callback))) {
200 		//	break;
201 		//}
202 
203 		if ((_osc_server = lo_server_new (tmpstr, error_callback))) {
204 			break;
205 		}
206 
207 #ifdef DEBUG
208 		cerr << "can't get osc at port: " << _port << endl;
209 #endif
210 		_port++;
211 		continue;
212 	}
213 
214 	if (!_osc_server) {
215 		return 1;
216 	}
217 
218 #ifdef ARDOUR_OSC_UNIX_SERVER
219 
220 	// APPEARS sluggish for now
221 
222 	// attempt to create unix socket server too
223 
224 	snprintf(tmpstr, sizeof(tmpstr), "/tmp/sooperlooper_XXXXXX");
225 	int fd = mkstemp(tmpstr);
226 
227 	if (fd >= 0 ) {
228 		::g_unlink (tmpstr);
229 		close (fd);
230 
231 		_osc_unix_server = lo_server_new (tmpstr, error_callback);
232 
233 		if (_osc_unix_server) {
234 			_osc_unix_socket_path = tmpstr;
235 		}
236 	}
237 #endif
238 
239 	PBD::info << "OSC @ " << get_server_url () << endmsg;
240 
241 	std::string url_file;
242 
243 	if (find_file (ardour_config_search_path(), "osc_url", url_file)) {
244 		_osc_url_file = url_file;
245 		if (g_file_set_contents (_osc_url_file.c_str(), get_server_url().c_str(), -1, NULL)) {
246 			cerr << "Couldn't write '" <<  _osc_url_file << "'" <<endl;
247 		}
248 	}
249 
250 	observer_busy = false;
251 	register_callbacks();
252 
253 	session_loaded (*session);
254 
255 	// lo_server_thread_add_method(_sthread, NULL, NULL, OSC::_dummy_handler, this);
256 
257 	/* startup the event loop thread */
258 
259 	BaseUI::run ();
260 
261 	// start timers for metering, timecode and heartbeat.
262 	// timecode and metering run at 100
263 	Glib::RefPtr<Glib::TimeoutSource> periodic_timeout = Glib::TimeoutSource::create (100); // milliseconds
264 	periodic_connection = periodic_timeout->connect (sigc::mem_fun (*this, &OSC::periodic));
265 	periodic_timeout->attach (main_loop()->get_context());
266 
267 	// catch track reordering
268 	// receive routes added
269 	session->RouteAdded.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&OSC::notify_routes_added, this, _1), this);
270 	// receive VCAs added
271 	session->vca_manager().VCAAdded.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&OSC::notify_vca_added, this, _1), this);
272 	// order changed
273 	PresentationInfo::Change.connect (session_connections, MISSING_INVALIDATOR, boost::bind (&OSC::recalcbanks, this), this);
274 
275 	_select = ControlProtocol::first_selected_stripable();
276 	if(!_select) {
277 		_select = session->master_out ();
278 	}
279 
280 	return 0;
281 }
282 
283 void
thread_init()284 OSC::thread_init ()
285 {
286 	pthread_set_name (event_loop_name().c_str());
287 
288 	if (_osc_unix_server) {
289 		Glib::RefPtr<IOSource> src = IOSource::create (lo_server_get_socket_fd (_osc_unix_server), IO_IN|IO_HUP|IO_ERR);
290 		src->connect (sigc::bind (sigc::mem_fun (*this, &OSC::osc_input_handler), _osc_unix_server));
291 		src->attach (_main_loop->get_context());
292 		local_server = src->gobj();
293 		g_source_ref (local_server);
294 	}
295 
296 	if (_osc_server) {
297 #ifdef PLATFORM_WINDOWS
298 		Glib::RefPtr<IOChannel> chan = Glib::IOChannel::create_from_win32_socket (lo_server_get_socket_fd (_osc_server));
299 		Glib::RefPtr<IOSource> src  = IOSource::create (chan, IO_IN|IO_HUP|IO_ERR);
300 #else
301 		Glib::RefPtr<IOSource> src  = IOSource::create (lo_server_get_socket_fd (_osc_server), IO_IN|IO_HUP|IO_ERR);
302 #endif
303 		src->connect (sigc::bind (sigc::mem_fun (*this, &OSC::osc_input_handler), _osc_server));
304 		src->attach (_main_loop->get_context());
305 		remote_server = src->gobj();
306 		g_source_ref (remote_server);
307 	}
308 
309 	PBD::notify_event_loops_about_thread_creation (pthread_self(), event_loop_name(), 2048);
310 	SessionEvent::create_per_thread_pool (event_loop_name(), 128);
311 }
312 
313 int
stop()314 OSC::stop ()
315 {
316 	periodic_connection.disconnect ();
317 	session_connections.drop_connections ();
318 
319 	// clear surfaces
320 	observer_busy = true;
321 	for (uint32_t it = 0; it < _surface.size (); ++it) {
322 		OSCSurface* sur = &_surface[it];
323 		surface_destroy (sur);
324 	}
325 	_surface.clear();
326 
327 	/* stop main loop */
328 	if (local_server) {
329 		g_source_destroy (local_server);
330 		g_source_unref (local_server);
331 		local_server = 0;
332 	}
333 
334 	if (remote_server) {
335 		g_source_destroy (remote_server);
336 		g_source_unref (remote_server);
337 		remote_server = 0;
338 	}
339 
340 	BaseUI::quit ();
341 
342 	if (_osc_server) {
343 		lo_server_free (_osc_server);
344 		_osc_server = 0;
345 	}
346 
347 	if (_osc_unix_server) {
348 		lo_server_free (_osc_unix_server);
349 		_osc_unix_server = 0;
350 	}
351 
352 	if (!_osc_unix_socket_path.empty()) {
353 		::g_unlink (_osc_unix_socket_path.c_str());
354 	}
355 
356 	if (!_osc_url_file.empty() ) {
357 		::g_unlink (_osc_url_file.c_str() );
358 	}
359 
360 	return 0;
361 }
362 
363 void
surface_destroy(OSCSurface * sur)364 OSC::surface_destroy (OSCSurface* sur)
365 {
366 	OSCSelectObserver* so;
367 	if ((so = dynamic_cast<OSCSelectObserver*>(sur->sel_obs)) != 0) {
368 		so->clear_observer ();
369 		delete so;
370 		sur->sel_obs = 0;
371 		PBD::ScopedConnection pc = sur->proc_connection;
372 		pc.disconnect ();
373 	}
374 
375 	OSCCueObserver* co;
376 	if ((co = dynamic_cast<OSCCueObserver*>(sur->cue_obs)) != 0) {
377 		delete co;
378 		sur->cue_obs = 0;
379 		sur->sends.clear ();
380 	}
381 
382 	OSCGlobalObserver* go;
383 	if ((go = dynamic_cast<OSCGlobalObserver*>(sur->global_obs)) != 0) {
384 		go->clear_observer ();
385 		delete go;
386 		sur->global_obs = 0;
387 	}
388 	uint32_t st_end = sur->observers.size ();
389 
390 	for (uint32_t i = 0; i < st_end; i++) {
391 		OSCRouteObserver* ro;
392 		if ((ro = dynamic_cast<OSCRouteObserver*>(sur->observers[i])) != 0) {
393 			ro->clear_strip ();
394 			delete ro;
395 			ro = 0;
396 		}
397 	}
398 	sur->observers.clear();
399 }
400 
401 
402 void
register_callbacks()403 OSC::register_callbacks()
404 {
405 	lo_server srvs[2];
406 	lo_server serv;
407 
408 	srvs[0] = _osc_server;
409 	srvs[1] = _osc_unix_server;
410 
411 	for (size_t i = 0; i < 2; ++i) {
412 
413 		if (!srvs[i]) {
414 			continue;
415 		}
416 
417 		serv = srvs[i];
418 
419 
420 #define REGISTER_CALLBACK(serv,path,types, function) lo_server_add_method (serv, path, types, OSC::_ ## function, this)
421 
422 		// Some controls have optional "f" for feedback or touchosc
423 		// http://hexler.net/docs/touchosc-controls-reference
424 
425 		REGISTER_CALLBACK (serv, X_("/refresh"), "", refresh_surface);
426 		REGISTER_CALLBACK (serv, X_("/refresh"), "f", refresh_surface);
427 		REGISTER_CALLBACK (serv, X_("/group/list"), "", group_list);
428 		REGISTER_CALLBACK (serv, X_("/group/list"), "f", group_list);
429 		REGISTER_CALLBACK (serv, X_("/surface/list"), "", surface_list);
430 		REGISTER_CALLBACK (serv, X_("/surface/list"), "f", surface_list);
431 		REGISTER_CALLBACK (serv, X_("/add_marker"), "", add_marker);
432 		REGISTER_CALLBACK (serv, X_("/add_marker"), "f", add_marker);
433 		REGISTER_CALLBACK (serv, X_("/add_marker"), "s", add_marker_name);
434 		REGISTER_CALLBACK (serv, X_("/access_action"), "s", access_action);
435 		REGISTER_CALLBACK (serv, X_("/loop_toggle"), "", loop_toggle);
436 		REGISTER_CALLBACK (serv, X_("/loop_toggle"), "f", loop_toggle);
437 		REGISTER_CALLBACK (serv, X_("/loop_location"), "ii", loop_location);
438 		REGISTER_CALLBACK (serv, X_("/goto_start"), "", goto_start);
439 		REGISTER_CALLBACK (serv, X_("/goto_start"), "f", goto_start);
440 		REGISTER_CALLBACK (serv, X_("/goto_end"), "", goto_end);
441 		REGISTER_CALLBACK (serv, X_("/goto_end"), "f", goto_end);
442 		REGISTER_CALLBACK (serv, X_("/scrub"), "f", scrub);
443 		REGISTER_CALLBACK (serv, X_("/jog"), "f", jog);
444 		REGISTER_CALLBACK (serv, X_("/jog/mode"), "f", jog_mode);
445 		REGISTER_CALLBACK (serv, X_("/rewind"), "", rewind);
446 		REGISTER_CALLBACK (serv, X_("/rewind"), "f", rewind);
447 		REGISTER_CALLBACK (serv, X_("/ffwd"), "", ffwd);
448 		REGISTER_CALLBACK (serv, X_("/ffwd"), "f", ffwd);
449 		REGISTER_CALLBACK (serv, X_("/transport_stop"), "", transport_stop);
450 		REGISTER_CALLBACK (serv, X_("/transport_stop"), "f", transport_stop);
451 		REGISTER_CALLBACK (serv, X_("/transport_play"), "", transport_play);
452 		REGISTER_CALLBACK (serv, X_("/transport_play"), "f", transport_play);
453 		REGISTER_CALLBACK (serv, X_("/transport_frame"), "", transport_sample);
454 		REGISTER_CALLBACK (serv, X_("/transport_speed"), "", transport_speed);
455 		REGISTER_CALLBACK (serv, X_("/record_enabled"), "", record_enabled);
456 		REGISTER_CALLBACK (serv, X_("/set_transport_speed"), "f", set_transport_speed);
457 		// locate ii is position and bool roll
458 		REGISTER_CALLBACK (serv, X_("/locate"), "ii", locate);
459 		REGISTER_CALLBACK (serv, X_("/save_state"), "", save_state);
460 		REGISTER_CALLBACK (serv, X_("/save_state"), "f", save_state);
461 		REGISTER_CALLBACK (serv, X_("/prev_marker"), "", prev_marker);
462 		REGISTER_CALLBACK (serv, X_("/prev_marker"), "f", prev_marker);
463 		REGISTER_CALLBACK (serv, X_("/next_marker"), "", next_marker);
464 		REGISTER_CALLBACK (serv, X_("/next_marker"), "f", next_marker);
465 		REGISTER_CALLBACK (serv, X_("/undo"), "", undo);
466 		REGISTER_CALLBACK (serv, X_("/undo"), "f", undo);
467 		REGISTER_CALLBACK (serv, X_("/redo"), "", redo);
468 		REGISTER_CALLBACK (serv, X_("/redo"), "f", redo);
469 		REGISTER_CALLBACK (serv, X_("/toggle_punch_in"), "", toggle_punch_in);
470 		REGISTER_CALLBACK (serv, X_("/toggle_punch_in"), "f", toggle_punch_in);
471 		REGISTER_CALLBACK (serv, X_("/toggle_punch_out"), "", toggle_punch_out);
472 		REGISTER_CALLBACK (serv, X_("/toggle_punch_out"), "f", toggle_punch_out);
473 		REGISTER_CALLBACK (serv, X_("/rec_enable_toggle"), "", rec_enable_toggle);
474 		REGISTER_CALLBACK (serv, X_("/rec_enable_toggle"), "f", rec_enable_toggle);
475 		REGISTER_CALLBACK (serv, X_("/toggle_all_rec_enables"), "", toggle_all_rec_enables);
476 		REGISTER_CALLBACK (serv, X_("/toggle_all_rec_enables"), "f", toggle_all_rec_enables);
477 		REGISTER_CALLBACK (serv, X_("/all_tracks_rec_in"), "f", all_tracks_rec_in);
478 		REGISTER_CALLBACK (serv, X_("/all_tracks_rec_out"), "f", all_tracks_rec_out);
479 		REGISTER_CALLBACK (serv, X_("/cancel_all_solos"), "f", cancel_all_solos);
480 		REGISTER_CALLBACK (serv, X_("/remove_marker"), "", remove_marker_at_playhead);
481 		REGISTER_CALLBACK (serv, X_("/remove_marker"), "f", remove_marker_at_playhead);
482 		REGISTER_CALLBACK (serv, X_("/jump_bars"), "f", jump_by_bars);
483 		REGISTER_CALLBACK (serv, X_("/jump_seconds"), "f", jump_by_seconds);
484 		REGISTER_CALLBACK (serv, X_("/mark_in"), "", mark_in);
485 		REGISTER_CALLBACK (serv, X_("/mark_in"), "f", mark_in);
486 		REGISTER_CALLBACK (serv, X_("/mark_out"), "", mark_out);
487 		REGISTER_CALLBACK (serv, X_("/mark_out"), "f", mark_out);
488 		REGISTER_CALLBACK (serv, X_("/toggle_click"), "", toggle_click);
489 		REGISTER_CALLBACK (serv, X_("/toggle_click"), "f", toggle_click);
490 		REGISTER_CALLBACK (serv, X_("/click/level"), "f", click_level);
491 		REGISTER_CALLBACK (serv, X_("/midi_panic"), "", midi_panic);
492 		REGISTER_CALLBACK (serv, X_("/midi_panic"), "f", midi_panic);
493 		REGISTER_CALLBACK (serv, X_("/stop_forget"), "", stop_forget);
494 		REGISTER_CALLBACK (serv, X_("/stop_forget"), "f", stop_forget);
495 		REGISTER_CALLBACK (serv, X_("/set_punch_range"), "", set_punch_range);
496 		REGISTER_CALLBACK (serv, X_("/set_punch_range"), "f", set_punch_range);
497 		REGISTER_CALLBACK (serv, X_("/set_loop_range"), "", set_loop_range);
498 		REGISTER_CALLBACK (serv, X_("/set_loop_range"), "f", set_loop_range);
499 		REGISTER_CALLBACK (serv, X_("/set_session_range"), "", set_session_range);
500 		REGISTER_CALLBACK (serv, X_("/set_session_range"), "f", set_session_range);
501 		REGISTER_CALLBACK (serv, X_("/toggle_monitor_mute"), "", toggle_monitor_mute);
502 		REGISTER_CALLBACK (serv, X_("/toggle_monitor_mute"), "f", toggle_monitor_mute);
503 		REGISTER_CALLBACK (serv, X_("/toggle_monitor_dim"), "", toggle_monitor_dim);
504 		REGISTER_CALLBACK (serv, X_("/toggle_monitor_dim"), "f", toggle_monitor_dim);
505 		REGISTER_CALLBACK (serv, X_("/toggle_monitor_mono"), "", toggle_monitor_mono);
506 		REGISTER_CALLBACK (serv, X_("/toggle_monitor_mono"), "f", toggle_monitor_mono);
507 		REGISTER_CALLBACK (serv, X_("/quick_snapshot_switch"), "", quick_snapshot_switch);
508 		REGISTER_CALLBACK (serv, X_("/quick_snapshot_switch"), "f", quick_snapshot_switch);
509 		REGISTER_CALLBACK (serv, X_("/quick_snapshot_stay"), "", quick_snapshot_stay);
510 		REGISTER_CALLBACK (serv, X_("/quick_snapshot_stay"), "f", quick_snapshot_stay);
511 		REGISTER_CALLBACK (serv, X_("/session_name"), "s", name_session);
512 		REGISTER_CALLBACK (serv, X_("/fit_1_track"), "", fit_1_track);
513 		REGISTER_CALLBACK (serv, X_("/fit_1_track"), "f", fit_1_track);
514 		REGISTER_CALLBACK (serv, X_("/fit_2_tracks"), "", fit_2_tracks);
515 		REGISTER_CALLBACK (serv, X_("/fit_2_tracks"), "f", fit_2_tracks);
516 		REGISTER_CALLBACK (serv, X_("/fit_4_tracks"), "", fit_4_tracks);
517 		REGISTER_CALLBACK (serv, X_("/fit_4_tracks"), "f", fit_4_tracks);
518 		REGISTER_CALLBACK (serv, X_("/fit_8_tracks"), "", fit_8_tracks);
519 		REGISTER_CALLBACK (serv, X_("/fit_8_tracks"), "f", fit_8_tracks);
520 		REGISTER_CALLBACK (serv, X_("/fit_16_tracks"), "", fit_16_tracks);
521 		REGISTER_CALLBACK (serv, X_("/fit_16_tracks"), "f", fit_16_tracks);
522 		REGISTER_CALLBACK (serv, X_("/fit_32_tracks"), "", fit_32_tracks);
523 		REGISTER_CALLBACK (serv, X_("/fit_32_tracks"), "f", fit_32_tracks);
524 		REGISTER_CALLBACK (serv, X_("/fit_all_tracks"), "", fit_all_tracks);
525 		REGISTER_CALLBACK (serv, X_("/fit_all_tracks"), "f", fit_all_tracks);
526 		REGISTER_CALLBACK (serv, X_("/zoom_100_ms"), "", zoom_100_ms);
527 		REGISTER_CALLBACK (serv, X_("/zoom_100_ms"), "f", zoom_100_ms);
528 		REGISTER_CALLBACK (serv, X_("/zoom_1_sec"), "", zoom_1_sec);
529 		REGISTER_CALLBACK (serv, X_("/zoom_1_sec"), "f", zoom_1_sec);
530 		REGISTER_CALLBACK (serv, X_("/zoom_10_sec"), "", zoom_10_sec);
531 		REGISTER_CALLBACK (serv, X_("/zoom_10_sec"), "f", zoom_10_sec);
532 		REGISTER_CALLBACK (serv, X_("/zoom_1_min"), "", zoom_1_min);
533 		REGISTER_CALLBACK (serv, X_("/zoom_1_min"), "f", zoom_1_min);
534 		REGISTER_CALLBACK (serv, X_("/zoom_5_min"), "", zoom_5_min);
535 		REGISTER_CALLBACK (serv, X_("/zoom_5_min"), "f", zoom_5_min);
536 		REGISTER_CALLBACK (serv, X_("/zoom_10_min"), "", zoom_10_min);
537 		REGISTER_CALLBACK (serv, X_("/zoom_10_min"), "f", zoom_10_min);
538 		REGISTER_CALLBACK (serv, X_("/zoom_to_session"), "", zoom_to_session);
539 		REGISTER_CALLBACK (serv, X_("/zoom_to_session"), "f", zoom_to_session);
540 		REGISTER_CALLBACK (serv, X_("/temporal_zoom_in"), "f", temporal_zoom_in);
541 		REGISTER_CALLBACK (serv, X_("/temporal_zoom_in"), "", temporal_zoom_in);
542 		REGISTER_CALLBACK (serv, X_("/temporal_zoom_out"), "", temporal_zoom_out);
543 		REGISTER_CALLBACK (serv, X_("/temporal_zoom_out"), "f", temporal_zoom_out);
544 		REGISTER_CALLBACK (serv, X_("/scroll_up_1_track"), "f", scroll_up_1_track);
545 		REGISTER_CALLBACK (serv, X_("/scroll_up_1_track"), "", scroll_up_1_track);
546 		REGISTER_CALLBACK (serv, X_("/scroll_dn_1_track"), "f", scroll_dn_1_track);
547 		REGISTER_CALLBACK (serv, X_("/scroll_dn_1_track"), "", scroll_dn_1_track);
548 		REGISTER_CALLBACK (serv, X_("/scroll_up_1_page"), "f", scroll_up_1_page);
549 		REGISTER_CALLBACK (serv, X_("/scroll_up_1_page"), "", scroll_up_1_page);
550 		REGISTER_CALLBACK (serv, X_("/scroll_dn_1_page"), "f", scroll_dn_1_page);
551 		REGISTER_CALLBACK (serv, X_("/scroll_dn_1_page"), "", scroll_dn_1_page);
552 		REGISTER_CALLBACK (serv, X_("/bank_up"), "", bank_up);
553 		REGISTER_CALLBACK (serv, X_("/bank_up"), "f", bank_delta);
554 		REGISTER_CALLBACK (serv, X_("/bank_down"), "", bank_down);
555 		REGISTER_CALLBACK (serv, X_("/bank_down"), "f", bank_down);
556 		REGISTER_CALLBACK (serv, X_("/use_group"), "f", use_group);
557 
558 		// Controls for the Selected strip
559 		REGISTER_CALLBACK (serv, X_("/select/previous"), "f", sel_previous);
560 		REGISTER_CALLBACK (serv, X_("/select/previous"), "", sel_previous);
561 		REGISTER_CALLBACK (serv, X_("/select/next"), "f", sel_next);
562 		REGISTER_CALLBACK (serv, X_("/select/next"), "", sel_next);
563 		REGISTER_CALLBACK (serv, X_("/select/send_gain"), "if", sel_sendgain);
564 		REGISTER_CALLBACK (serv, X_("/select/send_fader"), "if", sel_sendfader);
565 		REGISTER_CALLBACK (serv, X_("/select/send_enable"), "if", sel_sendenable);
566 		REGISTER_CALLBACK (serv, X_("/select/master_send_enable"), "i", sel_master_send_enable);
567 		REGISTER_CALLBACK (serv, X_("/select/send_page"), "f", sel_send_page);
568 		REGISTER_CALLBACK (serv, X_("/select/plug_page"), "f", sel_plug_page);
569 		REGISTER_CALLBACK (serv, X_("/select/plugin"), "f", sel_plugin);
570 		REGISTER_CALLBACK (serv, X_("/select/plugin/activate"), "f", sel_plugin_activate);
571 		REGISTER_CALLBACK (serv, X_("/select/expand"), "i", sel_expand);
572 		REGISTER_CALLBACK (serv, X_("/select/pan_elevation_position"), "f", sel_pan_elevation);
573 		REGISTER_CALLBACK (serv, X_("/select/pan_frontback_position"), "f", sel_pan_frontback);
574 		REGISTER_CALLBACK (serv, X_("/select/pan_lfe_control"), "f", sel_pan_lfe);
575 		REGISTER_CALLBACK (serv, X_("/select/comp_enable"), "f", sel_comp_enable);
576 		REGISTER_CALLBACK (serv, X_("/select/comp_threshold"), "f", sel_comp_threshold);
577 		REGISTER_CALLBACK (serv, X_("/select/comp_speed"), "f", sel_comp_speed);
578 		REGISTER_CALLBACK (serv, X_("/select/comp_mode"), "f", sel_comp_mode);
579 		REGISTER_CALLBACK (serv, X_("/select/comp_makeup"), "f", sel_comp_makeup);
580 		REGISTER_CALLBACK (serv, X_("/select/eq_enable"), "f", sel_eq_enable);
581 		REGISTER_CALLBACK (serv, X_("/select/eq_hpf/freq"), "f", sel_eq_hpf_freq);
582 		REGISTER_CALLBACK (serv, X_("/select/eq_hpf/enable"), "f", sel_eq_hpf_enable);
583 		REGISTER_CALLBACK (serv, X_("/select/eq_hpf/slope"), "f", sel_eq_hpf_slope);
584 		REGISTER_CALLBACK (serv, X_("/select/eq_lpf/freq"), "f", sel_eq_lpf_freq);
585 		REGISTER_CALLBACK (serv, X_("/select/eq_lpf/enable"), "f", sel_eq_lpf_enable);
586 		REGISTER_CALLBACK (serv, X_("/select/eq_lpf/slope"), "f", sel_eq_lpf_slope);
587 		REGISTER_CALLBACK (serv, X_("/select/eq_gain"), "if", sel_eq_gain);
588 		REGISTER_CALLBACK (serv, X_("/select/eq_freq"), "if", sel_eq_freq);
589 		REGISTER_CALLBACK (serv, X_("/select/eq_q"), "if", sel_eq_q);
590 		REGISTER_CALLBACK (serv, X_("/select/eq_shape"), "if", sel_eq_shape);
591 		REGISTER_CALLBACK (serv, X_("/select/add_personal_send"), "s", sel_new_personal_send);
592 		REGISTER_CALLBACK (serv, X_("/select/add_fldbck_send"), "s", sel_new_personal_send);
593 
594 		/* These commands require the route index in addition to the arg; TouchOSC (et al) can't use these  */
595 		REGISTER_CALLBACK (serv, X_("/strip/custom/mode"), "f", custom_mode);
596 		REGISTER_CALLBACK (serv, X_("/strip/custom/clear"), "f", custom_clear);
597 		REGISTER_CALLBACK (serv, X_("/strip/custom/clear"), "", custom_clear);
598 
599 		REGISTER_CALLBACK (serv, X_("/strip/plugin/parameter"), "iiif", route_plugin_parameter);
600 		// prints to cerr only
601 		REGISTER_CALLBACK (serv, X_("/strip/plugin/parameter/print"), "iii", route_plugin_parameter_print);
602 		REGISTER_CALLBACK (serv, X_("/strip/plugin/activate"), "ii", route_plugin_activate);
603 		REGISTER_CALLBACK (serv, X_("/strip/plugin/deactivate"), "ii", route_plugin_deactivate);
604 		REGISTER_CALLBACK (serv, X_("/strip/send/gain"), "iif", route_set_send_gain_dB);
605 		REGISTER_CALLBACK (serv, X_("/strip/send/fader"), "iif", route_set_send_fader);
606 		REGISTER_CALLBACK (serv, X_("/strip/send/enable"), "iif", route_set_send_enable);
607 		REGISTER_CALLBACK (serv, X_("/strip/sends"), "i", route_get_sends);
608 		REGISTER_CALLBACK (serv, X_("/strip/receives"), "i", route_get_receives);
609 		REGISTER_CALLBACK (serv, X_("/strip/plugin/list"), "i", route_plugin_list);
610 		REGISTER_CALLBACK (serv, X_("/strip/plugin/descriptor"), "ii", route_plugin_descriptor);
611 		REGISTER_CALLBACK (serv, X_("/strip/plugin/reset"), "ii", route_plugin_reset);
612 
613 		/* this is a special catchall handler,
614 		 * register at the end so this is only called if no
615 		 * other handler matches (also used for debug) */
616 		lo_server_add_method (serv, 0, 0, _catchall, this);
617 	}
618 }
619 
620 bool
osc_input_handler(IOCondition ioc,lo_server srv)621 OSC::osc_input_handler (IOCondition ioc, lo_server srv)
622 {
623 	if (ioc & IO_IN) {
624 		lo_server_recv (srv);
625 	}
626 
627 	if (ioc & ~(IO_IN|IO_PRI)) {
628 		return false;
629 	}
630 
631 	return true;
632 }
633 
634 std::string
get_server_url()635 OSC::get_server_url()
636 {
637 	string url;
638 	char * urlstr;
639 
640 	if (_osc_server) {
641 		urlstr = lo_server_get_url (_osc_server);
642 		url = urlstr;
643 		free (urlstr);
644 	}
645 
646 	return url;
647 }
648 
649 std::string
get_unix_server_url()650 OSC::get_unix_server_url()
651 {
652 	string url;
653 	char * urlstr;
654 
655 	if (_osc_unix_server) {
656 		urlstr = lo_server_get_url (_osc_unix_server);
657 		url = urlstr;
658 		free (urlstr);
659 	}
660 
661 	return url;
662 }
663 
664 void
gui_changed()665 OSC::gui_changed ()
666 {
667 	session->set_dirty();
668 }
669 
670 void
current_value_query(const char * path,size_t len,lo_arg ** argv,int argc,lo_message msg)671 OSC::current_value_query (const char* path, size_t len, lo_arg **argv, int argc, lo_message msg)
672 {
673 	char* subpath;
674 
675 	subpath = (char*) malloc (len-15+1);
676 	memcpy (subpath, path, len-15);
677 	subpath[len-15] = '\0';
678 
679 	send_current_value (subpath, argv, argc, msg);
680 
681 	free (subpath);
682 }
683 
684 void
send_current_value(const char * path,lo_arg ** argv,int argc,lo_message msg)685 OSC::send_current_value (const char* path, lo_arg** argv, int argc, lo_message msg)
686 {
687 	if (!session) {
688 		return;
689 	}
690 
691 	lo_message reply = lo_message_new ();
692 	boost::shared_ptr<Route> r;
693 	int id;
694 
695 	lo_message_add_string (reply, path);
696 
697 	if (argc == 0) {
698 		lo_message_add_string (reply, "bad syntax");
699 	} else {
700 		id = argv[0]->i;
701 		r = session->get_remote_nth_route (id);
702 
703 		if (!r) {
704 			lo_message_add_string (reply, "not found");
705 		} else {
706 
707 			if (strcmp (path, X_("/strip/state")) == 0) {
708 
709 				if (boost::dynamic_pointer_cast<AudioTrack>(r)) {
710 					lo_message_add_string (reply, "AT");
711 				} else if (boost::dynamic_pointer_cast<MidiTrack>(r)) {
712 					lo_message_add_string (reply, "MT");
713 				} else {
714 					lo_message_add_string (reply, "B");
715 				}
716 
717 				lo_message_add_string (reply, r->name().c_str());
718 				lo_message_add_int32 (reply, r->n_inputs().n_audio());
719 				lo_message_add_int32 (reply, r->n_outputs().n_audio());
720 				lo_message_add_int32 (reply, r->muted());
721 				lo_message_add_int32 (reply, r->soloed());
722 
723 			} else if (strcmp (path, X_("/strip/mute")) == 0) {
724 
725 				lo_message_add_int32 (reply, (float) r->muted());
726 
727 			} else if (strcmp (path, X_("/strip/solo")) == 0) {
728 
729 				lo_message_add_int32 (reply, r->soloed());
730 			}
731 		}
732 	}
733 	OSCSurface *sur = get_surface(get_address (msg));
734 
735 	if (sur->feedback[14]) {
736 		lo_send_message (get_address (msg), X_("/reply"), reply);
737 	} else {
738 		lo_send_message (get_address (msg), X_("#reply"), reply);
739 	}
740 	lo_message_free (reply);
741 }
742 
743 int
_catchall(const char * path,const char * types,lo_arg ** argv,int argc,lo_message msg,void * user_data)744 OSC::_catchall (const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data)
745 {
746 	return ((OSC*)user_data)->catchall (path, types, argv, argc, msg);
747 }
748 
749 int
catchall(const char * path,const char * types,lo_arg ** argv,int argc,lo_message msg)750 OSC::catchall (const char *path, const char* types, lo_arg **argv, int argc, lo_message msg)
751 {
752 	size_t len;
753 	int ret = 1; /* unhandled */
754 
755 	len = strlen (path);
756 	OSCSurface *sur = get_surface(get_address (msg), true);
757 	LinkSet *set;
758 	uint32_t ls = sur->linkset;
759 
760 	if (ls) {
761 		set = &(link_sets[ls]);
762 		sur->custom_mode = set->custom_mode;
763 		sur->custom_strips = set->custom_strips;
764 		sur->temp_mode = set->temp_mode;
765 		sur->temp_strips = set->temp_strips;
766 		sur->temp_master = set->temp_master;
767 	}
768 
769 	if (strstr (path, X_("/automation"))) {
770 		ret = set_automation (path, types, argv, argc, msg);
771 
772 	} else
773 	if (strstr (path, X_("/touch"))) {
774 		ret = touch_detect (path, types, argv, argc, msg);
775 
776 	} else
777 	if (strstr (path, X_("/toggle_roll"))) {
778 		if (!argc) {
779 			ret = osc_toggle_roll (false);
780 		} else {
781 			if ((types[0] == 'f' && argv[0]->f == 1.0) || (types[0] == 'i' && argv[0]->i == 1)) {
782 				ret = osc_toggle_roll (true);
783 			} else if ((types[0] == 'f' && argv[0]->f == 0.0) || (types[0] == 'i' && argv[0]->i == 0)) {
784 				ret = osc_toggle_roll (false);
785 			}
786 		}
787 	} else
788 	if (strstr (path, X_("/spill"))) {
789 		ret = spill (path, types, argv, argc, msg);
790 
791 	} else
792 	if (len >= 17 && !strcmp (&path[len-15], X_("/#current_value"))) {
793 		current_value_query (path, len, argv, argc, msg);
794 		ret = 0;
795 
796 	} else
797 	if (!strncmp (path, X_("/cue/"), 5)) {
798 
799 		ret = cue_parse (path, types, argv, argc, msg);
800 
801 	} else
802 	if (!strncmp (path, X_("/select/plugin/parameter"), 24)) {
803 
804 		ret = select_plugin_parameter (path, types, argv, argc, msg);
805 
806 	} else
807 	if (!strncmp (path, X_("/access_action/"), 15)) {
808 		check_surface (msg);
809 		if (!(argc && !argv[0]->i)) {
810 			std::string action_path = path;
811 
812 			access_action (action_path.substr(15));
813 		}
814 
815 		ret = 0;
816 	} else
817 	if (strcmp (path, X_("/strip/listen")) == 0) {
818 		if (argc <= 0) {
819 			PBD::warning << "OSC: Wrong number of parameters." << endmsg;
820 		} else if (sur->custom_mode && !sur->temp_mode) {
821 			PBD::warning << "OSC: Can't add strips with custom enabled." << endmsg;
822 		} else {
823 			for (int n = 0; n < argc; ++n) {
824 				boost::shared_ptr<Stripable> s = boost::shared_ptr<Stripable>();
825 				if (types[n] == 'f') {
826 					s = get_strip ((uint32_t) argv[n]->f, get_address (msg));
827 				} else if (types[n] == 'i') {
828 					s = get_strip (argv[n]->i, get_address (msg));
829 				}
830 				if (s) {
831 					sur->custom_strips.push_back (s);
832 				}
833 			}
834 			if (ls) {
835 				set->custom_strips = sur->custom_strips;
836 			}
837 		}
838 		ret = 0;
839 	} else
840 	if (strcmp (path, X_("/strip/ignore")) == 0) {
841 		if (argc <= 0) {
842 			PBD::warning << "OSC: Wrong number of parameters." << endmsg;
843 		} else if (!sur->custom_mode || sur->temp_mode) {
844 			PBD::warning << "OSC: Can't remove strips without custom enabled." << endmsg;
845 		} else {
846 			for (int n = 0; n < argc; ++n) {
847 				uint32_t st_no = 0;
848 				if (types[n] == 'f') {
849 					st_no = (uint32_t) argv[n]->f;
850 				} else if (types[n] == 'i') {
851 					st_no = (uint32_t) argv[n]->i;
852 				}
853 				if (st_no && st_no <= sur->custom_strips.size ()) {
854 					sur->custom_strips[argv[n]->i - 1] = boost::shared_ptr<Stripable>();
855 				}
856 			}
857 			if (ls) {
858 				set->custom_strips = sur->custom_strips;
859 			}
860 			ret = set_bank (sur->bank, msg);
861 		}
862 
863 		ret = 0;
864 	}
865 	else if (!strncmp (path, X_("/set_surface"), 12)) {
866 		ret = surface_parse (path, types, argv, argc, msg);
867 	}
868 	else if (strstr (path, X_("/strip"))) {
869 		ret = strip_parse (path, types, argv, argc, msg);
870 	}
871 	else if (strstr (path, X_("/master"))) {
872 		ret = master_parse (path, types, argv, argc, msg);
873 	}
874 	else if (strstr (path, X_("/monitor"))) {
875 		ret = monitor_parse (path, types, argv, argc, msg);
876 	}
877 	else if (strstr (path, X_("/select"))) {
878 		ret = select_parse (path, types, argv, argc, msg);
879 	}
880 	else if (!strncmp (path, X_("/marker"), 7)) {
881 		ret = set_marker (types, argv, argc, msg);
882 	}
883 	else if (strstr (path, X_("/link"))) {
884 		ret = parse_link (path, types, argv, argc, msg);
885 	}
886 	if (ret) {
887 		check_surface (msg);
888 	}
889 
890 	if ((ret && _debugmode != Off)) {
891 		debugmsg (_("Unhandled OSC message"), path, types, argv, argc);
892 	} else if (!ret && _debugmode == All) {
893 		debugmsg (_("OSC"), path, types, argv, argc);
894 	}
895 
896 	return ret;
897 }
898 
899 void
debugmsg(const char * prefix,const char * path,const char * types,lo_arg ** argv,int argc)900 OSC::debugmsg (const char *prefix, const char *path, const char* types, lo_arg **argv, int argc)
901 {
902 	std::stringstream ss;
903 	for (int i = 0; i < argc; ++i) {
904 		lo_type type = (lo_type)types[i];
905 			ss << " ";
906 		switch (type) {
907 			case LO_INT32:
908 				ss << "i:" << argv[i]->i;
909 				break;
910 			case LO_FLOAT:
911 				ss << "f:" << argv[i]->f;
912 				break;
913 			case LO_DOUBLE:
914 				ss << "d:" << argv[i]->d;
915 				break;
916 			case LO_STRING:
917 				ss << "s:" << &argv[i]->s;
918 				break;
919 			case LO_INT64:
920 				ss << "h:" << argv[i]->h;
921 				break;
922 			case LO_CHAR:
923 				ss << "c:" << argv[i]->s;
924 				break;
925 			case LO_TIMETAG:
926 				ss << "<Timetag>";
927 				break;
928 			case LO_BLOB:
929 				ss << "<BLOB>";
930 				break;
931 			case LO_TRUE:
932 				ss << "#T";
933 				break;
934 			case LO_FALSE:
935 				ss << "#F";
936 				break;
937 			case LO_NIL:
938 				ss << "NIL";
939 				break;
940 			case LO_INFINITUM:
941 				ss << "#inf";
942 				break;
943 			case LO_MIDI:
944 				ss << "<MIDI>";
945 				break;
946 			case LO_SYMBOL:
947 				ss << "<SYMBOL>";
948 				break;
949 			default:
950 				ss << "< ?? >";
951 				break;
952 		}
953 	}
954 	PBD::info << prefix << ": " << path << ss.str() << endmsg;
955 }
956 
957 // "Application Hook" Handlers //
958 void
session_loaded(Session & s)959 OSC::session_loaded (Session& s)
960 {
961 //	lo_address listener = lo_address_new (NULL, "7770");
962 //	lo_send (listener, "/session/loaded", "ss", s.path().c_str(), s.name().c_str());
963 }
964 
965 void
session_exported(std::string path,std::string name)966 OSC::session_exported (std::string path, std::string name)
967 {
968 	lo_address listener = lo_address_new (NULL, "7770");
969 	lo_send (listener, X_("/session/exported"), "ss", path.c_str(), name.c_str());
970 	lo_address_free (listener);
971 }
972 
973 // end "Application Hook" Handlers //
974 
975 /* path callbacks */
976 
977 int
current_value(const char *,const char *,lo_arg **,int,lo_message,void *)978 OSC::current_value (const char */*path*/, const char */*types*/, lo_arg **/*argv*/, int /*argc*/, lo_message /*msg*/, void* /*user_data*/)
979 {
980 #if 0
981 	const char* returl;
982 
983 	if (argc < 3 || types == 0 || strlen (types) < 3 || types[0] != 's' || types[1] != 's' || types[2] != s) {
984 		return 1;
985 	}
986 
987 	const char *returl = argv[1]->s;
988 	lo_address addr = find_or_cache_addr (returl);
989 
990 	const char *retpath = argv[2]->s;
991 	/** this call back looks wrong. It appears to send the same information for all queries */
992 
993 
994 	if (strcmp (argv[0]->s, X_("transport_frame")) == 0) {
995 
996 		if (session) {
997 			lo_send (addr, retpath, "i", session->transport_sample());
998 		}
999 
1000 	} else if (strcmp (argv[0]->s, X_("transport_speed")) == 0) {
1001 
1002 		if (session) {
1003 			lo_send (addr, retpath, "i", session->transport_sample());
1004 		}
1005 
1006 	} else if (strcmp (argv[0]->s, X_("transport_locked")) == 0) {
1007 
1008 		if (session) {
1009 			lo_send (addr, retpath, "i", session->transport_sample());
1010 		}
1011 
1012 	} else if (strcmp (argv[0]->s, X_("punch_in")) == 0) {
1013 
1014 		if (session) {
1015 			lo_send (addr, retpath, "i", session->transport_sample());
1016 		}
1017 
1018 	} else if (strcmp (argv[0]->s, X_("punch_out")) == 0) {
1019 
1020 		if (session) {
1021 			lo_send (addr, retpath, "i", session->transport_sample());
1022 		}
1023 
1024 	} else if (strcmp (argv[0]->s, X_("rec_enable")) == 0) {
1025 
1026 		if (session) {
1027 			lo_send (addr, retpath, "i", session->transport_sample());
1028 		}
1029 
1030 	} else {
1031 
1032 		/* error */
1033 	}
1034 #endif
1035 	return 0;
1036 }
1037 
1038 void
routes_list(lo_message msg)1039 OSC::routes_list (lo_message msg)
1040 {
1041 	if (!session) {
1042 		return;
1043 	}
1044 	OSCSurface *sur = get_surface(get_address (msg), true);
1045 
1046 	for (int n = 0; n < (int) sur->nstrips; ++n) {
1047 
1048 		boost::shared_ptr<Stripable> s = get_strip (n + 1, get_address (msg));
1049 
1050 		if (s) {
1051 			// some things need the route
1052 			boost::shared_ptr<Route> r = boost::dynamic_pointer_cast<Route> (s);
1053 
1054 			lo_message reply = lo_message_new ();
1055 
1056 			if (boost::dynamic_pointer_cast<AudioTrack>(s)) {
1057 				lo_message_add_string (reply, "AT");
1058 			} else if (boost::dynamic_pointer_cast<MidiTrack>(s)) {
1059 				lo_message_add_string (reply, "MT");
1060 			} else if (boost::dynamic_pointer_cast<VCA>(s)) {
1061 				lo_message_add_string (reply, "V");
1062 			} else if (s->is_master()) {
1063 				lo_message_add_string (reply, "MA");
1064 			} else if (s->is_monitor()) {
1065 				lo_message_add_string (reply, "MO");
1066 			} else if (boost::dynamic_pointer_cast<Route>(s) && !boost::dynamic_pointer_cast<Track>(s)) {
1067 				if (!(s->presentation_info().flags() & PresentationInfo::MidiBus)) {
1068 					if (s->is_foldbackbus()) {
1069 						lo_message_add_string (reply, "FB");
1070 					} else {
1071 						lo_message_add_string (reply, "B");
1072 					}
1073 				} else {
1074 					lo_message_add_string (reply, "MB");
1075 				}
1076 			}
1077 
1078 			lo_message_add_string (reply, s->name().c_str());
1079 			if (r) {
1080 				// routes have inputs and outputs
1081 				lo_message_add_int32 (reply, r->n_inputs().n_audio());
1082 				lo_message_add_int32 (reply, r->n_outputs().n_audio());
1083 			} else {
1084 				// non-routes like VCAs don't
1085 				lo_message_add_int32 (reply, 0);
1086 				lo_message_add_int32 (reply, 0);
1087 			}
1088 			if (s->mute_control()) {
1089 				lo_message_add_int32 (reply, s->mute_control()->get_value());
1090 			} else {
1091 				lo_message_add_int32 (reply, 0);
1092 			}
1093 			if (s->solo_control()) {
1094 				lo_message_add_int32 (reply, s->solo_control()->get_value());
1095 			} else {
1096 				lo_message_add_int32 (reply, 0);
1097 			}
1098 			lo_message_add_int32 (reply, n + 1);
1099 			if (s->rec_enable_control()) {
1100 				lo_message_add_int32 (reply, s->rec_enable_control()->get_value());
1101 			}
1102 			if (sur->feedback[14]) {
1103 				lo_send_message (get_address (msg), X_("/reply"), reply);
1104 			} else {
1105 				lo_send_message (get_address (msg), X_("#reply"), reply);
1106 			}
1107 			lo_message_free (reply);
1108 		}
1109 	}
1110 
1111 	// Send end of listing message
1112 	lo_message reply = lo_message_new ();
1113 
1114 	lo_message_add_string (reply, X_("end_route_list"));
1115 	lo_message_add_int64 (reply, session->sample_rate());
1116 	lo_message_add_int64 (reply, session->current_end_sample());
1117 	if (session->monitor_out()) {
1118 		// this session has a monitor section
1119 		lo_message_add_int32 (reply, 1);
1120 	} else {
1121 		lo_message_add_int32 (reply, 0);
1122 	}
1123 
1124 	if (sur->feedback[14]) {
1125 		lo_send_message (get_address (msg), X_("/reply"), reply);
1126 	} else {
1127 		lo_send_message (get_address (msg), X_("#reply"), reply);
1128 	}
1129 
1130 	lo_message_free (reply);
1131 	// send feedback for newly created control surface
1132 	strip_feedback (sur, true);
1133 	global_feedback (sur);
1134 	_strip_select (boost::shared_ptr<ARDOUR::Stripable>(), get_address (msg));
1135 
1136 }
1137 
1138 void
surface_list(lo_message msg)1139 OSC::surface_list (lo_message msg)
1140 {
1141 		get_surfaces ();
1142 }
1143 
1144 void
get_surfaces()1145 OSC::get_surfaces ()
1146 {
1147 
1148 	/* this function is for debugging and prints lots of
1149 	 * information about what surfaces Ardour knows about and their
1150 	 * internal parameters. It is best accessed by sending:
1151 	 * /surface/list from oscsend. This command does not create
1152 	 * a surface entry.
1153 	 */
1154 
1155 	PBD::info << string_compose ("\nList of known Surfaces (%1):\n", _surface.size());
1156 
1157 	Glib::Threads::Mutex::Lock lm (surfaces_lock);
1158 	for (uint32_t it = 0; it < _surface.size(); it++) {
1159 		OSCSurface* sur = &_surface[it];
1160 		char *chost = lo_url_get_hostname (sur->remote_url.c_str());
1161 		string host = chost;
1162 		free (chost);
1163 		string port = get_port (host);
1164 		if (port != "auto") {
1165 			port = "Manual port";
1166 		} else {
1167 			port = "Auto port";
1168 		}
1169 		PBD::info << string_compose ("\n  Surface: %1 - URL: %2  %3\n", it, sur->remote_url, port);
1170 		PBD::info << string_compose ("	Number of strips: %1   Bank size: %2   Current Bank %3\n", sur->nstrips, sur->bank_size, sur->bank);
1171 		PBD::info << string_compose ("	Use Custom: %1   Custom Strips: %2\n", sur->custom_mode, sur->custom_strips.size ());
1172 		PBD::info << string_compose ("	Temp Mode: %1   Temp Strips: %2\n", sur->temp_mode, sur->temp_strips.size ());
1173 		bool ug = false;
1174 		if (sur->usegroup == PBD::Controllable::UseGroup) {
1175 			ug = true;
1176 		}
1177 		PBD::info << string_compose ("	Strip Types: %1   Feedback: %2   No_clear flag: %3   Gain mode: %4   Use groups flag %5\n", \
1178 			sur->strip_types.to_ulong(), sur->feedback.to_ulong(), sur->no_clear, sur->gainmode, ug);
1179 		PBD::info << string_compose ("	Using plugin: %1  of  %2 plugins, with %3 params.  Page size: %4  Page: %5\n", \
1180 			sur->plugin_id, sur->plugins.size(), sur->plug_params.size(), sur->plug_page_size, sur->plug_page);
1181 		PBD::info << string_compose ("	Send page size: %1  Page: %2\n", sur->send_page_size, sur->send_page);
1182 		PBD::info << string_compose ("	Expanded flag %1   Track: %2   Jogmode: %3\n", sur->expand_enable, sur->expand, sur->jogmode);
1183 		PBD::info << string_compose ("	Personal monitor flag %1,   Aux master: %2,   Number of sends: %3\n", sur->cue, sur->aux, sur->sends.size());
1184 		PBD::info << string_compose ("	Linkset: %1   Device Id: %2\n", sur->linkset, sur->linkid);
1185 	}
1186 	PBD::info << string_compose ("\nList of LinkSets (%1):\n", link_sets.size());
1187 	std::map<uint32_t, LinkSet>::iterator it;
1188 	for (it = link_sets.begin(); it != link_sets.end(); it++) {
1189 		if (!(*it).first) {
1190 			continue;
1191 		}
1192 		uint32_t devices = 0;
1193 		LinkSet* set = &(*it).second;
1194 		if (set->urls.size()) {
1195 			devices = set->urls.size() - 1;
1196 		}
1197 		PBD::info << string_compose ("\n  Linkset %1 has %2 devices and sees %3 strips\n", (*it).first, devices, set->strips.size());
1198 		PBD::info << string_compose ("	Bank size: %1   Current bank: %2   Strip Types: %3\n", set->banksize, set->bank, set->strip_types.to_ulong());
1199 		PBD::info << string_compose ("	Auto bank sizing: %1 Linkset not ready flag: %2\n", set->autobank, set->not_ready);
1200 		PBD::info << string_compose ("	Use Custom: %1 Number of Custom Strips: %2\n", set->custom_mode, set->custom_strips.size ());
1201 		PBD::info << string_compose ("	Temp Mode: %1 Number of Temp Strips: %2\n", set->temp_mode, set->temp_strips.size ());
1202 	}
1203 	PBD::info << endmsg;
1204 }
1205 
1206 int
custom_clear(lo_message msg)1207 OSC::custom_clear (lo_message msg)
1208 {
1209 	if (!session) {
1210 		return 0;
1211 	}
1212 	OSCSurface *sur = get_surface(get_address (msg), true);
1213 	sur->custom_mode = 0;
1214 	sur->custom_strips.clear ();
1215 	sur->strips = get_sorted_stripables(sur->strip_types, sur->cue, false, sur->custom_strips);
1216 	sur->nstrips = sur->strips.size();
1217 	LinkSet *set;
1218 	uint32_t ls = sur->linkset;
1219 	if (ls) {
1220 		set = &(link_sets[ls]);
1221 		set->custom_mode = 0;
1222 		set->custom_strips.clear ();
1223 		set->strips = sur->strips;
1224 	}
1225 	return set_bank (1, msg);
1226 }
1227 
1228 int
custom_mode(float state,lo_message msg)1229 OSC::custom_mode (float state, lo_message msg)
1230 {
1231 	return _custom_mode ((uint32_t) state, get_address (msg));
1232 }
1233 
1234 int
_custom_mode(uint32_t state,lo_address addr)1235 OSC::_custom_mode (uint32_t state, lo_address addr)
1236 {
1237 	if (!session) {
1238 		return 0;
1239 	}
1240 	OSCSurface *sur = get_surface(addr, true);
1241 	LinkSet *set;
1242 	uint32_t ls = sur->linkset;
1243 
1244 	if (ls) {
1245 		set = &(link_sets[ls]);
1246 		sur->custom_mode = set->custom_mode;
1247 		sur->custom_strips = set->custom_strips;
1248 	}
1249 	sur->temp_mode = TempOff;
1250 	if (state > 0){
1251 		if (sur->custom_strips.size () == 0) {
1252 			PBD::warning << "No custom strips set to enable" << endmsg;
1253 			sur->custom_mode = 0;
1254 			if (ls) {
1255 				set->custom_mode = 0;
1256 			}
1257 			return -1;
1258 		} else {
1259 			if (sur->bank_size) {
1260 				sur->custom_mode = state | 0x4;
1261 			} else {
1262 				sur->custom_mode = state;
1263 			}
1264 			sur->strips = get_sorted_stripables(sur->strip_types, sur->cue, sur->custom_mode, sur->custom_strips);
1265 			sur->nstrips = sur->custom_strips.size();
1266 		}
1267 	} else {
1268 		sur->custom_mode = 0;
1269 		sur->strips = get_sorted_stripables(sur->strip_types, sur->cue, 0, sur->custom_strips);
1270 		sur->nstrips = sur->strips.size();
1271 	}
1272 	if (ls) {
1273 		set->custom_mode = sur->custom_mode;
1274 		set->strips = sur->strips;
1275 		set->temp_mode = sur->temp_mode;
1276 	}
1277 	return _set_bank (1, addr);
1278 }
1279 
1280 int
cancel_all_solos()1281 OSC::cancel_all_solos ()
1282 {
1283 	session->cancel_all_solo ();
1284 	return 0;
1285 }
1286 
1287 int
osc_toggle_roll(bool ret2strt)1288 OSC::osc_toggle_roll (bool ret2strt)
1289 {
1290 	if (!session) {
1291 		return 0;
1292 	}
1293 
1294 	if (session->is_auditioning()) {
1295 		session->cancel_audition ();
1296 		return 0;
1297 	}
1298 
1299 	bool rolling = transport_rolling();
1300 
1301 	if (rolling) {
1302 		session->request_stop (ret2strt, true);
1303 	} else {
1304 
1305 		if (session->get_play_loop() && Config->get_loop_is_mode()) {
1306 			session->request_locate (session->locations()->auto_loop_location()->start(), MustRoll);
1307 		} else {
1308 			session->request_roll (TRS_UI);
1309 		}
1310 	}
1311 	return 0;
1312 }
1313 
1314 lo_address
get_address(lo_message msg)1315 OSC::get_address (lo_message msg)
1316 {
1317 	lo_address addr = lo_message_get_source (msg);
1318 	string host = lo_address_get_hostname (addr);
1319 	string port = lo_address_get_port (addr);
1320 	int protocol = lo_address_get_protocol (addr);
1321 	string saved_port = get_port (host);
1322 	if (saved_port != "") {
1323 		if (saved_port != "auto") {
1324 			port = saved_port;
1325 			return lo_address_new_with_proto (protocol, host.c_str(), port.c_str());
1326 		} else {
1327 			return lo_message_get_source (msg);
1328 		}
1329 	}
1330 
1331 	// if we get here we need to add a new entry for this surface
1332 	PortAdd new_port;
1333 	new_port.host = host;
1334 	if (address_only) {
1335 		new_port.port = remote_port;
1336 		_ports.push_back (new_port);
1337 		return lo_address_new_with_proto (protocol, host.c_str(), remote_port.c_str());
1338 	} else {
1339 		new_port.port = "auto";
1340 		_ports.push_back (new_port);
1341 		return lo_message_get_source (msg);
1342 	}
1343 }
1344 
1345 string
get_port(string host)1346 OSC::get_port (string host)
1347 {
1348 	for (uint32_t i = 0; i < _ports.size (); i++) {
1349 		if (_ports[i].host == host) {
1350 			return _ports[i].port;
1351 		}
1352 	}
1353 	return "";
1354 }
1355 
1356 int
refresh_surface(lo_message msg)1357 OSC::refresh_surface (lo_message msg)
1358 {
1359 	OSCSurface *s = get_surface(get_address (msg), true);
1360 	uint32_t bs = s->bank_size;
1361 	uint32_t st = (uint32_t) s->strip_types.to_ulong();
1362 	uint32_t fb = (uint32_t) s->feedback.to_ulong();
1363 	uint32_t gm = (uint32_t) s->gainmode;
1364 	uint32_t sp = s->send_page_size;
1365 	uint32_t pp = s->plug_page_size;
1366 
1367 	surface_destroy (s);
1368 	// restart all observers
1369 	set_surface (bs, st, fb, gm, sp, pp, msg);
1370 	return 0;
1371 }
1372 
1373 void
clear_devices()1374 OSC::clear_devices ()
1375 {
1376 	tick = false;
1377 	observer_busy = true;
1378 	session_connections.drop_connections ();
1379 	// clear out surfaces
1380 	for (uint32_t it = 0; it < _surface.size(); ++it) {
1381 		OSCSurface* sur = &_surface[it];
1382 		surface_destroy (sur);
1383 	}
1384 	_surface.clear();
1385 	link_sets.clear ();
1386 	_ports.clear ();
1387 
1388 	PresentationInfo::Change.connect (session_connections, MISSING_INVALIDATOR, boost::bind (&OSC::recalcbanks, this), this);
1389 
1390 	observer_busy = false;
1391 	tick = true;
1392 }
1393 
1394 int
parse_link(const char * path,const char * types,lo_arg ** argv,int argc,lo_message msg)1395 OSC::parse_link (const char *path, const char* types, lo_arg **argv, int argc, lo_message msg)
1396 {
1397 	int ret = 1; /* unhandled */
1398 	int set = 0;
1399 	if (!argc) {
1400 		PBD::warning << "OSC: /link/* needs at least one parameter" << endmsg;
1401 		return ret;
1402 	}
1403 	float data = 0;
1404 	if (types[argc - 1] == 'f') {
1405 		data = argv[argc - 1]->f;
1406 	} else {
1407 		data = argv[argc - 1]->i;
1408 	}
1409 	if (isdigit(strrchr (path, '/')[1])) {
1410 		set = atoi (&(strrchr (path, '/')[1]));
1411 	} else if (argc == 2) {
1412 		if (types[0] == 'f') {
1413 			set = (int) argv[0]->f;
1414 		} else {
1415 			set = argv[0]->i;
1416 		}
1417 	} else {
1418 		PBD::warning << "OSC: wrong number of parameters." << endmsg;
1419 		return ret;
1420 	}
1421 	LinkSet *ls = get_linkset (set, get_address (msg));
1422 
1423 	if (!set) {
1424 		return 0;
1425 	}
1426 	if (!strncmp (path, X_("/link/bank_size"), 15)) {
1427 		ls->banksize = (uint32_t) data;
1428 		ls->autobank = false;
1429 		ls->not_ready = link_check (set);
1430 		if (ls->not_ready) {
1431 			ls->bank = 1;
1432 			surface_link_state (ls);
1433 		} else {
1434 			_set_bank (ls->bank, get_address (msg));
1435 		}
1436 		ret = 0;
1437 
1438 	} else if (!strncmp (path, X_("/link/set"), 9)) {
1439 		ret = set_link (set, (uint32_t) data, get_address (msg));
1440 	}
1441 
1442 	return ret;
1443 }
1444 
1445 OSC::LinkSet *
get_linkset(uint32_t set,lo_address addr)1446 OSC::get_linkset (uint32_t set, lo_address addr)
1447 {
1448 	OSCSurface *sur = get_surface(addr);
1449 	LinkSet *ls = 0;
1450 
1451 	if (set) {
1452 		// need to check if set is wanted
1453 		std::map<uint32_t, LinkSet>::iterator it;
1454 		it = link_sets.find(set);
1455 		if (it == link_sets.end()) {
1456 			// no such linkset make it
1457 			LinkSet new_ls;
1458 			new_ls.banksize = 0;
1459 			new_ls.bank = 1;
1460 			new_ls.autobank = true;
1461 			new_ls.not_ready = true;
1462 			new_ls.strip_types = sur->strip_types;
1463 			new_ls.strips = sur->strips;
1464 			new_ls.custom_strips = sur->custom_strips;
1465 			new_ls.custom_mode = sur->custom_mode;
1466 			new_ls.temp_mode = sur->temp_mode;
1467 			new_ls.urls.resize (2);
1468 			link_sets[set] = new_ls;
1469 		}
1470 		ls = &link_sets[set];
1471 
1472 	} else {
1473 		// User expects this surface to be removed from any sets
1474 		uint32_t oldset = sur->linkset;
1475 		if (oldset) {
1476 			uint32_t oldid = sur->linkid;
1477 			sur->linkid = 1;
1478 			sur->linkset = 0;
1479 			LinkSet *ols = &link_sets[oldset];
1480 			if (ols) {
1481 				ols->not_ready = oldid;
1482 				ols->urls[oldid] = "";
1483 				surface_link_state (ols);
1484 			}
1485 		}
1486 	}
1487 	return ls;
1488 }
1489 
1490 int
set_link(uint32_t set,uint32_t id,lo_address addr)1491 OSC::set_link (uint32_t set, uint32_t id, lo_address addr)
1492 {
1493 	OSCSurface *sur = get_surface(addr, true);
1494 	sur->linkset = set;
1495 	sur->linkid = id;
1496 	LinkSet *ls = get_linkset (set, addr);
1497 	if (ls->urls.size() <= (uint32_t) id) {
1498 		ls->urls.resize ((int) id + 1);
1499 	}
1500 	ls->urls[(uint32_t) id] = sur->remote_url;
1501 	ls->not_ready = link_check (set);
1502 	if (ls->not_ready) {
1503 		surface_link_state (ls);
1504 	} else {
1505 		_set_bank (1, addr);
1506 	}
1507 	return 0;
1508 }
1509 
1510 void
link_strip_types(uint32_t linkset,uint32_t striptypes)1511 OSC::link_strip_types (uint32_t linkset, uint32_t striptypes)
1512 {
1513 	LinkSet *ls = 0;
1514 
1515 	if (!linkset) {
1516 		return;
1517 	}
1518 	std::map<uint32_t, LinkSet>::iterator it;
1519 	it = link_sets.find(linkset);
1520 	if (it == link_sets.end()) {
1521 		// this should never happen... but
1522 		return;
1523 	}
1524 	ls = &link_sets[linkset];
1525 	ls->strip_types = striptypes;
1526 	ls->temp_mode = TempOff;
1527 	for (uint32_t dv = 1; dv < ls->urls.size(); dv++) {
1528 		OSCSurface *su;
1529 
1530 		if (ls->urls[dv] != "") {
1531 			string url = ls->urls[dv];
1532 			su = get_surface (lo_address_new_from_url (url.c_str()), true);
1533 			if (su->linkset == linkset) {
1534 				su->strip_types = striptypes;
1535 				if (su->strip_types[10]) {
1536 					su->usegroup = PBD::Controllable::UseGroup;
1537 				} else {
1538 					su->usegroup = PBD::Controllable::NoGroup;
1539 				}
1540 			} else {
1541 				ls->urls[dv] = "";
1542 			}
1543 		}
1544 	}
1545 }
1546 
1547 void
surface_link_state(LinkSet * set)1548 OSC::surface_link_state (LinkSet * set)
1549 {
1550 	for (uint32_t dv = 1; dv < set->urls.size(); dv++) {
1551 
1552 		if (set->urls[dv] != "") {
1553 			string url = set->urls[dv];
1554 			OSCSurface *sur = get_surface (lo_address_new_from_url (url.c_str()), true);
1555 			for (uint32_t i = 0; i < sur->observers.size(); i++) {
1556 				sur->observers[i]->set_link_ready (set->not_ready);
1557 			}
1558 		}
1559 	}
1560 }
1561 
1562 int
link_check(uint32_t set)1563 OSC::link_check (uint32_t set)
1564 {
1565 	LinkSet *ls = 0;
1566 
1567 	if (!set) {
1568 		return 1;
1569 	}
1570 	std::map<uint32_t, LinkSet>::iterator it;
1571 	it = link_sets.find(set);
1572 	if (it == link_sets.end()) {
1573 		// this should never happen... but
1574 		return 1;
1575 	}
1576 	ls = &link_sets[set];
1577 	uint32_t bank_total = 0;
1578 	for (uint32_t dv = 1; dv < ls->urls.size(); dv++) {
1579 		OSCSurface *su;
1580 
1581 		if (ls->urls[dv] != "") {
1582 			string url = ls->urls[dv];
1583 			su = get_surface (lo_address_new_from_url (url.c_str()), true);
1584 		} else {
1585 			return dv;
1586 		}
1587 		if (su->linkset == set) {
1588 			bank_total = bank_total + su->bank_size;
1589 		} else {
1590 			ls->urls[dv] = "";
1591 			return dv;
1592 		}
1593 		if (ls->autobank) {
1594 			ls->banksize = bank_total;
1595 		} else {
1596 			if (bank_total != ls->banksize) {
1597 				return ls->urls.size();
1598 			}
1599 		}
1600 	}
1601 	return 0;
1602 }
1603 
1604 int
surface_parse(const char * path,const char * types,lo_arg ** argv,int argc,lo_message msg)1605 OSC::surface_parse (const char *path, const char* types, lo_arg **argv, int argc, lo_message msg)
1606 {
1607 	int ret = 1; /* unhandled */
1608 	OSCSurface *sur = get_surface(get_address (msg), true);
1609 	int pi_page = sur->plug_page_size;
1610 	int se_page = sur->send_page_size;
1611 	int fadermode = sur->gainmode;
1612 	int feedback = sur->feedback.to_ulong();
1613 	int strip_types = sur->strip_types.to_ulong();
1614 	int bank_size = sur->bank_size;
1615 	int linkset = sur->linkset;
1616 	int linkid = sur->linkid;
1617 	string host = lo_url_get_hostname(sur->remote_url.c_str());
1618 	int port = atoi (get_port (host).c_str());
1619 	int data = 0;
1620 
1621 	if (argc) {
1622 		if (types[0] == 'f') {
1623 			data = (int)argv[0]->f;
1624 		} else if (types[0] == 'i') {
1625 			data = argv[0]->i;
1626 		} else if (types[0] == 's') {
1627 			if (isdigit(argv[0]->s)) {
1628 				data = atoi (&(argv[0]->s));
1629 			} else {
1630 				PBD::warning << "OSC: Parameter is not numerical." << endmsg;
1631 				return 1;
1632 			}
1633 		} else {
1634 			PBD::warning << "OSC: Wrong parameter type." << endmsg;
1635 			return 1;
1636 		}
1637 	}
1638 
1639 	if (argc == 1 && !strncmp (path, X_("/set_surface/feedback"), 21)) {
1640 		ret = set_surface_feedback (data, msg);
1641 	}
1642 	else if (argc == 1 && !strncmp (path, X_("/set_surface/bank_size"), 22)) {
1643 		ret = set_surface_bank_size (data, msg);
1644 	}
1645 	else if (argc == 1 && !strncmp (path, X_("/set_surface/gainmode"), 21)) {
1646 		ret = set_surface_gainmode (data, msg);
1647 	}
1648 	else if (argc == 1 && !strncmp (path, X_("/set_surface/strip_types"), 24)) {
1649 		ret = set_surface_strip_types (data, msg);
1650 	}
1651 	else if (argc == 1 && !strncmp (path, X_("/set_surface/send_page_size"), 27)) {
1652 		ret = sel_send_pagesize (data, msg);
1653 	}
1654 	else if (argc == 1 && !strncmp (path, X_("/set_surface/plugin_page_size"), 29)) {
1655 		ret = sel_plug_pagesize (data, msg);
1656 	}
1657 	else if (argc == 1 && !strncmp (path, X_("/set_surface/port"), 17)) {
1658 		ret = set_surface_port (data, msg);
1659 	} else if (strlen(path) == 12) {
1660 
1661 		// command is in /set_surface iii form
1662 		switch (argc) {
1663 			case 9:
1664 				if (types[8] == 'f') {
1665 					linkid = (int) argv[8]->f;
1666 				} else {
1667 					linkid = argv[8]->i;
1668 				}
1669 				/* fallthrough */
1670 			case 8:
1671 				if (types[7] == 'f') {
1672 					linkset = (int) argv[7]->f;
1673 				} else {
1674 					linkset = argv[7]->i;
1675 				}
1676 				/* fallthrough */
1677 			case 7:
1678 				if (types[6] == 'f') {
1679 					port = (int) argv[6]->f;
1680 				} else {
1681 					port = argv[6]->i;
1682 				}
1683 				/* fallthrough */
1684 			case 6:
1685 				if (types[5] == 'f') {
1686 					pi_page = (int) argv[5]->f;
1687 				} else {
1688 					pi_page = argv[5]->i;
1689 				}
1690 				/* fallthrough */
1691 			case 5:
1692 				if (types[4] == 'f') {
1693 					se_page = (int) argv[4]->f;
1694 				} else {
1695 					se_page = argv[4]->i;
1696 				}
1697 				/* fallthrough */
1698 			case 4:
1699 				if (types[3] == 'f') {
1700 					fadermode = (int) argv[3]->f;
1701 				} else {
1702 					fadermode = argv[3]->i;
1703 				}
1704 				/* fallthrough */
1705 			case 3:
1706 				if (types[2] == 'f') {
1707 					feedback = (int) argv[2]->f;
1708 				} else {
1709 					feedback = argv[2]->i;
1710 				}
1711 				/* fallthrough */
1712 			case 2:
1713 				if (types[1] == 'f') {
1714 					strip_types = (int) argv[1]->f;
1715 				} else {
1716 					strip_types = argv[1]->i;
1717 				}
1718 				/* fallthrough */
1719 			case 1:
1720 				bank_size = data;
1721 				set_surface_port (port, msg);
1722 				ret = set_surface (bank_size, strip_types, feedback, fadermode, se_page, pi_page, msg);
1723 				if ((uint32_t) linkset != sur->linkset) {
1724 					set_link (linkset, linkid, get_address (msg));
1725 				}
1726 				break;
1727 			case 0:
1728 				// send current setup
1729 				{
1730 					lo_message reply = lo_message_new ();
1731 					lo_message_add_int32 (reply, bank_size);
1732 					lo_message_add_int32 (reply, strip_types);
1733 					lo_message_add_int32 (reply, feedback);
1734 					lo_message_add_int32 (reply, fadermode);
1735 					lo_message_add_int32 (reply, se_page);
1736 					lo_message_add_int32 (reply, pi_page);
1737 					lo_message_add_int32 (reply, (int) linkset);
1738 					lo_message_add_int32 (reply, (int) linkid);
1739 					lo_message_add_int32 (reply, (int) port);
1740 					lo_send_message (get_address (msg), X_("/set_surface"), reply);
1741 					lo_message_free (reply);
1742 					return 0;
1743 				}
1744 				break;
1745 
1746 			default:
1747 				PBD::warning << "OSC: Too many parameters." << endmsg;
1748 				return 1;
1749 				break;
1750 		}
1751 	} else if (isdigit(path[13])) {
1752 		// some of our parameters must be "in-lined"
1753 		bank_size = atoi (&path[13]);
1754 		const char * par = strstr (&path[13], "/");
1755 		if (par) {
1756 			strip_types = atoi (&par[1]);
1757 			const char * fb = strstr (&par[1], "/");
1758 			if (fb) {
1759 				feedback = atoi (&fb[1]);
1760 				const char * fm = strstr (&fb[1], "/");
1761 				if (fm) {
1762 					fadermode = atoi (&fm[1]);
1763 					const char * sp = strstr (&fm[1], "/");
1764 					if (sp) {
1765 						se_page = atoi (&sp[1]);
1766 						const char * pp = strstr (&sp[1], "/");
1767 						if (pp) {
1768 							pi_page = atoi (&pp[1]);
1769 							const char * po = strstr (&pp[1], "/");
1770 							if (po) {
1771 								port = atoi (&po[1]);
1772 								const char * ls = strstr (&po[1], "/");
1773 								if (ls) {
1774 									linkset = atoi (&ls[1]);
1775 									const char * li = strstr (&ls[1], "/");
1776 									if (li) {
1777 										linkid = atoi (&li[1]);
1778 									} else {
1779 										if (types[0] == 'f') {
1780 											linkid = (int) argv[0]->f;
1781 										} else if (types[0] == 'i') {
1782 											linkid = argv[0]->i;
1783 										}
1784 									}
1785 								} else {
1786 									if (types[0] == 'f') {
1787 										linkset = (int) argv[0]->f;
1788 									} else if (types[0] == 'i') {
1789 										linkset = argv[0]->i;
1790 									}
1791 								}
1792 							} else {
1793 								if (types[0] == 'f') {
1794 									port = (int) argv[0]->f;
1795 								} else if (types[0] == 'i') {
1796 									port = argv[0]->i;
1797 								}
1798 							}
1799 						} else {
1800 							if (types[0] == 'f') {
1801 								pi_page = (int) argv[0]->f;
1802 							} else if (types[0] == 'i') {
1803 								pi_page = argv[0]->i;
1804 							}
1805 						}
1806 					} else {
1807 						if (types[0] == 'f') {
1808 							se_page = (int) argv[0]->f;
1809 						} else if (types[0] == 'i') {
1810 							se_page = argv[0]->i;
1811 						}
1812 					}
1813 				} else {
1814 					if (types[0] == 'f') {
1815 						fadermode = (int) argv[0]->f;
1816 					} else if (types[0] == 'i') {
1817 						fadermode = argv[0]->i;
1818 					}
1819 				}
1820 			} else {
1821 				if (types[0] == 'f') {
1822 					feedback = (int) argv[0]->f;
1823 				} else if (types[0] == 'i') {
1824 					feedback = argv[0]->i;
1825 				}
1826 			}
1827 		} else {
1828 			if (types[0] == 'f') {
1829 				strip_types = (int) argv[0]->f;
1830 			} else if (types[0] == 'i') {
1831 				strip_types = argv[0]->i;
1832 			}
1833 		}
1834 		set_surface_port (port, msg);
1835 		ret = set_surface (bank_size, strip_types, feedback, fadermode, se_page, pi_page, msg);
1836 		if ((uint32_t) linkset != sur->linkset) {
1837 			set_link (linkset, linkid, get_address (msg));
1838 		}
1839 	}
1840 	return ret;
1841 }
1842 
1843 int
set_surface(uint32_t b_size,uint32_t strips,uint32_t fb,uint32_t gm,uint32_t se_size,uint32_t pi_size,lo_message msg)1844 OSC::set_surface (uint32_t b_size, uint32_t strips, uint32_t fb, uint32_t gm, uint32_t se_size, uint32_t pi_size, lo_message msg)
1845 {
1846 	if (observer_busy) {
1847 		return -1;
1848 	}
1849 	OSCSurface *s = get_surface(get_address (msg), true);
1850 	s->bank_size = b_size;
1851 	s->strip_types = strips;
1852 	s->feedback = fb;
1853 	s->gainmode = gm;
1854 	if (s->strip_types[10]) {
1855 		s->usegroup = PBD::Controllable::UseGroup;
1856 	} else {
1857 		s->usegroup = PBD::Controllable::NoGroup;
1858 	}
1859 	s->send_page_size = se_size;
1860 	s->plug_page_size = pi_size;
1861 	if (s->temp_mode) {
1862 		s->temp_mode = TempOff;
1863 	}
1864 	if (s->linkset) {
1865 		set_link (s->linkset, s->linkid, get_address (msg));
1866 		link_strip_types (s->linkset, s->strip_types.to_ulong());
1867 	} else {
1868 		// set bank and strip feedback
1869 		strip_feedback(s, true);
1870 		_set_bank (1, get_address (msg));
1871 		_strip_select (boost::shared_ptr<Stripable> (), get_address (msg));
1872 	}
1873 
1874 	global_feedback (s);
1875 	sel_send_pagesize (se_size, msg);
1876 	sel_plug_pagesize (pi_size, msg);
1877 	return 0;
1878 }
1879 
1880 int
set_surface_bank_size(uint32_t bs,lo_message msg)1881 OSC::set_surface_bank_size (uint32_t bs, lo_message msg)
1882 {
1883 	if (observer_busy) {
1884 		return -1;
1885 	}
1886 	OSCSurface *s = get_surface(get_address (msg), true);
1887 	s->bank_size = bs;
1888 	if (s->custom_mode && bs) {
1889 		s->custom_mode = s->custom_mode | 0x4;
1890 	}
1891 	if (s->linkset) {
1892 		set_link (s->linkset, s->linkid, get_address (msg));
1893 	} else {
1894 		// set bank and strip feedback
1895 		_set_bank (1, get_address (msg));
1896 	}
1897 	return 0;
1898 }
1899 
1900 int
set_surface_strip_types(uint32_t st,lo_message msg)1901 OSC::set_surface_strip_types (uint32_t st, lo_message msg)
1902 {
1903 	if (observer_busy) {
1904 		return -1;
1905 	}
1906 	OSCSurface *s = get_surface(get_address (msg), true);
1907 	s->strip_types = st;
1908 	s->temp_mode = TempOff;
1909 	if (s->strip_types[10]) {
1910 		s->usegroup = PBD::Controllable::UseGroup;
1911 	} else {
1912 		s->usegroup = PBD::Controllable::NoGroup;
1913 	}
1914 	if (s->linkset) {
1915 		link_strip_types (s->linkset, st);
1916 	}
1917 	// set bank and strip feedback
1918 	strip_feedback(s, false);
1919 	set_bank (1, msg);
1920 	_strip_select (boost::shared_ptr<Stripable> (), get_address (msg));
1921 	return 0;
1922 }
1923 
1924 
1925 int
set_surface_feedback(uint32_t fb,lo_message msg)1926 OSC::set_surface_feedback (uint32_t fb, lo_message msg)
1927 {
1928 	if (observer_busy) {
1929 		return -1;
1930 	}
1931 	OSCSurface *s = get_surface(get_address (msg), true);
1932 	s->feedback = fb;
1933 
1934 	strip_feedback (s, true);
1935 	global_feedback (s);
1936 	_strip_select (boost::shared_ptr<ARDOUR::Stripable>(), get_address (msg));
1937 	return 0;
1938 }
1939 
1940 int
set_surface_gainmode(uint32_t gm,lo_message msg)1941 OSC::set_surface_gainmode (uint32_t gm, lo_message msg)
1942 {
1943 	if (observer_busy) {
1944 		return -1;
1945 	}
1946 	OSCSurface *s = get_surface(get_address (msg), true);
1947 	s->gainmode = gm;
1948 
1949 	strip_feedback (s, true);
1950 	global_feedback (s);
1951 	_strip_select (boost::shared_ptr<ARDOUR::Stripable>(), get_address (msg));
1952 	return 0;
1953 }
1954 
1955 int
set_surface_port(uint32_t po,lo_message msg)1956 OSC::set_surface_port (uint32_t po, lo_message msg)
1957 {
1958 	string new_port;
1959 	if (!po) {
1960 		new_port = "auto";
1961 	} else if (po > 1024) {
1962 		new_port = string_compose ("%1", po);
1963 	} else {
1964 		PBD::warning << "Port value must be greater than 1024" << endmsg;
1965 		return -1;
1966 	}
1967 	OSCSurface *sur = get_surface(get_address (msg), true);
1968 	lo_address addr = lo_message_get_source (msg);
1969 	string host = lo_address_get_hostname (addr);
1970 	string port = lo_address_get_port (addr);
1971 	int protocol = lo_address_get_protocol (addr);
1972 	for (uint32_t i = 0; i < _ports.size (); i++) {
1973 		if (_ports[i].host == host) {
1974 			if (_ports[i].port == new_port) {
1975 				// no change - do nothing
1976 				return 0;
1977 			} else {
1978 				lo_address new_addr;
1979 				_ports[i].port = new_port;
1980 				if (new_port == "auto") {
1981 					new_addr = addr;
1982 				} else {
1983 					new_addr = lo_address_new_with_proto (protocol, host.c_str(), new_port.c_str());
1984 				}
1985 				char * rurl;
1986 				rurl = lo_address_get_url (new_addr);
1987 				sur->remote_url = rurl;
1988 				free (rurl);
1989 				for (uint32_t it = 0; it < _surface.size();) {
1990 					if (&_surface[it] == sur) {
1991 						it++;
1992 						continue;
1993 					}
1994 					char *sur_host = lo_url_get_hostname(_surface[it].remote_url.c_str());
1995 					if (strstr (sur_host, host.c_str())) {
1996 						surface_destroy (&_surface[it]);
1997 						_surface.erase (_surface.begin() + it);
1998 					} else {
1999 						it++;
2000 					}
2001 				}
2002 				if (sur->feedback.to_ulong()) {
2003 					refresh_surface (msg);
2004 				}
2005 				return 0;
2006 			}
2007 		}
2008 	}
2009 	// should not get here
2010 	return -1;
2011 }
2012 
2013 int
check_surface(lo_message msg)2014 OSC::check_surface (lo_message msg)
2015 {
2016 	if (!session) {
2017 		return -1;
2018 	}
2019 	get_surface (get_address (msg));
2020 	return 0;
2021 }
2022 
2023 OSC::OSCSurface *
get_surface(lo_address addr,bool quiet)2024 OSC::get_surface (lo_address addr , bool quiet)
2025 {
2026 	string r_url;
2027 	char * rurl;
2028 	rurl = lo_address_get_url (addr);
2029 	r_url = rurl;
2030 	free (rurl);
2031 	for (uint32_t it = 0; it < _surface.size(); ++it) {
2032 		//find setup for this surface
2033 		if (!_surface[it].remote_url.find(r_url)){
2034 			return &_surface[it];
2035 		}
2036 	}
2037 
2038 	// No surface create one with default values
2039 	OSCSurface s;
2040 	s.remote_url = r_url;
2041 	s.no_clear = false;
2042 	s.jogmode = 0;
2043 	s.bank = 1;
2044 	s.bank_size = default_banksize;
2045 	s.observers.clear();
2046 	s.sel_obs = 0;
2047 	s.global_obs = 0;
2048 	s.strip_types = default_strip;
2049 	s.feedback = default_feedback;
2050 	s.gainmode = default_gainmode;
2051 	s.usegroup = PBD::Controllable::NoGroup;
2052 	s.custom_strips.clear ();
2053 	s.custom_mode = 0;
2054 	s.temp_mode = TempOff;
2055 	s.sel_obs = 0;
2056 	s.expand = 0;
2057 	s.expand_enable = false;
2058 	s.expand_strip = boost::shared_ptr<Stripable> ();
2059 	s.cue = false;
2060 	s.aux = 0;
2061 	s.cue_obs = 0;
2062 	s.strips = get_sorted_stripables(s.strip_types, s.cue, false, s.custom_strips);
2063 	s.send_page = 1;
2064 	s.send_page_size = default_send_size;
2065 	s.plug_page = 1;
2066 	s.plug_page_size = default_plugin_size;
2067 	s.plugin_id = 1;
2068 	s.linkset = 0;
2069 	s.linkid = 1;
2070 
2071 	s.nstrips = s.strips.size();
2072 	{
2073 		_surface.push_back (s);
2074 	}
2075 
2076 	if (!quiet) {
2077 		strip_feedback (&s, true);
2078 		global_feedback (&s);
2079 	}
2080 	_strip_select2 (boost::shared_ptr<ARDOUR::Stripable>(), &_surface[_surface.size() - 1], addr);
2081 
2082 	return &_surface[_surface.size() - 1];
2083 }
2084 
2085 // setup global feedback for a surface
2086 void
global_feedback(OSCSurface * sur)2087 OSC::global_feedback (OSCSurface* sur)
2088 {
2089 	OSCGlobalObserver* o = sur->global_obs;
2090 	if (o) {
2091 		delete o;
2092 		sur->global_obs = 0;
2093 	}
2094 	if (sur->feedback[4] || sur->feedback[3] || sur->feedback[5] || sur->feedback[6]) {
2095 
2096 		// create a new Global Observer for this surface
2097 		OSCGlobalObserver* o = new OSCGlobalObserver (*this, *session, sur);
2098 		sur->global_obs = o;
2099 		o->jog_mode (sur->jogmode);
2100 	}
2101 }
2102 
2103 void
strip_feedback(OSCSurface * sur,bool new_bank_size)2104 OSC::strip_feedback (OSCSurface* sur, bool new_bank_size)
2105 {
2106 	LinkSet *set;
2107 	uint32_t ls = sur->linkset;
2108 
2109 	if (ls) {
2110 		set = &(link_sets[ls]);
2111 		if (set->not_ready) {
2112 			return;
2113 		}
2114 		sur->custom_mode = set->custom_mode;
2115 		sur->custom_strips = set->custom_strips;
2116 		sur->temp_mode = set->temp_mode;
2117 		sur->temp_strips = set->temp_strips;
2118 		sur->temp_master = set->temp_master;
2119 	}
2120 	if (!sur->temp_mode) {
2121 		sur->strips = get_sorted_stripables(sur->strip_types, sur->cue, sur->custom_mode, sur->custom_strips);
2122 	} else {
2123 		sur->strips = get_sorted_stripables(sur->strip_types, sur->cue, 1, sur->temp_strips);
2124 	}
2125 	uint32_t old_size = sur->nstrips;
2126 	sur->nstrips = sur->strips.size();
2127 	if (old_size != sur->nstrips) {
2128 		new_bank_size = true;
2129 	}
2130 
2131 	if (ls) {
2132 		set->strips = sur->strips;
2133 	}
2134 
2135 	if (new_bank_size || (!sur->feedback[0] && !sur->feedback[1])) {
2136 		// delete old observers
2137 		for (uint32_t i = 0; i < sur->observers.size(); i++) {
2138 			delete sur->observers[i];
2139 		}
2140 		sur->observers.clear();
2141 
2142 		uint32_t bank_size = sur->bank_size;
2143 		if (!bank_size) {
2144 			bank_size = sur->nstrips;
2145 		}
2146 
2147 		if (sur->feedback[0] || sur->feedback[1]) {
2148 			for (uint32_t i = 0; i < bank_size; i++) {
2149 				OSCRouteObserver* o = new OSCRouteObserver (*this, i + 1, sur);
2150 				sur->observers.push_back (o);
2151 				if (sur->temp_mode == BusOnly) {
2152 					boost::shared_ptr<ARDOUR::Stripable> str = get_strip (i + 1, lo_address_new_from_url (sur->remote_url.c_str()));
2153 					boost::shared_ptr<ARDOUR::Send> send = get_send (str, lo_address_new_from_url (sur->remote_url.c_str()));
2154 					if (send) {
2155 						o->refresh_send (send, true);
2156 					}
2157 				}
2158 
2159 			}
2160 		}
2161 	} else {
2162 		if (sur->feedback[0] || sur->feedback[1]) {
2163 			for (uint32_t i = 0; i < sur->observers.size(); i++) {
2164 				boost::shared_ptr<ARDOUR::Stripable> str = get_strip (i + 1, lo_address_new_from_url (sur->remote_url.c_str()));
2165 				sur->observers[i]->refresh_strip(str, true);
2166 				if (sur->temp_mode == BusOnly) {
2167 					boost::shared_ptr<ARDOUR::Send> send = get_send (str, lo_address_new_from_url (sur->remote_url.c_str()));
2168 					if (send) {
2169 						sur->observers[i]->refresh_send (send, true);
2170 					}
2171 				}
2172 			}
2173 		}
2174 	}
2175 	bank_leds (sur);
2176 }
2177 
2178 void
notify_routes_added(ARDOUR::RouteList &)2179 OSC::notify_routes_added (ARDOUR::RouteList &)
2180 {
2181 	// not sure if we need this PI change seems to cover
2182 	//recalcbanks();
2183 }
2184 
2185 void
notify_vca_added(ARDOUR::VCAList &)2186 OSC::notify_vca_added (ARDOUR::VCAList &)
2187 {
2188 	// not sure if we need this PI change seems to cover
2189 	//recalcbanks();
2190 }
2191 
2192 void
recalcbanks()2193 OSC::recalcbanks ()
2194 {
2195 	tick = false;
2196 	bank_dirty = true;
2197 }
2198 
2199 void
_recalcbanks()2200 OSC::_recalcbanks ()
2201 {
2202 	if (observer_busy) {
2203 		return;
2204 	}
2205 	/*
2206 	 * We have two different ways of working here:
2207 	 * 1) banked: The controller has a bank of strips and only can deal
2208 	 * with banksize strips. We start banksize observers which run until
2209 	 * either banksize is changed or Ardour exits.
2210 	 *
2211 	 * 2) banksize is 0 or unlimited and so is the same size as the number
2212 	 * of strips.
2213 	 */
2214 
2215 	// refresh each surface we know about.
2216 	for (uint32_t it = 0; it < _surface.size(); ++it) {
2217 		OSCSurface* sur = &_surface[it];
2218 		// find lo_address
2219 		lo_address addr = lo_address_new_from_url (sur->remote_url.c_str());
2220 		if (sur->cue) {
2221 			_cue_set (sur->aux, addr);
2222 		} else if (!sur->bank_size) {
2223 			strip_feedback (sur, false);
2224 			// This surface uses /strip/list tell it routes have changed
2225 			lo_message reply;
2226 			reply = lo_message_new ();
2227 			lo_send_message (addr, X_("/strip/list"), reply);
2228 			lo_message_free (reply);
2229 		} else {
2230 			strip_feedback (sur, false);
2231 		}
2232 		_strip_select (boost::shared_ptr<ARDOUR::Stripable>(), addr);
2233 	}
2234 }
2235 
2236 int
set_bank(uint32_t bank_start,lo_message msg)2237 OSC::set_bank (uint32_t bank_start, lo_message msg)
2238 {
2239 	return _set_bank (bank_start, get_address (msg));
2240 }
2241 
2242 // set bank is callable with either message or address
2243 int
_set_bank(uint32_t bank_start,lo_address addr)2244 OSC::_set_bank (uint32_t bank_start, lo_address addr)
2245 {
2246 	if (!session) {
2247 		return -1;
2248 	}
2249 	if (!session->nroutes()) {
2250 		return -1;
2251 	}
2252 
2253 	OSCSurface *s = get_surface (addr, true);
2254 
2255 	Sorted striplist = s->strips;
2256 	uint32_t nstrips = s->nstrips;
2257 
2258 	LinkSet *set;
2259 	uint32_t ls = s->linkset;
2260 
2261 	if (ls) {
2262 		//we have a linkset... deal with each surface
2263 		set = &(link_sets[ls]);
2264 		if (set->not_ready) {
2265 			return 1;
2266 		}
2267 		uint32_t d_count = set->urls.size();
2268 		set->strips = striplist;
2269 		bank_start = bank_limits_check (bank_start, set->banksize, nstrips);
2270 		set->bank = bank_start;
2271 		uint32_t not_ready = 0;
2272 		for (uint32_t dv = 1; dv < d_count; dv++) {
2273 			if (set->urls[dv] != "") {
2274 				string url = set->urls[dv];
2275 				OSCSurface *sur = get_surface (lo_address_new_from_url (url.c_str()));
2276 				if (sur->linkset != ls) {
2277 					set->urls[dv] = "";
2278 					not_ready = dv;
2279 				} else {
2280 					lo_address sur_addr = lo_address_new_from_url (sur->remote_url.c_str());
2281 
2282 					sur->bank = bank_start;
2283 					bank_start = bank_start + sur->bank_size;
2284 					strip_feedback (sur, false);
2285 					_strip_select (boost::shared_ptr<ARDOUR::Stripable>(), sur_addr);
2286 					bank_leds (sur);
2287 					lo_address_free (sur_addr);
2288 				}
2289 			} else {
2290 				not_ready = dv;
2291 			}
2292 			if (not_ready) {
2293 				if (!set->not_ready) {
2294 					set->not_ready = not_ready;
2295 				}
2296 				set->bank = 1;
2297 				break;
2298 			}
2299 		}
2300 		if (not_ready) {
2301 			surface_link_state (set);
2302 		}
2303 
2304 	} else {
2305 
2306 		s->bank = bank_limits_check (bank_start, s->bank_size, nstrips);
2307 		strip_feedback (s, true);
2308 		_strip_select (boost::shared_ptr<ARDOUR::Stripable>(), addr);
2309 		bank_leds (s);
2310 	}
2311 
2312 
2313 	bank_dirty = false;
2314 	tick = true;
2315 	return 0;
2316 }
2317 
2318 uint32_t
bank_limits_check(uint32_t bank,uint32_t size,uint32_t total)2319 OSC::bank_limits_check (uint32_t bank, uint32_t size, uint32_t total)
2320 {
2321 	uint32_t b_size;
2322 	if (!size) {
2323 		// no banking - bank includes all stripables
2324 		b_size = total;
2325 	} else {
2326 		b_size = size;
2327 	}
2328 	// Do limits checking
2329 	if (bank < 1) bank = 1;
2330 	if (b_size >= total)  {
2331 		bank = 1;
2332 	} else if (bank > ((total - b_size) + 1)) {
2333 		// top bank is always filled if there are enough strips for at least one bank
2334 		bank = (uint32_t)((total - b_size) + 1);
2335 	}
2336 	return bank;
2337 }
2338 
2339 void
bank_leds(OSCSurface * s)2340 OSC::bank_leds (OSCSurface* s)
2341 {
2342 	uint32_t bank = 0;
2343 	uint32_t size = 0;
2344 	uint32_t total = 0;
2345 	// light bankup or bankdown buttons if it is possible to bank in that direction
2346 	lo_address addr = lo_address_new_from_url (s->remote_url.c_str());
2347 	if (s->linkset) {
2348 		LinkSet *set;
2349 		set = &(link_sets[s->linkset]);
2350 		bank = set->bank;
2351 		size = set->banksize;
2352 		total = s->nstrips;
2353 		if (set->not_ready) {
2354 			total = 1;
2355 		}
2356 	} else {
2357 		bank = s->bank;
2358 		size = s->bank_size;
2359 		total = s->nstrips;
2360 	}
2361 	if (size && (s->feedback[0] || s->feedback[1] || s->feedback[4])) {
2362 		lo_message reply;
2363 		reply = lo_message_new ();
2364 		if ((total <= size) || (bank > (total - size))) {
2365 			lo_message_add_int32 (reply, 0);
2366 		} else {
2367 			lo_message_add_int32 (reply, 1);
2368 		}
2369 		lo_send_message (addr, X_("/bank_up"), reply);
2370 		lo_message_free (reply);
2371 		reply = lo_message_new ();
2372 		if (bank > 1) {
2373 			lo_message_add_int32 (reply, 1);
2374 		} else {
2375 			lo_message_add_int32 (reply, 0);
2376 		}
2377 		lo_send_message (addr, X_("/bank_down"), reply);
2378 		lo_message_free (reply);
2379 	}
2380 }
2381 
2382 int
bank_up(lo_message msg)2383 OSC::bank_up (lo_message msg)
2384 {
2385 	return bank_delta (1.0, msg);
2386 }
2387 
2388 int
bank_delta(float delta,lo_message msg)2389 OSC::bank_delta (float delta, lo_message msg)
2390 {
2391 	if (!session) {
2392 		return -1;
2393 	}
2394 	// only do deltas of -1 0 or 1
2395 	if (delta > 0) {
2396 		delta = 1;
2397 	} else if (delta < 0) {
2398 		delta = -1;
2399 	} else {
2400 		// 0  key release ignore
2401 		return 0;
2402 	}
2403 	OSCSurface *s = get_surface(get_address (msg));
2404 	if (!s->bank_size) {
2405 		// bank size of 0 means use all strips no banking
2406 		return 0;
2407 	}
2408 	uint32_t old_bank = 0;
2409 	uint32_t bank_size = 0;
2410 	if (s->linkset) {
2411 		old_bank = link_sets[s->linkset].bank;
2412 		bank_size = link_sets[s->linkset].banksize;
2413 	} else {
2414 		old_bank = s->bank;
2415 		bank_size = s->bank_size;
2416 	}
2417 	uint32_t new_bank = old_bank + (bank_size * (int) delta);
2418 	if ((int)new_bank < 1) {
2419 		new_bank = 1;
2420 	}
2421 	if (new_bank != old_bank) {
2422 		set_bank (new_bank, msg);
2423 	}
2424 	return 0;
2425 }
2426 
2427 int
bank_down(lo_message msg)2428 OSC::bank_down (lo_message msg)
2429 {
2430 	return bank_delta (-1.0, msg);
2431 }
2432 
2433 int
use_group(float value,lo_message msg)2434 OSC::use_group (float value, lo_message msg)
2435 {
2436 	if (!session) {
2437 		return -1;
2438 	}
2439 	OSCSurface *s = get_surface(get_address (msg));
2440 	if (value) {
2441 		s->usegroup = PBD::Controllable::UseGroup;
2442 	} else {
2443 		s->usegroup = PBD::Controllable::NoGroup;
2444 	}
2445 	return 0;
2446 }
2447 
2448 // this gets called for anything that starts with /select/group
2449 int
parse_sel_group(const char * path,const char * types,lo_arg ** argv,int argc,lo_message msg)2450 OSC::parse_sel_group (const char *path, const char* types, lo_arg **argv, int argc, lo_message msg)
2451 {
2452 	OSCSurface *sur = get_surface(get_address (msg));
2453 	boost::shared_ptr<Stripable> s = sur->select;
2454 	int ret = 1; /* unhandled */
2455 	/// these could be added to strip
2456 	if (s) {
2457 		boost::shared_ptr<Route> rt = boost::dynamic_pointer_cast<Route> (s);
2458 		if (!rt) {
2459 			PBD::warning << "OSC: VCAs can not be part of a group." << endmsg;
2460 			return ret;
2461 		}
2462 		RouteGroup *rg = rt->route_group();
2463 		if (!rg) {
2464 			PBD::warning << "OSC: This strip is not part of a group." << endmsg;
2465 		}
2466 		float value = 0;
2467 		if (argc == 1) {
2468 			if (types[0] == 'f') {
2469 				value = (uint32_t) argv[0]->f;
2470 			} else if (types[0] == 'i') {
2471 				value = (uint32_t) argv[0]->i;
2472 			}
2473 		}
2474 		if (!strncmp (path, X_("/select/group/enable"), 20)) {
2475 			if (rg) {
2476 				if (argc == 1) {
2477 					rg->set_active (value, this);
2478 					ret = 0;
2479 				}
2480 			} else {
2481 				int_message (X_("/select/group/enable"), 0, get_address (msg));
2482 			}
2483 		}
2484 		else if (strcmp (path, X_("/select/group/gain")) == 0) {
2485 			if (rg) {
2486 				if (argc == 1) {
2487 					rg->set_gain ((bool) value);
2488 					ret = 0;
2489 				}
2490 			} else {
2491 				int_message (X_("/select/group/gain"), 0, get_address (msg));
2492 			}
2493 		}
2494 		else if (strcmp (path, X_("/select/group/relative")) == 0) {
2495 			if (rg) {
2496 				if (argc == 1) {
2497 					rg->set_relative ((bool) value, this);
2498 					ret = 0;
2499 				}
2500 			} else {
2501 				int_message (X_("/select/group/relative"), 0, get_address (msg));
2502 			}
2503 		}
2504 		else if (strcmp (path, X_("/select/group/mute")) == 0) {
2505 			if (rg) {
2506 				if (argc == 1) {
2507 					rg->set_mute ((bool) value);
2508 					ret = 0;
2509 				}
2510 			} else {
2511 				int_message (X_("/select/group/mute"), 0, get_address (msg));
2512 			}
2513 		}
2514 		else if (strcmp (path, X_("/select/group/solo")) == 0) {
2515 			if (rg) {
2516 				if (argc == 1) {
2517 					rg->set_solo ((bool) value);
2518 					ret = 0;
2519 				}
2520 			} else {
2521 				int_message (X_("/select/group/solo"), 0, get_address (msg));
2522 			}
2523 		}
2524 		else if (strcmp (path, X_("/select/group/recenable")) == 0) {
2525 			if (rg) {
2526 				if (argc == 1) {
2527 					rg->set_recenable ((bool) value);
2528 					ret = 0;
2529 				}
2530 			} else {
2531 				int_message (X_("/select/group/recenable"), 0, get_address (msg));
2532 			}
2533 		}
2534 		else if (strcmp (path, X_("/select/group/select")) == 0) {
2535 			if (rg) {
2536 				if (argc == 1) {
2537 					rg->set_select ((bool) value);
2538 					ret = 0;
2539 				}
2540 			} else {
2541 				int_message (X_("/select/group/select"), 0, get_address (msg));
2542 			}
2543 		}
2544 		else if (strcmp (path, X_("/select/group/active")) == 0) {
2545 			if (rg) {
2546 				if (argc == 1) {
2547 					rg->set_route_active ((bool) value);
2548 					ret = 0;
2549 				}
2550 			} else {
2551 				int_message (X_("/select/group/active"), 0, get_address (msg));
2552 			}
2553 		}
2554 		else if (strcmp (path, X_("/select/group/color")) == 0) {
2555 			if (rg) {
2556 				if (argc == 1) {
2557 					rg->set_color ((bool) value);
2558 					ret = 0;
2559 				}
2560 			} else {
2561 				int_message (X_("/select/group/color"), 0, get_address (msg));
2562 			}
2563 		}
2564 		else if (strcmp (path, X_("/select/group/monitoring")) == 0) {
2565 			if (rg) {
2566 				if (argc == 1) {
2567 					rg->set_monitoring ((bool) value);
2568 					ret = 0;
2569 				}
2570 			} else {
2571 				int_message (X_("/select/group/monitoring"), 0, get_address (msg));
2572 			}
2573 		}
2574 	}
2575 	return ret;
2576  }
2577 
2578 boost::shared_ptr<VCA>
get_vca_by_name(std::string vname)2579 OSC::get_vca_by_name (std::string vname)
2580 {
2581 	StripableList stripables;
2582 	session->get_stripables (stripables);
2583 	for (StripableList::iterator it = stripables.begin(); it != stripables.end(); ++it) {
2584 		boost::shared_ptr<Stripable> s = *it;
2585 		boost::shared_ptr<VCA> v = boost::dynamic_pointer_cast<VCA> (s);
2586 		if (v) {
2587 			if (vname == v->name()) {
2588 				return v;
2589 			}
2590 		}
2591 	}
2592 	return boost::shared_ptr<VCA>();
2593 }
2594 
2595 int
set_temp_mode(lo_address addr)2596 OSC::set_temp_mode (lo_address addr)
2597 {
2598 	bool ret = 1;
2599 	OSCSurface *sur = get_surface(addr);
2600 	boost::shared_ptr<Stripable> s = sur->temp_master;
2601 	if (s) {
2602 		if (sur->temp_mode == GroupOnly) {
2603 			boost::shared_ptr<Route> rt = boost::dynamic_pointer_cast<Route> (s);
2604 			if (rt) {
2605 				RouteGroup *rg = rt->route_group();
2606 				if (rg) {
2607 					sur->temp_strips.clear();
2608 					boost::shared_ptr<RouteList> rl = rg->route_list();
2609 					for (RouteList::iterator it = rl->begin(); it != rl->end(); ++it) {
2610 						boost::shared_ptr<Route> r = *it;
2611 						boost::shared_ptr<Stripable> st = boost::dynamic_pointer_cast<Stripable> (r);
2612 						sur->temp_strips.push_back(st);
2613 					}
2614 					// check if this group feeds a bus or is slaved
2615 					boost::shared_ptr<Stripable> mstr = boost::shared_ptr<Stripable> ();
2616 					if (rg->has_control_master()) {
2617 						boost::shared_ptr<VCA> vca = session->vca_manager().vca_by_number (rg->group_master_number());
2618 						if (vca) {
2619 							mstr = boost::dynamic_pointer_cast<Stripable> (vca);
2620 						}
2621 					} else if (rg->has_subgroup()) {
2622 						boost::shared_ptr<Route> sgr = rg->subgroup_bus().lock();
2623 						if (sgr) {
2624 							mstr = boost::dynamic_pointer_cast<Stripable> (sgr);
2625 						}
2626 					}
2627 					if (mstr) {
2628 						sur->temp_strips.push_back(mstr);
2629 					}
2630 					sur->strips = get_sorted_stripables(sur->strip_types, sur->cue, 1, sur->temp_strips);
2631 					sur->nstrips = sur->temp_strips.size();
2632 					ret = 0;
2633 				}
2634 			}
2635 		} else if (sur->temp_mode == VCAOnly) {
2636 			boost::shared_ptr<VCA> vca = boost::dynamic_pointer_cast<VCA> (s);
2637 			if (vca) {
2638 				sur->temp_strips.clear();
2639 				StripableList stripables;
2640 				session->get_stripables (stripables);
2641 				for (StripableList::iterator it = stripables.begin(); it != stripables.end(); ++it) {
2642 					boost::shared_ptr<Stripable> st = *it;
2643 					if (st->slaved_to (vca)) {
2644 						sur->temp_strips.push_back(st);
2645 					}
2646 				}
2647 				sur->temp_strips.push_back(s);
2648 				sur->strips = get_sorted_stripables(sur->strip_types, sur->cue, 1, sur->temp_strips);
2649 				sur->nstrips = sur->temp_strips.size();
2650 				ret = 0;
2651 			}
2652 		} else if (sur->temp_mode == BusOnly) {
2653 			boost::shared_ptr<Route> rt = boost::dynamic_pointer_cast<Route> (s);
2654 			if (rt) {
2655 				if (!rt->is_track () && rt->can_solo ()) {
2656 					// this is a bus, but not master, monitor or audition
2657 					sur->temp_strips.clear();
2658 					StripableList stripables;
2659 					session->get_stripables (stripables, PresentationInfo::AllStripables);
2660 					for (StripableList::iterator it = stripables.begin(); it != stripables.end(); ++it) {
2661 						boost::shared_ptr<Stripable> st = *it;
2662 						boost::shared_ptr<Route> ri = boost::dynamic_pointer_cast<Route> (st);
2663 						bool sends = true;
2664 						if (ri && ri->direct_feeds_according_to_graph (rt, &sends)) {
2665 							sur->temp_strips.push_back(st);
2666 						}
2667 					}
2668 					sur->temp_strips.push_back(s);
2669 					sur->strips = get_sorted_stripables(sur->strip_types, sur->cue, 1, sur->temp_strips);
2670 					sur->nstrips = sur->temp_strips.size();
2671 					ret = 0;
2672 				}
2673 			}
2674 		} else if (sur->temp_mode == TempOff) {
2675 			sur->temp_mode = TempOff;
2676 			ret = 0;
2677 		}
2678 	}
2679 	LinkSet *set;
2680 	uint32_t ls = sur->linkset;
2681 	if (ls) {
2682 		set = &(link_sets[ls]);
2683 		set->temp_mode = sur->temp_mode;
2684 		set->temp_strips.clear ();
2685 		set->temp_strips = sur->temp_strips;
2686 		set->temp_master = sur->temp_master;
2687 		set->strips = sur->strips;
2688 	}
2689 	if (ret) {
2690 		sur->temp_mode = TempOff;
2691 	}
2692 	return ret;
2693 }
2694 
2695 boost::shared_ptr<Send>
get_send(boost::shared_ptr<Stripable> st,lo_address addr)2696 OSC::get_send (boost::shared_ptr<Stripable> st, lo_address addr)
2697 {
2698 	OSCSurface *sur = get_surface(addr);
2699 	boost::shared_ptr<Stripable> s = sur->temp_master;
2700 	if (st && s && (st != s)) {
2701 		boost::shared_ptr<Route> rt = boost::dynamic_pointer_cast<Route> (s);
2702 		boost::shared_ptr<Route> rst = boost::dynamic_pointer_cast<Route> (st);
2703 		//find what send number feeds s
2704 		return rst->internal_send_for (rt);
2705 	}
2706 	return boost::shared_ptr<Send> ();
2707 }
2708 
2709 int
name_session(char * n,lo_message msg)2710 OSC::name_session (char *n, lo_message msg)
2711 {
2712 	if (!session) {
2713 		return -1;
2714 	}
2715 	string new_name = n;
2716 	std::string const& illegal = Session::session_name_is_legal (new_name);
2717 
2718 	if (!illegal.empty()) {
2719 		PBD::warning  << (string_compose (_("To ensure compatibility with various systems\n"
2720 				    "session names may not contain a '%1' character"), illegal)) << endmsg;
2721 		return -1;
2722 	}
2723 	switch (session->rename (new_name)) {
2724 		case -1:
2725 			PBD::warning  << (_("That name is already in use by another directory/folder. Please try again.")) << endmsg;
2726 			break;
2727 		case 0:
2728 			return 0;
2729 			break;
2730 		default:
2731 			PBD::warning  << (_("Renaming this session failed.\nThings could be seriously messed up at this point")) << endmsg;
2732 			break;
2733 	}
2734 	return -1;
2735 }
2736 
2737 uint32_t
get_sid(boost::shared_ptr<ARDOUR::Stripable> strip,lo_address addr)2738 OSC::get_sid (boost::shared_ptr<ARDOUR::Stripable> strip, lo_address addr)
2739 {
2740 	if (!strip) {
2741 		return 0;
2742 	}
2743 
2744 	OSCSurface *s = get_surface(addr);
2745 
2746 	uint32_t b_size;
2747 	if (!s->bank_size) {
2748 		// no banking
2749 		b_size = s->nstrips;
2750 	} else {
2751 		b_size = s->bank_size;
2752 	}
2753 
2754 	for (uint32_t n = s->bank; n < (min ((b_size + s->bank), s->nstrips + 1)); ++n) {
2755 		if (n <= s->strips.size()) {
2756 			if (strip == s->strips[n-1]) {
2757 				return n - s->bank + 1;
2758 			}
2759 		}
2760 	}
2761 	// strip not in current bank
2762 	return 0;
2763 }
2764 
2765 boost::shared_ptr<ARDOUR::Stripable>
get_strip(uint32_t ssid,lo_address addr)2766 OSC::get_strip (uint32_t ssid, lo_address addr)
2767 {
2768 	OSCSurface *s = get_surface(addr);
2769 	if (ssid && ((ssid + s->bank - 2) < s->nstrips)) {
2770 		return s->strips[ssid + s->bank - 2];
2771 	}
2772 	// guess it is out of range
2773 	return boost::shared_ptr<ARDOUR::Stripable>();
2774 }
2775 
2776 // send and plugin paging commands
2777 int
sel_send_pagesize(uint32_t size,lo_message msg)2778 OSC::sel_send_pagesize (uint32_t size, lo_message msg)
2779 {
2780 	OSCSurface *s = get_surface(get_address (msg));
2781 	if  (size != s->send_page_size) {
2782 		s->send_page_size = size;
2783 		s->sel_obs->set_send_size(size);
2784 	}
2785 	return 0;
2786 }
2787 
2788 int
sel_send_page(int page,lo_message msg)2789 OSC::sel_send_page (int page, lo_message msg)
2790 {
2791 	OSCSurface *s = get_surface(get_address (msg));
2792 	uint32_t send_size = s->send_page_size;
2793 	if (!send_size) {
2794 		send_size = s->nsends;
2795 	}
2796 	uint32_t max_page = (uint32_t)(s->nsends / send_size) + 1;
2797 	s->send_page = s->send_page + page;
2798 	if (s->send_page < 1) {
2799 		s->send_page = 1;
2800 	} else if ((uint32_t)s->send_page > max_page) {
2801 		s->send_page = max_page;
2802 	}
2803 	s->sel_obs->set_send_page (s->send_page);
2804 	return 0;
2805 }
2806 
2807 int
sel_plug_pagesize(uint32_t size,lo_message msg)2808 OSC::sel_plug_pagesize (uint32_t size, lo_message msg)
2809 {
2810 	OSCSurface *s = get_surface(get_address (msg));
2811 	if (size != s->plug_page_size) {
2812 		s->plug_page_size = size;
2813 		s->sel_obs->set_plugin_size(size);
2814 	}
2815 	return 0;
2816 }
2817 
2818 int
sel_plug_page(int page,lo_message msg)2819 OSC::sel_plug_page (int page, lo_message msg)
2820 {
2821 	if (!page) {
2822 		return 0;
2823 	}
2824 	int new_page = 0;
2825 	OSCSurface *s = get_surface(get_address (msg));
2826 	if (page > 0) {
2827 		new_page = s->plug_page + s->plug_page_size;
2828 		if ((uint32_t) new_page > s->plug_params.size ()) {
2829 			new_page = s->plug_page;
2830 		}
2831 	} else {
2832 		new_page = s->plug_page - s->plug_page_size;
2833 		if (new_page < 1) {
2834 			new_page = 1;
2835 		}
2836 	}
2837 	if (new_page != s->plug_page) {
2838 		s->plug_page = new_page;
2839 		s->sel_obs->set_plugin_page(s->plug_page);
2840 	}
2841 	return 0;
2842 }
2843 
2844 int
sel_plugin(int delta,lo_message msg)2845 OSC::sel_plugin (int delta, lo_message msg)
2846 {
2847 	if (!delta) {
2848 		return 0;
2849 	}
2850 	OSCSurface *sur = get_surface(get_address (msg));
2851 	return _sel_plugin (sur->plugin_id + delta, get_address (msg));
2852 }
2853 
2854 int
_sel_plugin(int id,lo_address addr)2855 OSC::_sel_plugin (int id, lo_address addr)
2856 {
2857 	OSCSurface *sur = get_surface(addr);
2858 	boost::shared_ptr<Stripable> s = sur->select;
2859 	if (s) {
2860 		boost::shared_ptr<Route> r = boost::dynamic_pointer_cast<Route>(s);
2861 		if (!r) {
2862 			return 1;
2863 		}
2864 
2865 		/* find out how many plugins we have */
2866 		sur->plugins.clear();
2867 		for (int nplugs = 0; true; ++nplugs) {
2868 			boost::shared_ptr<Processor> proc = r->nth_plugin (nplugs);
2869 			if (!proc) {
2870 				break;
2871 			}
2872 			if (!r->nth_plugin(nplugs)->display_to_user()) {
2873 				continue;
2874 			}
2875 #ifdef MIXBUS
2876 			/* need to check for mixbus channel strips (and exclude them) */
2877 			boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert>(proc);
2878 			if (pi && pi->is_channelstrip()) {
2879 				continue;
2880 			}
2881 #endif
2882 			sur->plugins.push_back (nplugs);
2883 		}
2884 
2885 		// limit plugin_id to actual plugins
2886 		if (sur->plugins.size() < 1) {
2887 			sur->plugin_id = 0;
2888 			sur->plug_page = 1;
2889 			if (sur->sel_obs) {
2890 				sur->sel_obs->set_plugin_id(-1, 1);
2891 			}
2892 			return 0;
2893 		} else if (id < 1) {
2894 			sur->plugin_id = 1;
2895 		} else if (sur->plugins.size() < (uint32_t) id) {
2896 			sur->plugin_id = sur->plugins.size();
2897 		} else {
2898 			sur->plugin_id = id;
2899 		}
2900 
2901 		// we have a plugin number now get the processor
2902 		boost::shared_ptr<Processor> proc = r->nth_plugin (sur->plugins[sur->plugin_id - 1]);
2903 		boost::shared_ptr<PluginInsert> pi;
2904 		if (!(pi = boost::dynamic_pointer_cast<PluginInsert>(proc))) {
2905 			PBD::warning << "OSC: Plugin: " << sur->plugin_id << " does not seem to be a plugin" << endmsg;
2906 			return 1;
2907 		}
2908 		boost::shared_ptr<ARDOUR::Plugin> pip = pi->plugin();
2909 		bool ok = false;
2910 		// put only input controls into a vector
2911 		sur->plug_params.clear ();
2912 		uint32_t nplug_params  = pip->parameter_count();
2913 		for ( uint32_t ppi = 0;  ppi < nplug_params; ++ppi) {
2914 			uint32_t controlid = pip->nth_parameter(ppi, ok);
2915 			if (!ok) {
2916 				continue;
2917 			}
2918 			if (pip->parameter_is_input(controlid)) {
2919 				sur->plug_params.push_back (ppi);
2920 			}
2921 		}
2922 
2923 		sur->plug_page = 1;
2924 
2925 		if (sur->sel_obs) {
2926 			sur->sel_obs->set_plugin_id(sur->plugins[sur->plugin_id - 1], sur->plug_page);
2927 		}
2928 		return 0;
2929 	}
2930 	return 1;
2931 }
2932 
2933 void
transport_sample(lo_message msg)2934 OSC::transport_sample (lo_message msg)
2935 {
2936 	if (!session) {
2937 		return;
2938 	}
2939 	check_surface (msg);
2940 	samplepos_t pos = session->transport_sample ();
2941 
2942 	lo_message reply = lo_message_new ();
2943 	lo_message_add_int64 (reply, pos);
2944 
2945 	lo_send_message (get_address (msg), X_("/transport_frame"), reply);
2946 
2947 	lo_message_free (reply);
2948 }
2949 
2950 void
transport_speed(lo_message msg)2951 OSC::transport_speed (lo_message msg)
2952 {
2953 	if (!session) {
2954 		return;
2955 	}
2956 	check_surface (msg);
2957 	double ts = get_transport_speed();
2958 
2959 	lo_message reply = lo_message_new ();
2960 	lo_message_add_double (reply, ts);
2961 
2962 	lo_send_message (get_address (msg), X_("/transport_speed"), reply);
2963 
2964 	lo_message_free (reply);
2965 }
2966 
2967 void
record_enabled(lo_message msg)2968 OSC::record_enabled (lo_message msg)
2969 {
2970 	if (!session) {
2971 		return;
2972 	}
2973 	check_surface (msg);
2974 	int re = (int)session->get_record_enabled ();
2975 
2976 	lo_message reply = lo_message_new ();
2977 	lo_message_add_int32 (reply, re);
2978 
2979 	lo_send_message (get_address (msg), X_("/record_enabled"), reply);
2980 
2981 	lo_message_free (reply);
2982 }
2983 
2984 int
scrub(float delta,lo_message msg)2985 OSC::scrub (float delta, lo_message msg)
2986 {
2987 	if (!session) return -1;
2988 	check_surface (msg);
2989 
2990 	scrub_place = session->transport_sample ();
2991 
2992 	float speed;
2993 
2994 	int64_t now = PBD::get_microseconds ();
2995 	int64_t diff = now - scrub_time;
2996 	if (diff > 35000) {
2997 		// speed 1 (or 0 if jog wheel supports touch)
2998 		speed = delta;
2999 	} else if ((diff > 20000) && (fabs(scrub_speed) == 1)) {
3000 		// add some hysteresis to stop excess speed jumps
3001 		speed = delta;
3002 	} else {
3003 		speed = (int)(delta * 2);
3004 	}
3005 	scrub_time = now;
3006 	if (scrub_speed == speed) {
3007 		// Already at that speed no change
3008 		return 0;
3009 	}
3010 	scrub_speed = speed;
3011 
3012 	if (speed > 0) {
3013 		if (speed == 1) {
3014 			session->request_transport_speed (.5);
3015 		} else {
3016 			session->request_transport_speed (9.9);
3017 		}
3018 	} else if (speed < 0) {
3019 		if (speed == -1) {
3020 			session->request_transport_speed (-.5);
3021 		} else {
3022 			session->request_transport_speed (-1);
3023 		}
3024 	} else {
3025 		session->request_stop ();
3026 	}
3027 
3028 	return 0;
3029 }
3030 
3031 int
jog(float delta,lo_message msg)3032 OSC::jog (float delta, lo_message msg)
3033 {
3034 	if (!session) return -1;
3035 
3036 	OSCSurface *s = get_surface(get_address (msg));
3037 
3038 	switch(s->jogmode)
3039 	{
3040 		case 0:
3041 			if (delta) {
3042 				jump_by_seconds (delta / 5);
3043 			}
3044 			break;
3045 		case 1:
3046 			if (delta > 0) {
3047 				access_action ("Common/nudge-playhead-forward");
3048 			} else if (delta < 0) {
3049 				access_action ("Common/nudge-playhead-backward");
3050 			}
3051 			break;
3052 		case 2:
3053 			scrub (delta, msg);
3054 			break;
3055 		case 3:
3056 			if (delta) {
3057 				double speed = get_transport_speed ();
3058 				set_transport_speed (speed + (delta / 8.1));
3059 			} else {
3060 				set_transport_speed (0);
3061 			}
3062 			break;
3063 		case 4:
3064 			if (delta > 0) {
3065 				next_marker ();
3066 			} else if (delta < 0) {
3067 				prev_marker ();
3068 			}
3069 			break;
3070 		case 5:
3071 			if (delta > 0) {
3072 				access_action ("Editor/scroll-forward");
3073 			} else if (delta < 0) {
3074 				access_action ("Editor/scroll-backward");
3075 			}
3076 			break;
3077 		case 6:
3078 			if (delta > 0) {
3079 				set_bank (s->bank + 1, msg);
3080 			} else if (delta < 0) {
3081 				set_bank (s->bank - 1, msg);
3082 			}
3083 			break;
3084 		case 7:
3085 			if (delta > 0) {
3086 				bank_up (msg);
3087 			} else if (delta < 0) {
3088 				bank_down (msg);
3089 			}
3090 			break;
3091 		default:
3092 			break;
3093 
3094 	}
3095 	return 0;
3096 
3097 }
3098 
3099 int
jog_mode(float mode,lo_message msg)3100 OSC::jog_mode (float mode, lo_message msg)
3101 {
3102 	if (!session) return -1;
3103 
3104 	OSCSurface *s = get_surface(get_address (msg));
3105 	if (get_transport_speed () != 1.0) {
3106 		set_transport_speed (0);
3107 	}
3108 	s->jogmode = (uint32_t) mode;
3109 	s->global_obs->jog_mode (mode);
3110 	return 0;
3111 }
3112 
3113 // two structs to help with going to markers
3114 struct LocationMarker {
LocationMarkerLocationMarker3115 	LocationMarker (const std::string& l, samplepos_t w)
3116 		: label (l), when (w) {}
3117 	std::string label;
3118 	samplepos_t  when;
3119 };
3120 
3121 struct LocationMarkerSort {
operator ()LocationMarkerSort3122 	bool operator() (const LocationMarker& a, const LocationMarker& b) {
3123 		return (a.when < b.when);
3124 	}
3125 };
3126 
3127 int
set_marker(const char * types,lo_arg ** argv,int argc,lo_message msg)3128 OSC::set_marker (const char* types, lo_arg **argv, int argc, lo_message msg)
3129 {
3130 	if (argc != 1) {
3131 		PBD::warning << "Wrong number of parameters, one only." << endmsg;
3132 		return -1;
3133 	}
3134 	const Locations::LocationList& ll (session->locations ()->list ());
3135 	uint32_t marker = 0;
3136 
3137 	switch (types[0]) {
3138 		case 's':
3139 			{
3140 				Location *cur_mark = 0;
3141 				for (Locations::LocationList::const_iterator l = ll.begin(); l != ll.end(); ++l) {
3142 					if ((*l)->is_mark ()) {
3143 						if (strcmp (&argv[0]->s, (*l)->name().c_str()) == 0) {
3144 							session->request_locate ((*l)->start (), MustStop);
3145 							return 0;
3146 						} else if ((*l)->start () == session->transport_sample()) {
3147 							cur_mark = (*l);
3148 						}
3149 					}
3150 				}
3151 				if (cur_mark) {
3152 					cur_mark->set_name (&argv[0]->s);
3153 					return 0;
3154 				}
3155 				PBD::warning << string_compose ("Marker: \"%1\" - does not exist", &argv[0]->s) << endmsg;
3156 				return -1;
3157 			}
3158 			break;
3159 		case 'i':
3160 			marker = (uint32_t) argv[0]->i - 1;
3161 			break;
3162 		case 'f':
3163 			marker = (uint32_t) argv[0]->f - 1;
3164 			break;
3165 		default:
3166 			return -1;
3167 			break;
3168 	}
3169 	std::vector<LocationMarker> lm;
3170 	// get Locations that are marks
3171 	for (Locations::LocationList::const_iterator l = ll.begin(); l != ll.end(); ++l) {
3172 		if ((*l)->is_mark ()) {
3173 			lm.push_back (LocationMarker((*l)->name(), (*l)->start ()));
3174 		}
3175 	}
3176 	// sort them by position
3177 	LocationMarkerSort location_marker_sort;
3178 	std::sort (lm.begin(), lm.end(), location_marker_sort);
3179 	// go there
3180 	if (marker < lm.size()) {
3181 		session->request_locate (lm[marker].when, MustStop);
3182 		return 0;
3183 	}
3184 	// we were unable to deal with things
3185 	return -1;
3186 }
3187 
3188 int
group_list(lo_message msg)3189 OSC::group_list (lo_message msg)
3190 {
3191 	return send_group_list (get_address (msg));
3192 }
3193 
3194 int
send_group_list(lo_address addr)3195 OSC::send_group_list (lo_address addr)
3196 {
3197 	lo_message reply;
3198 	reply = lo_message_new ();
3199 
3200 	lo_message_add_string (reply, X_("none"));
3201 
3202 	std::list<RouteGroup*> groups = session->route_groups ();
3203 	for (std::list<RouteGroup *>::iterator i = groups.begin(); i != groups.end(); ++i) {
3204 		RouteGroup *rg = *i;
3205 		lo_message_add_string (reply, rg->name().c_str());
3206 	}
3207 	lo_send_message (addr, X_("/group/list"), reply);
3208 	lo_message_free (reply);
3209 	return 0;
3210 }
3211 
3212 int
click_level(float position)3213 OSC::click_level (float position)
3214 {
3215 	if (!session) return -1;
3216 	if (session->click_gain()->gain_control()) {
3217 		session->click_gain()->gain_control()->set_value (session->click_gain()->gain_control()->interface_to_internal (position), PBD::Controllable::NoGroup);
3218 	}
3219 	return 0;
3220 }
3221 
3222 int
route_get_sends(lo_message msg)3223 OSC::route_get_sends(lo_message msg) {
3224 	if (!session) {
3225 		return -1;
3226 	}
3227 
3228 	lo_arg **argv = lo_message_get_argv(msg);
3229 
3230 	int rid = argv[0]->i;
3231 
3232 	boost::shared_ptr<Stripable> strip = get_strip(rid, get_address(msg));
3233 	if (!strip) {
3234 		return -1;
3235 	}
3236 
3237 	boost::shared_ptr<Route> r = boost::dynamic_pointer_cast<Route> (strip);
3238 	if (!r) {
3239 		return -1;
3240 	}
3241 
3242 	lo_message reply = lo_message_new();
3243 	lo_message_add_int32(reply, rid);
3244 
3245 	int i = 0;
3246 	for (;;) {
3247 		boost::shared_ptr<Processor> p = r->nth_send(i++);
3248 
3249 		if (!p) {
3250 			break;
3251 		}
3252 
3253 		boost::shared_ptr<InternalSend> isend = boost::dynamic_pointer_cast<InternalSend> (p);
3254 		if (isend) {
3255 			lo_message_add_int32(reply, get_sid(isend->target_route(), get_address(msg)));
3256 			lo_message_add_string(reply, isend->name().c_str());
3257 			lo_message_add_int32(reply, i);
3258 			boost::shared_ptr<Amp> a = isend->amp();
3259 			lo_message_add_float(reply, a->gain_control()->internal_to_interface (a->gain_control()->get_value()));
3260 			lo_message_add_int32(reply, p->active() ? 1 : 0);
3261 		}
3262 	}
3263 	// if used dedicated message path to identify this reply in async operation.
3264 	// Naming it #reply wont help the client to identify the content.
3265 	lo_send_message(get_address (msg), X_("/strip/sends"), reply);
3266 
3267 	lo_message_free(reply);
3268 
3269 	return 0;
3270 }
3271 
3272 int
route_get_receives(lo_message msg)3273 OSC::route_get_receives(lo_message msg) {
3274 	if (!session) {
3275 		return -1;
3276 	}
3277 
3278 	lo_arg **argv = lo_message_get_argv(msg);
3279 
3280 	uint32_t rid = argv[0]->i;
3281 
3282 
3283 	boost::shared_ptr<Stripable> strip = get_strip(rid, get_address(msg));
3284 	if (!strip) {
3285 		return -1;
3286 	}
3287 
3288 	boost::shared_ptr<Route> r = boost::dynamic_pointer_cast<Route> (strip);
3289 	if (!r) {
3290 		return -1;
3291 	}
3292 
3293 	boost::shared_ptr<RouteList> route_list = session->get_routes();
3294 
3295 	lo_message reply = lo_message_new();
3296 	lo_message_add_int32(reply, rid);
3297 
3298 	for (RouteList::iterator i = route_list->begin(); i != route_list->end(); ++i) {
3299 		boost::shared_ptr<Route> tr = boost::dynamic_pointer_cast<Route> (*i);
3300 		if (!tr) {
3301 			continue;
3302 		}
3303 		int j = 0;
3304 
3305 		for (;;) {
3306 			boost::shared_ptr<Processor> p = tr->nth_send(j++);
3307 
3308 			if (!p) {
3309 				break;
3310 			}
3311 
3312 			boost::shared_ptr<InternalSend> isend = boost::dynamic_pointer_cast<InternalSend> (p);
3313 			if (isend) {
3314 				if( isend->target_route()->id() == r->id()){
3315 					boost::shared_ptr<Amp> a = isend->amp();
3316 
3317 					lo_message_add_int32(reply, get_sid(tr, get_address(msg)));
3318 					lo_message_add_string(reply, tr->name().c_str());
3319 					lo_message_add_int32(reply, j);
3320 					lo_message_add_float(reply, a->gain_control()->internal_to_interface (a->gain_control()->get_value()));
3321 					lo_message_add_int32(reply, p->active() ? 1 : 0);
3322 				}
3323 			}
3324 		}
3325 	}
3326 
3327 	// I have used a dedicated message path to identify this reply in async operation.
3328 	// Naming it #reply wont help the client to identify the content.
3329 	lo_send_message(get_address (msg), X_("/strip/receives"), reply);
3330 	lo_message_free(reply);
3331 	return 0;
3332 }
3333 
3334 // strip calls
3335 
3336 int
master_parse(const char * path,const char * types,lo_arg ** argv,int argc,lo_message msg)3337 OSC::master_parse (const char *path, const char* types, lo_arg **argv, int argc, lo_message msg)
3338 {
3339 	if (!session) return -1;
3340 	int ret = 1;
3341 	// set sub_path to null string if path is /master
3342 	const char* sub_path = &path[7];
3343 	if (strlen(path) > 8) {
3344 		// reset sub_path to char after /master/ if at least 1 char longer
3345 		sub_path = &path[8];
3346 	} else if (strlen(path) == 8) {
3347 		PBD::warning << "OSC: trailing / not valid." << endmsg;
3348 	}
3349 
3350 	//OSCSurface *sur = get_surface(get_address (msg));
3351 	boost::shared_ptr<Stripable> s = session->master_out();
3352 	if (s) {
3353 		ret = _strip_parse (path, sub_path, types, argv, argc, s, 0, false, msg);
3354 	} else {
3355 		PBD::warning << "OSC: No Master strip" << endmsg;
3356 	}
3357 	return ret;
3358 }
3359 
3360 int
monitor_parse(const char * path,const char * types,lo_arg ** argv,int argc,lo_message msg)3361 OSC::monitor_parse (const char *path, const char* types, lo_arg **argv, int argc, lo_message msg)
3362 {
3363 	if (!session) return -1;
3364 	int ret = 1;
3365 	// set sub_path to null string if path is /monitor
3366 	const char* sub_path = &path[8];
3367 	if (strlen(path) > 9) {
3368 		// reset sub_path to char after /monitor/ if at least 1 char longer
3369 		sub_path = &path[9];
3370 	} else if (strlen(path) == 9) {
3371 		PBD::warning << "OSC: trailing / not valid." << endmsg;
3372 	}
3373 
3374 	//OSCSurface *sur = get_surface(get_address (msg));
3375 	boost::shared_ptr<Stripable> s = session->monitor_out();
3376 	if (s) {
3377 		boost::shared_ptr<MonitorProcessor> mon = session->monitor_out()->monitor_control();
3378 		int state = 0;
3379 		if (types[0] == 'f') {
3380 			state = (uint32_t) argv[0]->f;
3381 		} else if (types[0] == 'i') {
3382 			state = argv[0]->i;
3383 		}
3384 		// these are only in the monitor section
3385 		if (!strncmp (sub_path, X_("mute"), 4)) {
3386 			if (argc) {
3387 				mon->set_cut_all (state);
3388 			} else {
3389 				int_message (path, mon->cut_all (), get_address (msg));
3390 			}
3391 		} else if (!strncmp (sub_path, X_("dim"), 3)) {
3392 			if (argc) {
3393 				mon->set_dim_all (state);
3394 			} else {
3395 				int_message (path, mon->dim_all (), get_address (msg));
3396 			}
3397 		} else if (!strncmp (sub_path, X_("mono"), 4)) {
3398 			if (argc) {
3399 				mon->set_mono (state);
3400 			} else {
3401 				int_message (path, mon->mono (), get_address (msg));
3402 			}
3403 		} else {
3404 			ret = _strip_parse (path, sub_path, types, argv, argc, s, 0, false, msg);
3405 		}
3406 	} else {
3407 		PBD::warning << "OSC: No Monitor strip" << endmsg;
3408 	}
3409 	return ret;
3410 }
3411 
3412 int
select_parse(const char * path,const char * types,lo_arg ** argv,int argc,lo_message msg)3413 OSC::select_parse (const char *path, const char* types, lo_arg **argv, int argc, lo_message msg)
3414 {
3415 	if (!session) return -1;
3416 	int ret = 1;
3417 	// set sub_path to null string if path is /select
3418 	const char* sub_path = &path[7];
3419 	if (strlen(path) > 8) {
3420 		// reset sub_path to char after /select/ if at least 1 char longer
3421 		sub_path = &path[8];
3422 	} else if (strlen(path) == 8) {
3423 		PBD::warning << "OSC: trailing / not valid." << endmsg;
3424 	}
3425 
3426 	OSCSurface *sur = get_surface(get_address (msg));
3427 
3428 	if (!strncmp (sub_path, X_("select"), 6)) {
3429 		PBD::warning << "OSC: select is already selected." << endmsg;
3430 		return 1;
3431 	}
3432 	if (!strncmp (path, X_("/select/group"), 13) && strlen (path) > 13) {
3433 		/** this needs fixing as it blocks /group s name */
3434 		PBD::info << "OSC: select_parse /select/group/." << endmsg;
3435 		ret = parse_sel_group (path, types, argv, argc, msg);
3436 	}
3437 	else if (!strncmp (path, X_("/select/send_gain/"), 18) && strlen (path) > 18) {
3438 		int ssid = atoi (&path[18]);
3439 		ret = sel_sendgain (ssid, argv[0]->f, msg);
3440 	}
3441 	else if (!strncmp (path, X_("/select/send_fader/"), 19) && strlen (path) > 19) {
3442 		int ssid = atoi (&path[19]);
3443 		ret = sel_sendfader (ssid, argv[0]->f, msg);
3444 	}
3445 	else if (!strncmp (path, X_("/select/send_enable/"), 20) && strlen (path) > 20) {
3446 		int ssid = atoi (&path[20]);
3447 		ret = sel_sendenable (ssid, argv[0]->f, msg);
3448 	}
3449 	else if (!strncmp (path, X_("/select/eq_gain/"), 16) && strlen (path) > 16) {
3450 		int ssid = atoi (&path[16]);
3451 		ret = sel_eq_gain (ssid, argv[0]->f, msg);
3452 	}
3453 	else if (!strncmp (path, X_("/select/eq_freq/"), 16) && strlen (path) > 16) {
3454 		int ssid = atoi (&path[16]);
3455 		ret = sel_eq_freq (ssid, argv[0]->f , msg);
3456 	}
3457 	else if (!strncmp (path, X_("/select/eq_q/"), 13) && strlen (path) > 13) {
3458 		int ssid = atoi (&path[13]);
3459 		ret = sel_eq_q (ssid, argv[0]->f, msg);
3460 	}
3461 	else if (!strncmp (path, X_("/select/eq_shape/"), 17) && strlen (path) > 17) {
3462 		int ssid = atoi (&path[17]);
3463 		ret = sel_eq_shape (ssid, argv[0]->f, msg);
3464 	}
3465 	else {
3466 		/// this is in both strip and select
3467 		boost::shared_ptr<Stripable> s = sur->select;
3468 		if (s) {
3469 			if (!strncmp (sub_path, X_("expand"), 6)) {
3470 				int yn = 0;
3471 				if (types[0] == 'f') {
3472 					yn = (int) argv[0]->f;
3473 				} else if (types[0] == 'i') {
3474 					yn = argv[0]->i;
3475 				} else {
3476 					return 1;
3477 				}
3478 				if (types[0] != 'f' && types[0] != 'i') {
3479 					return 1;
3480 				}
3481 				sur->expand_strip = s;
3482 				sur->expand_enable = (bool) yn;
3483 				boost::shared_ptr<Stripable> sel;
3484 				if (yn) {
3485 					sel = s;
3486 				} else {
3487 					sel = boost::shared_ptr<Stripable> ();
3488 				}
3489 
3490 				return _strip_select (sel, get_address (msg));
3491 			} else {
3492 				ret = _strip_parse (path, sub_path, types, argv, argc, s, 0, false, msg);
3493 			}
3494 		} else {
3495 			PBD::warning << "OSC: No selected strip" << endmsg;
3496 		}
3497 	}
3498 
3499 	return ret;
3500 
3501 }
3502 
3503 
3504 int
strip_parse(const char * path,const char * types,lo_arg ** argv,int argc,lo_message msg)3505 OSC::strip_parse (const char *path, const char* types, lo_arg **argv, int argc, lo_message msg)
3506 {
3507 	if (!session) return -1;
3508 	int ret = 1;
3509 	int ssid = 0;
3510 	int param_1 = 1;
3511 	uint32_t nparam = argc;
3512 	const char* sub_path = &path[6];
3513 	if (strlen(path) > 7) {
3514 		// reset sub_path to char after /strip/ if at least 1 char longer
3515 		sub_path = &path[7];
3516 	} else if (strlen(path) == 7) {
3517 		PBD::warning << "OSC: trailing / not valid." << endmsg;
3518 		return 1;
3519 	}
3520 
3521 	OSCSurface *sur = get_surface(get_address (msg));
3522 
3523 	// ssid may be in three places
3524 	 if (atoi(sub_path)) {
3525 		// test for /strip/<ssid>/subpath
3526 		ssid = atoi(sub_path);
3527 		nparam++;
3528 		param_1 = 0;
3529 		if (strchr(sub_path, (int) '/')) {
3530 			sub_path = &(strchr(sub_path, (int) '/')[1]);
3531 		} else {
3532 			sub_path = &(strchr(sub_path, 0)[1]);
3533 		}
3534 	} else if (atoi (&(strrchr(path, (int) '/')[1]))) {
3535 		// check for /path/<ssid>
3536 		ssid = atoi (&(strrchr(path, (int) '/')[1]));
3537 		nparam++;
3538 		param_1 = 0;
3539 	} else if (argc) {
3540 		if (types[0] == 'i') {
3541 			ssid = argv[0]->i;
3542 		} else if (types[0] == 'f') {
3543 			ssid = argv[0]->f;
3544 		}
3545 	}
3546 	if (!nparam && !ssid) {
3547 		// only list works here
3548 		if (!strcmp (path, X_("/strip/list"))) {
3549 			// /strip/list is legacy
3550 			routes_list (msg);
3551 			ret = 0;
3552 		}
3553 		else if (!strcmp (path, X_("/strip"))) {
3554 			strip_list (msg);
3555 			ret = 0;
3556 		} else {
3557 			PBD::warning << "OSC: missing parameters." << endmsg;
3558 			return 1;
3559 		}
3560 	}
3561 	boost::shared_ptr<Stripable> s = get_strip (ssid, get_address (msg));
3562 	if (s) {
3563 		if (!strncmp (sub_path, X_("expand"), 6)) {
3564 			/// this is in both strip and select should be in _parse_strip
3565 			int yn = 0;
3566 			if (types[param_1] == 'f') {
3567 				yn = (int) argv[param_1]->f;
3568 			} else if (types[param_1] == 'i') {
3569 				yn = argv[param_1]->i;
3570 			} else {
3571 				return 1;
3572 			}
3573 			if (types[param_1] != 'f' && types[param_1] != 'i') {
3574 				return 1;
3575 			}
3576 			sur->expand_strip = s;
3577 			sur->expand_enable = (bool) yn;
3578 			sur->expand = ssid;
3579 			boost::shared_ptr<Stripable> sel;
3580 			if (yn) {
3581 				sel = s;
3582 			} else {
3583 				sel = boost::shared_ptr<Stripable> ();
3584 			}
3585 
3586 			return _strip_select (sel, get_address (msg));
3587 		} else {
3588 			ret = _strip_parse (path, sub_path, types, argv, argc, s, param_1, true, msg);
3589 		}
3590 	} else {
3591 		PBD::warning << "OSC: No such strip" << endmsg;
3592 	}
3593 
3594 	return ret;
3595 
3596 }
3597 
3598 int
_strip_parse(const char * path,const char * sub_path,const char * types,lo_arg ** argv,int argc,boost::shared_ptr<ARDOUR::Stripable> s,int param_1,bool strp,lo_message msg)3599 OSC::_strip_parse (const char *path, const char *sub_path, const char* types, lo_arg **argv, int argc, boost::shared_ptr<ARDOUR::Stripable> s, int param_1, bool strp, lo_message msg)
3600 {
3601 	int ret = 1;
3602 	int yn = 0;
3603 	float value = 0.0;
3604 	string strng = "";
3605 	char *text;
3606 	bool s_flt = false;
3607 	bool s_int = false;
3608 	if (types[param_1] == 'f') {
3609 		yn = (int) argv[param_1]->f;
3610 		s_int = true;
3611 		value = argv[param_1]->f;
3612 		s_flt = true;
3613 	} else if (types[param_1] == 'i') {
3614 		yn = argv[param_1]->i;
3615 		s_int = true;
3616 	} else if (types[param_1] == 's') {
3617 		text = &argv[param_1]->s;
3618 		strng = &argv[param_1]->s;
3619 		if (atoi(text) || text[0] == '0') {
3620 			yn = atoi(text);
3621 			s_int = true;
3622 		}
3623 		if (atof(text)) {
3624 			value = atof(text);
3625 			s_flt = true;
3626 		}
3627 	}
3628 	OSCSurface *sur = get_surface(get_address (msg));
3629 	bool send_active = strp && sur->temp_mode == BusOnly && get_send (s, get_address (msg));
3630 	bool control_disabled = strp && (sur->temp_mode == BusOnly) && (s != sur->temp_master);
3631 	bool n_mo = !s->is_monitor();
3632 	boost::shared_ptr<Route> rt = boost::dynamic_pointer_cast<Route> (s);
3633 
3634 	if (!strlen(sub_path)) {
3635 		// send stripable info
3636 		int sid = 0;
3637 		if (param_1) {
3638 			if (types[0] == 'f') {
3639 				sid = (int) argv[0]->f;
3640 			} else if (types[0] == 'i') {
3641 				sid = argv[0]->i;
3642 			}
3643 		}
3644 		ret = strip_state (path, s, sid, msg);
3645 	}
3646 	else if (!strncmp (sub_path, X_("gain"), 4) || !strncmp (sub_path, X_("fader"), 5) ||  !strncmp (sub_path, X_("db_delta"), 8)){
3647 		boost::shared_ptr<GainControl> gain_control;
3648 		gain_control = s->gain_control();
3649 		if (gain_control) {
3650 			if (argc > (param_1)) {
3651 				if (s_flt) {
3652 					if (send_active) {
3653 						gain_control = get_send(s, get_address (msg))->gain_control();
3654 					}
3655 					float abs;
3656 					if (!strncmp (sub_path, X_("gain"), 4)) {
3657 						if (value < -192) {
3658 							abs = 0;
3659 						} else {
3660 							abs = dB_to_coefficient (value);
3661 						}
3662 					} else if (!strncmp (sub_path, X_("fader"), 5)) {
3663 						abs = gain_control->interface_to_internal (value);
3664 					} else if (!strncmp (sub_path, X_("db_delta"), 8)) {
3665 						float db = accurate_coefficient_to_dB (gain_control->get_value()) + value;
3666 						if (db < -192) {
3667 							abs = 0;
3668 						} else {
3669 							abs = dB_to_coefficient (db);
3670 						}
3671 					} else {
3672 						abs = 0;
3673 					}
3674 					float top = gain_control->upper();
3675 					if (abs > top) {
3676 						abs = top;
3677 					}
3678 					fake_touch (gain_control);
3679 					gain_control->set_value (abs, sur->usegroup);
3680 					ret = 0;
3681 				}
3682 			} else {
3683 				float ret_v;
3684 				if (!strncmp (sub_path, X_("gain"), 4)) {
3685 					ret_v = fast_coefficient_to_dB (gain_control->get_value ());
3686 					ret = 0;
3687 				} else if (!strncmp (sub_path, X_("fader"), 5)) {
3688 					ret_v = gain_control->internal_to_interface (gain_control->get_value ());
3689 					ret = 0;
3690 				} else {
3691 					PBD::warning << "OSC: delta has no info" << endmsg;
3692 				}
3693 				if (!ret) {
3694 					float_message (path, ret_v, get_address (msg));
3695 				}
3696 			}
3697 		}
3698 	}
3699 	else if (!strncmp (sub_path, X_("trimdB"), 6)) {
3700 		if (!control_disabled && s->trim_control() && n_mo) {
3701 			if (argc > (param_1)) {
3702 				if (s_flt) {
3703 					float abs = dB_to_coefficient (value);
3704 					s->trim_control()->set_value (abs, sur->usegroup);
3705 					fake_touch (s->trim_control());
3706 					ret = 0;
3707 				}
3708 			} else {
3709 				float_message (path, fast_coefficient_to_dB (s->trim_control()->get_value ()), get_address (msg));
3710 				ret = 0;
3711 			}
3712 		}
3713 	}
3714 	else if (!strncmp (sub_path, X_("pan_stereo_position"), 19)) {
3715 		boost::shared_ptr<PBD::Controllable> pan_control = boost::shared_ptr<PBD::Controllable>();
3716 		pan_control = s->pan_azimuth_control();
3717 		if (n_mo && pan_control) {
3718 			if (argc > (param_1)) {
3719 				if (s_flt) {
3720 					if (send_active) {
3721 						boost::shared_ptr<ARDOUR::Send> send = get_send (s, get_address (msg));
3722 						if (send->pan_outs() > 1) {
3723 							pan_control = send->panner_shell()->panner()->pannable()->pan_azimuth_control;
3724 						} else {
3725 							pan_control = boost::shared_ptr<PBD::Controllable>();
3726 						}
3727 					}
3728 					if(pan_control) {
3729 						pan_control->set_value (s->pan_azimuth_control()->interface_to_internal (value), sur->usegroup);
3730 						boost::shared_ptr<AutomationControl>pan_automate = boost::dynamic_pointer_cast<AutomationControl> (pan_control);
3731 						fake_touch (pan_automate);
3732 						ret = 0;
3733 					}
3734 				}
3735 			} else {
3736 				float_message (path, pan_control->internal_to_interface (pan_control->get_value ()), get_address (msg));
3737 				ret = 0;
3738 			}
3739 		}
3740 	}
3741 	else if (!strncmp (sub_path, X_("pan_stereo_width"), 16)) {
3742 		if (!control_disabled && s->pan_width_control()) {
3743 			if (argc > (param_1)) {
3744 				if (s_flt) {
3745 					/// this should maybe be active in send mode (see above)
3746 					s->pan_width_control()->set_value (value, sur->usegroup);
3747 					fake_touch (s->pan_width_control());
3748 					ret = 0;
3749 				}
3750 			} else {
3751 				float_message (path, s->pan_width_control()->get_value (), get_address (msg));
3752 				ret = 0;
3753 			}
3754 		}
3755 	}
3756 	else if (!strncmp (sub_path, X_("mute"), 4)) {
3757 		if (!control_disabled && s->mute_control()) {
3758 			if (argc > (param_1)) {
3759 				if (s_int) {
3760 					s->mute_control()->set_value (yn ? 1.0 : 0.0, sur->usegroup);
3761 					fake_touch (s->mute_control());
3762 					ret = 0;
3763 				}
3764 			} else {
3765 				int_message (path, s->mute_control()->get_value (), get_address (msg));
3766 				ret = 0;
3767 			}
3768 		}
3769 	}
3770 	else if (!strncmp (sub_path, X_("solo_iso"), 8)) {
3771 		if (!control_disabled && s->solo_isolate_control()) {
3772 			if (argc > (param_1)) {
3773 				if (s_int) {
3774 					s->solo_isolate_control()->set_value (yn ? 1.0 : 0.0, sur->usegroup);
3775 					ret = 0;
3776 				}
3777 			} else {
3778 				int_message (path, s->solo_isolate_control()->get_value (), get_address (msg));
3779 				ret = 0;
3780 			}
3781 		}
3782 	}
3783 	else if (!strncmp (sub_path, X_("solo_safe"), 9)) {
3784 		if (!control_disabled && s->solo_safe_control()) {
3785 			if (argc > (param_1)) {
3786 				if (s_int) {
3787 					s->solo_safe_control()->set_value (yn ? 1.0 : 0.0, sur->usegroup);
3788 					ret = 0;
3789 				}
3790 			} else {
3791 				int_message (path, s->solo_safe_control()->get_value (), get_address (msg));
3792 				ret = 0;
3793 			}
3794 		}
3795 	}
3796 	else if (!strncmp (sub_path, X_("solo"), 4)) {
3797 		if (!control_disabled && s->solo_control() && !s->is_master() && !s->is_monitor()) {
3798 			if (argc > (param_1)) {
3799 				if (s_int) {
3800 					s->solo_control()->set_value (yn ? 1.0 : 0.0, sur->usegroup);
3801 					ret = 0;
3802 				}
3803 			} else {
3804 				int_message (path, s->solo_control()->get_value (), get_address (msg));
3805 				ret = 0;
3806 			}
3807 		}
3808 	}
3809 	else if (!strncmp (sub_path, X_("monitor_input"), 13)) {
3810 		boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (s);
3811 		if (!control_disabled && track && track->monitoring_control()) {
3812 			std::bitset<32> mon_bs = track->monitoring_control()->get_value ();
3813 			if (argc > (param_1)) {
3814 				if (s_int) {
3815 					mon_bs[0] = yn ? 1 : 0;
3816 					track->monitoring_control()->set_value (mon_bs.to_ulong(), sur->usegroup);
3817 					ret = 0;
3818 				}
3819 			} else {
3820 				int_message (path, (int) mon_bs[0], get_address (msg));
3821 				ret = 0;
3822 			}
3823 		}
3824 	}
3825 	else if (!strncmp (sub_path, X_("monitor_disk"), 12)) {
3826 		boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (s);
3827 		if (!control_disabled && track && track->monitoring_control()) {
3828 			std::bitset<32> mon_bs = track->monitoring_control()->get_value ();
3829 			if (argc > (param_1)) {
3830 				if (s_int) {
3831 					mon_bs[1] = yn ? 1 : 0;
3832 					track->monitoring_control()->set_value (mon_bs.to_ulong(), sur->usegroup);
3833 					ret = 0;
3834 				}
3835 			} else {
3836 				int_message (path, (int) mon_bs[1], get_address (msg));
3837 				ret = 0;
3838 			}
3839 		}
3840 	}
3841 	else if (!strncmp (sub_path, X_("recenable"), 9)) {
3842 		if (!control_disabled && s->rec_enable_control()) {
3843 			if (argc > (param_1)) {
3844 				if (s_int) {
3845 					s->rec_enable_control()->set_value (yn, sur->usegroup);
3846 					ret = 0;
3847 				}
3848 			} else {
3849 				int_message (path, s->rec_enable_control()->get_value (), get_address (msg));
3850 				ret = 0;
3851 			}
3852 		}
3853 	}
3854 	else if (!strncmp (sub_path, X_("record_safe"), 11)) {
3855 		if (!control_disabled && s->rec_safe_control()) {
3856 			if (argc > (param_1)) {
3857 				if (s_int) {
3858 					s->rec_safe_control()->set_value (yn, sur->usegroup);
3859 					ret = 0;
3860 				}
3861 			} else {
3862 				int_message (path, s->rec_safe_control()->get_value (), get_address (msg));
3863 				ret = 0;
3864 			}
3865 		}
3866 	}
3867 	else if (!strncmp (sub_path, X_("hide"), 4)) {
3868 		if (!control_disabled) {
3869 			if (argc > (param_1)) {
3870 				if (s_int && yn != s->is_hidden ()) {
3871 					s->presentation_info().set_hidden ((bool) yn);
3872 					ret = 0;
3873 				} else {
3874 					PBD::warning << string_compose("OSC: value already %1 not changed.", yn) << endmsg;
3875 				}
3876 			} else {
3877 				int_message (path, s->is_hidden (), get_address (msg));
3878 				ret = 0;
3879 			}
3880 		}
3881 	}
3882 	else if (!strncmp (sub_path, X_("select"), 6)) {
3883 		if (argc > (param_1)) {
3884 			if (s_int) {
3885 				//ignore button release
3886 				if (!yn) return 0;
3887 				sur->expand_enable = false;
3888 				set_stripable_selection (s);
3889 				ret = 0;
3890 			}
3891 		} else {
3892 			int_message (path, s->is_selected(), get_address (msg));
3893 			ret = 0;
3894 		}
3895 	}
3896 	else if (!strncmp (sub_path, X_("polarity"), 8)) {
3897 		if (!control_disabled && s->phase_control()) {
3898 			if (argc > (param_1)) {
3899 				if (s_int) {
3900 					for (uint64_t i = 0; i < s->phase_control()->size(); i++) {
3901 						s->phase_control()->set_phase_invert(i, yn ? 1.0 : 0.0);
3902 						/** maybe consider adding a param for which channel
3903 						 * polarity/1 for channel one for example
3904 						 * at that point maybe do in own call
3905 						 */
3906 					}
3907 					ret = 0;
3908 				}
3909 			} else {
3910 				int inv = 0;
3911 				for (uint64_t i = 0; i < s->phase_control()->size(); i++) {
3912 					if (s->phase_control()->inverted (i)) {
3913 						// just check if any are inverted
3914 						inv = 1;
3915 					}
3916 				}
3917 				int_message (path, inv, get_address (msg));
3918 				ret = 0;
3919 			}
3920 		}
3921 	}
3922 	else if (!strncmp (sub_path, X_("name"), 4)) {
3923 		if (argc > (param_1)) {
3924 			if (types[param_1] == 's') {
3925 				if (!control_disabled) {
3926 					s->set_name(strng);
3927 					ret = 0;
3928 				}
3929 			}
3930 		} else {
3931 			text_message (path, s->name(), get_address (msg));
3932 			ret = 0;
3933 		}
3934 	}
3935 	else if (!strncmp (sub_path, X_("group"), 5)) {
3936 		if (!control_disabled) {
3937 			if (rt) {
3938 				RouteGroup *rg = rt->route_group();
3939 				if (argc > (param_1)) {
3940 					if (types[param_1] == 's') {
3941 
3942 
3943 						if (strng == "" || strng == " ") {
3944 							strng = "none";
3945 						}
3946 
3947 						RouteGroup* new_rg = session->route_group_by_name (strng);
3948 						if (rg) {
3949 							string old_group = rg->name();
3950 							if (strng == "none") {
3951 								if (rg->size () == 1) {
3952 									session->remove_route_group (*rg);
3953 								} else {
3954 									rg->remove (rt);
3955 								}
3956 								ret = 0;
3957 							} else if (strng != old_group) {
3958 								if (new_rg) {
3959 									// group exists switch to it
3960 									if (rg->size () == 1) {
3961 										session->remove_route_group (rg);
3962 									} else {
3963 										rg->remove (rt);
3964 									}
3965 									new_rg->add (rt);
3966 								} else {
3967 									rg->set_name (strng);
3968 								}
3969 								ret = 0;
3970 							} else {
3971 								// asked for same group
3972 								ret = 1;
3973 							}
3974 						} else {
3975 							if (strng == "none") {
3976 								ret = 1;
3977 							} else if (new_rg) {
3978 								new_rg->add (rt);
3979 								ret = 0;
3980 							} else {
3981 								// create new group with this strip in it
3982 								RouteGroup* new_rg = new RouteGroup (*session, strng);
3983 								session->add_route_group (new_rg);
3984 								new_rg->add (rt);
3985 								ret = 0;
3986 							}
3987 						}
3988 					}
3989 				} else {
3990 					if (rg) {
3991 						text_message (path, rg->name(), get_address (msg));
3992 					} else {
3993 						text_message (path, "none", get_address (msg));
3994 					}
3995 					ret = 0;
3996 				}
3997 			} else {
3998 				PBD::warning << "OSC: VCAs can not be part of a group." << endmsg;
3999 				///return -1;
4000 			}
4001 		}
4002 	}
4003 	else if (!strncmp (sub_path, X_("comment"), 7)) {
4004 		if (!control_disabled && rt) {
4005 			if (argc > (param_1)) {
4006 				if (types[param_1] == 's') {
4007 					rt->set_comment (strng, this);
4008 					ret = 0;
4009 				}
4010 			} else {
4011 				text_message (path, rt->comment (), get_address (msg));
4012 				ret = 0;
4013 			}
4014 		}
4015 	}
4016 	else if (!strncmp (sub_path, X_("vca"), 3)) {
4017 		boost::shared_ptr<Slavable> slv = boost::dynamic_pointer_cast<Slavable> (s);
4018 		if (!control_disabled && slv) {
4019 			if (argc > (param_1)) {
4020 				string svalue = strng;
4021 				string v_name = svalue.substr (0, svalue.rfind (" ["));
4022 				boost::shared_ptr<VCA> vca = get_vca_by_name (v_name);
4023 				uint32_t ivalue = 0;
4024 				if (!strncmp (sub_path, X_("vca/toggle"), 10)) {
4025 					if (vca) {
4026 						if (s->slaved_to (vca)) {
4027 							slv->unassign (vca);
4028 						} else {
4029 							slv->assign (vca);
4030 						}
4031 						ret = 0;
4032 					}
4033 				}
4034 				else if (strcmp (sub_path, X_("vca")) == 0) {
4035 					if (argc > (param_1 + 1)) {
4036 						if (vca) {
4037 							bool p_good = false;
4038 							if (types[param_1 + 1] == 'i') {
4039 								ivalue = argv[1]->i;
4040 								p_good = true;
4041 							} else if (types[1] == 'f') {
4042 								ivalue = (uint32_t) argv[1]->f;
4043 								p_good = true;
4044 							}
4045 							if (vca && p_good) {
4046 								if (ivalue) {
4047 									slv->assign (vca);
4048 								} else {
4049 									slv->unassign (vca);
4050 								}
4051 								ret = 0;
4052 							} else {
4053 								PBD::warning << "OSC: setting a vca needs both the vca name and it's state" << endmsg;
4054 							}
4055 						}
4056 					}
4057 				}
4058 			} else {
4059 				/// put list of VCAs this strip is controlled by
4060 				_lo_lock.lock ();
4061 				lo_message rmsg = lo_message_new ();
4062 				if (param_1) {
4063 					int sid = 0;
4064 					if (types[0] == 'f') {
4065 						sid = (int) argv[0]->f;
4066 					} else if (types[0] == 'i') {
4067 						sid = argv[0]->i;
4068 					}
4069 					lo_message_add_int32 (rmsg, sid);
4070 				}
4071 				StripableList stripables;
4072 				session->get_stripables (stripables);
4073 				for (StripableList::iterator it = stripables.begin(); it != stripables.end(); ++it) {
4074 					boost::shared_ptr<Stripable> st = *it;
4075 					boost::shared_ptr<VCA> v = boost::dynamic_pointer_cast<VCA> (st);
4076 					if (v && s->slaved_to (v)) {
4077 						lo_message_add_string (rmsg, v->name().c_str());
4078 					}
4079 				}
4080 				lo_send_message (get_address (msg), path, rmsg);
4081 				lo_message_free (rmsg);
4082 				_lo_lock.unlock ();
4083 				ret = 0;
4084 			}
4085 		}
4086 	}
4087 
4088 
4089 	if (ret) {
4090 		int sid = 0;
4091 		_lo_lock.lock ();
4092 		lo_message rmsg = lo_message_new ();
4093 		if (param_1) {
4094 			if (types[0] == 'f') {
4095 				sid = (int) argv[0]->f;
4096 			} else if (types[0] == 'i') {
4097 				sid = argv[0]->i;
4098 			}
4099 			lo_message_add_int32 (rmsg, sid);
4100 		}
4101 		if (types[param_1] == 'f') {
4102 			if (!strncmp (sub_path, X_("gain"), 4)) {
4103 				lo_message_add_float (rmsg, -200);
4104 			} else {
4105 				lo_message_add_float (rmsg, 0);
4106 			}
4107 		} else if (types[param_1] == 'i') {
4108 			lo_message_add_int32 (rmsg, 0);
4109 		} else if (types[param_1] == 's') {
4110 			//lo_message_add_string (rmsg, val.c_str());
4111 			lo_message_add_string (rmsg, " ");
4112 		}
4113 		lo_send_message (get_address (msg), path, rmsg);
4114 		lo_message_free (rmsg);
4115 		_lo_lock.unlock ();
4116 	}
4117 
4118 	return ret;
4119 
4120 	/*
4121 	 * for reference
4122 
4123 		REGISTER_CALLBACK (serv, X_("/strip/sends"), "i", route_get_sends);
4124 		REGISTER_CALLBACK (serv, X_("/strip/send/gain"), "iif", route_set_send_gain_dB);
4125 		REGISTER_CALLBACK (serv, X_("/strip/send/fader"), "iif", route_set_send_fader);
4126 		REGISTER_CALLBACK (serv, X_("/strip/send/enable"), "iif", route_set_send_enable);
4127 		REGISTER_CALLBACK (serv, X_("/strip/receives"), "i", route_get_receives);
4128 
4129 		REGISTER_CALLBACK (serv, X_("/strip/plugin/list"), "i", route_plugin_list);
4130 		REGISTER_CALLBACK (serv, X_("/strip/plugin/parameter"), "iiif", route_plugin_parameter);
4131 		// prints to cerr only
4132 		REGISTER_CALLBACK (serv, X_("/strip/plugin/parameter/print"), "iii", route_plugin_parameter_print);
4133 		REGISTER_CALLBACK (serv, X_("/strip/plugin/activate"), "ii", route_plugin_activate);
4134 		REGISTER_CALLBACK (serv, X_("/strip/plugin/deactivate"), "ii", route_plugin_deactivate);
4135 		REGISTER_CALLBACK (serv, X_("/strip/plugin/descriptor"), "ii", route_plugin_descriptor);
4136 		REGISTER_CALLBACK (serv, X_("/strip/plugin/reset"), "ii", route_plugin_reset);
4137 	*/
4138 
4139 }
4140 
4141 int
strip_state(const char * path,boost::shared_ptr<ARDOUR::Stripable> s,int ssid,lo_message msg)4142 OSC::strip_state (const char *path, boost::shared_ptr<ARDOUR::Stripable> s, int ssid, lo_message msg)
4143 {
4144 	PBD::info << string_compose("OSC: strip_state path:%1", path) << endmsg;
4145 	// some things need the route
4146 	boost::shared_ptr<Route> r = boost::dynamic_pointer_cast<Route> (s);
4147 
4148 	lo_message reply = lo_message_new ();
4149 	if (ssid) {
4150 		// strip number not in path
4151 		lo_message_add_int32 (reply, ssid);
4152 	}
4153 
4154 	if (boost::dynamic_pointer_cast<AudioTrack>(s)) {
4155 		lo_message_add_string (reply, "AT");
4156 	} else if (boost::dynamic_pointer_cast<MidiTrack>(s)) {
4157 		lo_message_add_string (reply, "MT");
4158 	} else if (boost::dynamic_pointer_cast<VCA>(s)) {
4159 		lo_message_add_string (reply, "V");
4160 	} else if (s->is_master()) {
4161 		lo_message_add_string (reply, "MA");
4162 	} else if (s->is_monitor()) {
4163 		lo_message_add_string (reply, "MO");
4164 	} else if (boost::dynamic_pointer_cast<Route>(s) && !boost::dynamic_pointer_cast<Track>(s)) {
4165 		if (!(s->presentation_info().flags() & PresentationInfo::MidiBus)) {
4166 			if (s->is_foldbackbus()) {
4167 				lo_message_add_string (reply, "FB");
4168 			} else {
4169 				lo_message_add_string (reply, "B");
4170 			}
4171 		} else {
4172 			lo_message_add_string (reply, "MB");
4173 		}
4174 	}
4175 
4176 	lo_message_add_string (reply, s->name().c_str());
4177 	if (r) {
4178 		// routes have inputs and outputs
4179 		lo_message_add_int32 (reply, r->n_inputs().n_audio());
4180 		lo_message_add_int32 (reply, r->n_outputs().n_audio());
4181 	} else {
4182 		// non-routes like VCAs don't
4183 		lo_message_add_int32 (reply, -1);
4184 		lo_message_add_int32 (reply, -1);
4185 	}
4186 	if (s->mute_control()) {
4187 		lo_message_add_int32 (reply, s->mute_control()->get_value());
4188 	} else {
4189 		lo_message_add_int32 (reply, -1);
4190 	}
4191 	if (s->solo_control()) {
4192 		lo_message_add_int32 (reply, s->solo_control()->get_value());
4193 	} else {
4194 		lo_message_add_int32 (reply, -1);
4195 	}
4196 	if (s->rec_enable_control()) {
4197 		lo_message_add_int32 (reply, s->rec_enable_control()->get_value());
4198 	} else {
4199 		lo_message_add_int32 (reply, -1);
4200 	}
4201 	lo_send_message (get_address (msg), X_(path), reply);
4202 	lo_message_free (reply);
4203 	return 0;
4204 }
4205 
4206 int
strip_list(lo_message msg)4207 OSC::strip_list (lo_message msg)
4208 {
4209 	OSCSurface *sur = get_surface(get_address (msg), true);
4210 	string temppath = "/strip";
4211 	int ssid = 0;
4212 	for (int n = 0; n < (int) sur->nstrips; ++n) {
4213 		if (sur->feedback[2]) {
4214 			temppath = string_compose ("/strip/%1", n+1);
4215 		} else {
4216 			ssid = n + 1;
4217 		}
4218 
4219 		boost::shared_ptr<Stripable> s = get_strip (n + 1, get_address (msg));
4220 
4221 		if (s) {
4222 			strip_state (temppath.c_str(), s, ssid, msg);
4223 		}
4224 	}
4225 	return 0;
4226 
4227 }
4228 
4229 int
set_automation(const char * path,const char * types,lo_arg ** argv,int argc,lo_message msg)4230 OSC::set_automation (const char *path, const char* types, lo_arg **argv, int argc, lo_message msg)
4231 {
4232 	if (!session) return -1;
4233 
4234 	int ret = 1;
4235 	OSCSurface *sur = get_surface(get_address (msg));
4236 	boost::shared_ptr<Stripable> strp = boost::shared_ptr<Stripable>();
4237 	uint32_t ctr = 0;
4238 	uint32_t aut = 0;
4239 	uint32_t ssid;
4240 	boost::shared_ptr<Send> send = boost::shared_ptr<Send> ();
4241 
4242 	if (argc) {
4243 		if (types[argc - 1] == 'f') {
4244 			aut = (int)argv[argc - 1]->f;
4245 		} else {
4246 			aut = argv[argc - 1]->i;
4247 		}
4248 	}
4249 
4250 	//parse path first to find stripable
4251 	if (!strncmp (path, X_("/strip/"), 7)) {
4252 		// find ssid and stripable
4253 		if (argc > 1) {
4254 			if (types[1] == 'f') {
4255 				ssid = (uint32_t)argv[0]->f;
4256 			} else {
4257 				ssid = argv[0]->i;
4258 			}
4259 			strp = get_strip (ssid, get_address (msg));
4260 		} else {
4261 			ssid = atoi (&(strrchr (path, '/' ))[1]);
4262 			strp = get_strip (ssid, get_address (msg));
4263 		}
4264 		send = get_send (strp, get_address (msg));
4265 		ctr = 7;
4266 	} else if (!strncmp (path, X_("/select/"), 8)) {
4267 		strp = sur->select;
4268 		ctr = 8;
4269 	} else {
4270 		return ret;
4271 	}
4272 	if (strp) {
4273 		boost::shared_ptr<AutomationControl> control = boost::shared_ptr<AutomationControl>();
4274 		// other automatable controls can be added by repeating the next 6.5 lines
4275 		if ((!strncmp (&path[ctr], X_("fader"), 5)) || (!strncmp (&path[ctr], X_("gain"), 4))) {
4276 			if (send) {
4277 				control = send->gain_control ();
4278 			} else if (strp->gain_control ()) {
4279 				control = strp->gain_control ();
4280 			} else {
4281 				PBD::warning << "No fader for this strip" << endmsg;
4282 			}
4283 		} else if (!strncmp (&path[ctr], X_("pan"), 3)) {
4284 			if (send) {
4285 				if (send->panner_linked_to_route () || !send->has_panner ()) {
4286 					PBD::warning << "Send panner not available" << endmsg;
4287 				} else {
4288 					boost::shared_ptr<Delivery> _send_del = boost::dynamic_pointer_cast<Delivery> (send);
4289 					boost::shared_ptr<Pannable> pannable = _send_del->panner()->pannable();
4290 					if (pannable->pan_azimuth_control) {
4291 						control = pannable->pan_azimuth_control;
4292 					} else {
4293 						PBD::warning << "Automation not available for " << path << endmsg;
4294 					}
4295 				}
4296 			} else if (strp->pan_azimuth_control ()) {
4297 					control = strp->pan_azimuth_control ();
4298 			} else {
4299 				PBD::warning << "Automation not available for " << path << endmsg;
4300 			}
4301 
4302 		} else if (!strncmp (&path[ctr], X_("trimdB"), 6)) {
4303 			if (send) {
4304 				PBD::warning << "Send trim not available" << endmsg;
4305 			} else if (strp->trim_control ()) {
4306 				control = strp->trim_control ();
4307 			} else {
4308 				PBD::warning << "No trim for this strip" << endmsg;
4309 			}
4310 		} else if (!strncmp (&path[ctr], X_("mute"), 4)) {
4311 			if (send) {
4312 				PBD::warning << "Send mute not automatable" << endmsg;
4313 			} else if (strp->mute_control ()) {
4314 				control = strp->mute_control ();
4315 			} else {
4316 				PBD::warning << "No trim for this strip" << endmsg;
4317 			}
4318 
4319 		} else {
4320 			PBD::warning << "Automation not available for " << path << endmsg;
4321 		}
4322 
4323 		if (control) {
4324 
4325 			switch (aut) {
4326 				case 0:
4327 					control->set_automation_state (ARDOUR::Off);
4328 					ret = 0;
4329 					break;
4330 				case 1:
4331 					control->set_automation_state (ARDOUR::Play);
4332 					ret = 0;
4333 					break;
4334 				case 2:
4335 					control->set_automation_state (ARDOUR::Write);
4336 					ret = 0;
4337 					break;
4338 				case 3:
4339 					control->set_automation_state (ARDOUR::Touch);
4340 					ret = 0;
4341 					break;
4342 				case 4:
4343 					control->set_automation_state (ARDOUR::Latch);
4344 					ret = 0;
4345 					break;
4346 				default:
4347 					break;
4348 			}
4349 		}
4350 	}
4351 
4352 	return ret;
4353 }
4354 
4355 int
touch_detect(const char * path,const char * types,lo_arg ** argv,int argc,lo_message msg)4356 OSC::touch_detect (const char *path, const char* types, lo_arg **argv, int argc, lo_message msg)
4357 {
4358 	if (!session) return -1;
4359 
4360 	int ret = 1;
4361 	OSCSurface *sur = get_surface(get_address (msg));
4362 	boost::shared_ptr<Stripable> strp = boost::shared_ptr<Stripable>();
4363 	boost::shared_ptr<Send> send = boost::shared_ptr<Send> ();
4364 	uint32_t ctr = 0;
4365 	uint32_t touch = 0;
4366 	uint32_t ssid;
4367 
4368 	if (argc) {
4369 		if (types[argc - 1] == 'f') {
4370 			touch = (int)argv[argc - 1]->f;
4371 		} else {
4372 			touch = argv[argc - 1]->i;
4373 		}
4374 	}
4375 
4376 	//parse path first to find stripable
4377 	if (!strncmp (path, X_("/strip/"), 7)) {
4378 		// find ssid and stripable
4379 		if (argc > 1) {
4380 			if (types[0] == 'f') {
4381 				ssid = (uint32_t)argv[0]->f;
4382 			} else {
4383 				ssid = argv[0]->i;
4384 			}
4385 			strp = get_strip (ssid, get_address (msg));
4386 		} else {
4387 			ssid = atoi (&(strrchr (path, '/' ))[1]);
4388 			strp = get_strip (ssid, get_address (msg));
4389 		}
4390 		send = get_send (strp, get_address (msg));
4391 		ctr = 7;
4392 	} else if (!strncmp (path, X_("/select/"), 8)) {
4393 		strp = sur->select;
4394 		ctr = 8;
4395 	} else {
4396 		return ret;
4397 	}
4398 	if (strp) {
4399 		boost::shared_ptr<AutomationControl> control = boost::shared_ptr<AutomationControl>();
4400 		// other automatable controls can be added by repeating the next 6.5 lines
4401 		if ((!strncmp (&path[ctr], X_("fader"), 5)) || (!strncmp (&path[ctr], X_("gain"), 4))) {
4402 			if (strp->gain_control ()) {
4403 				control = strp->gain_control ();
4404 			} else {
4405 				PBD::warning << "No fader for this strip" << endmsg;
4406 			}
4407 			if (send) {
4408 				control = send->gain_control ();
4409 			}
4410 		} else if (!strncmp (&path[ctr], X_("pan"), 3)) {
4411 			if (send) {
4412 				if (send->panner_linked_to_route () || !send->has_panner ()) {
4413 					PBD::warning << "Send panner not available" << endmsg;
4414 				} else {
4415 					boost::shared_ptr<Delivery> _send_del = boost::dynamic_pointer_cast<Delivery> (send);
4416 					boost::shared_ptr<Pannable> pannable = _send_del->panner()->pannable();
4417 					if (!strncmp (&path[ctr], X_("pan_stereo_position"), 19)) {
4418 						if (pannable->pan_azimuth_control) {
4419 							control = pannable->pan_azimuth_control;
4420 						} else {
4421 							PBD::warning << "Automation not available for " << path << endmsg;
4422 						}
4423 					} else if (!strncmp (&path[ctr], X_("pan_stereo_width"), 16)) {
4424 						if (strp->pan_width_control ()) {
4425 								control = strp->pan_width_control ();
4426 						} else {
4427 							PBD::warning << "Automation not available for " << path << endmsg;
4428 						}
4429 					}
4430 				}
4431 			}
4432 		} else if (!strncmp (&path[ctr], X_("trimdB"), 6)) {
4433 			if (send) {
4434 				PBD::warning << "Send trim not available" << endmsg;
4435 			} else if (strp->trim_control ()) {
4436 				control = strp->trim_control ();
4437 			} else {
4438 				PBD::warning << "No trim for this strip" << endmsg;
4439 			}
4440 		} else if (!strncmp (&path[ctr], X_("mute"), 4)) {
4441 			if (send) {
4442 				PBD::warning << "Send mute not automatable" << endmsg;
4443 			} else if (strp->mute_control ()) {
4444 				control = strp->mute_control ();
4445 			} else {
4446 				PBD::warning << "No trim for this strip" << endmsg;
4447 			}
4448 
4449 		} else {
4450 			PBD::warning << "Automation not available for " << path << endmsg;
4451 		}
4452 
4453 		if (control) {
4454 			if (touch) {
4455 				//start touch
4456 				control->start_touch (control->session().transport_sample());
4457 				ret = 0;
4458 			} else {
4459 				// end touch
4460 				control->stop_touch (control->session().transport_sample());
4461 				ret = 0;
4462 			}
4463 			// just in case some crazy surface starts sending control values before touch
4464 			FakeTouchMap::iterator x = _touch_timeout.find(control);
4465 			if (x != _touch_timeout.end()) {
4466 				_touch_timeout.erase (x);
4467 			}
4468 		}
4469 	}
4470 
4471 	return ret;
4472 }
4473 
4474 int
fake_touch(boost::shared_ptr<ARDOUR::AutomationControl> ctrl)4475 OSC::fake_touch (boost::shared_ptr<ARDOUR::AutomationControl> ctrl)
4476 {
4477 	if (ctrl) {
4478 		//start touch
4479 		if (ctrl->automation_state() == Touch && !ctrl->touching ()) {
4480 		ctrl->start_touch (ctrl->session().transport_sample());
4481 		_touch_timeout[ctrl] = 10;
4482 		}
4483 	}
4484 
4485 	return 0;
4486 }
4487 
4488 int
spill(const char * path,const char * types,lo_arg ** argv,int argc,lo_message msg)4489 OSC::spill (const char *path, const char* types, lo_arg **argv, int argc, lo_message msg)
4490 {
4491 	/*
4492 	 * spill should have the form of:
4493 	 * /select/spill (may have i or f keypress/release)
4494 	 * /strip/spill i (may have keypress and i may be inline)
4495 	 */
4496 	if (!session || argc > 1) return -1;
4497 
4498 	int ret = 1;
4499 	OSCSurface *sur = get_surface(get_address (msg));
4500 	boost::shared_ptr<Stripable> strp = boost::shared_ptr<Stripable>();
4501 	uint32_t value = 0;
4502 	OSCTempMode new_mode = TempOff;
4503 
4504 	if (argc) {
4505 		if (types[0] == 'f') {
4506 			value = (int)argv[0]->f;
4507 		} else {
4508 			value = argv[0]->i;
4509 		}
4510 		if (!value) {
4511 			// key release ignore
4512 			return 0;
4513 		}
4514 	}
4515 
4516 	//parse path first to find stripable
4517 	if (!strncmp (path, X_("/strip/"), 7)) {
4518 		/*
4519 		 * we don't know if value is press or ssid
4520 		 * so we have to check if the last / has an int after it first
4521 		 * if not then we use value
4522 		 */
4523 		uint32_t ssid = 0;
4524 		ssid = atoi (&(strrchr (path, '/' ))[1]);
4525 		if (!ssid) {
4526 			ssid = value;
4527 		}
4528 		strp = get_strip (ssid, get_address (msg));
4529 	} else if (!strncmp (path, X_("/select/"), 8)) {
4530 		strp = sur->select;
4531 	} else {
4532 		return ret;
4533 	}
4534 	if (strp) {
4535 		boost::shared_ptr<Route> rt = boost::dynamic_pointer_cast<Route> (strp);
4536 		boost::shared_ptr<VCA> v = boost::dynamic_pointer_cast<VCA> (strp);
4537 		if (strstr (path, X_("/vca")) || v) {
4538 			//strp must be a VCA
4539 			if (v) {
4540 				new_mode = VCAOnly;
4541 			} else {
4542 				return ret;
4543 			}
4544 		} else
4545 		if (strstr (path, X_("/group"))) {
4546 			//strp must be in a group
4547 			if (rt) {
4548 				RouteGroup *rg = rt->route_group();
4549 				if (rg) {
4550 					new_mode = GroupOnly;
4551 				} else {
4552 					return ret;
4553 				}
4554 			}
4555 		} else
4556 		if (strstr (path, X_("/bus"))) {
4557 			//strp must be a bus with either sends or no inputs
4558 			if (rt) {
4559 				if (!rt->is_track () && rt->can_solo ()) {
4560 					new_mode = BusOnly;
4561 				}
4562 			}
4563 		} else {
4564 			// decide by auto
4565 			// vca should never get here
4566 			if (rt->is_track ()) {
4567 				if (rt->route_group()) {
4568 					new_mode = GroupOnly;
4569 				}
4570 			} else if (!rt->is_track () && rt->can_solo ()) {
4571 						new_mode = BusOnly;
4572 			}
4573 		}
4574 		if (new_mode) {
4575 			sur->temp_mode = new_mode;
4576 			sur->temp_master = strp;
4577 			set_temp_mode (get_address (msg));
4578 			set_bank (1, msg);
4579 			return 0;
4580 		}
4581 
4582 	}
4583 	return ret;
4584 }
4585 
4586 int
sel_new_personal_send(char * foldback,lo_message msg)4587 OSC::sel_new_personal_send (char *foldback, lo_message msg)
4588 {
4589 	OSCSurface *sur = get_surface(get_address (msg));
4590 	boost::shared_ptr<Stripable> s;
4591 	s = sur->select;
4592 	boost::shared_ptr<Route> rt = boost::shared_ptr<Route> ();
4593 	if (s) {
4594 		rt = boost::dynamic_pointer_cast<Route> (s);
4595 		if (!rt) {
4596 			PBD::warning << "OSC: can not send from VCAs." << endmsg;
4597 			return -1;
4598 		}
4599 	}
4600 	/* if a foldbackbus called foldback exists use it
4601 	 * other wise create it. Then create a foldback send from
4602 	 * this route to that bus.
4603 	 */
4604 	string foldbackbus = foldback;
4605 	string foldback_name = foldbackbus;
4606 	if (foldbackbus.find ("- FB") == string::npos) {
4607 		foldback_name = string_compose ("%1 - FB", foldbackbus);
4608 	}
4609 	boost::shared_ptr<Route> lsn_rt = session->route_by_name (foldback_name);
4610 	if (!lsn_rt) {
4611 		// doesn't exist but check if raw name does and is foldbackbus
4612 		boost::shared_ptr<Route> raw_rt = session->route_by_name (foldbackbus);
4613 		if (raw_rt && raw_rt->is_foldbackbus()) {
4614 			lsn_rt = raw_rt;
4615 		} else {
4616 			// create the foldbackbus
4617 			RouteList list = session->new_audio_route (1, 1, 0, 1, foldback_name, PresentationInfo::FoldbackBus, (uint32_t) -1);
4618 			lsn_rt = *(list.begin());
4619 			lsn_rt->presentation_info().set_hidden (true);
4620 			session->set_dirty();
4621 		}
4622 	}
4623 	if (lsn_rt) {
4624 		//boost::shared_ptr<Route> rt_send = ;
4625 		if (rt && (lsn_rt != rt)) {
4626 			// make sure there isn't one already
4627 			bool s_only = true;
4628 			if (!rt->feeds (lsn_rt, &s_only)) {
4629 				// create send
4630 				rt->add_foldback_send (lsn_rt, false);
4631 				//boost::shared_ptr<Send> snd = rt->internal_send_for (aux);
4632 				session->dirty ();
4633 				return 0;
4634 			} else {
4635 				PBD::warning << "OSC: new_send - duplicate send, ignored." << endmsg;
4636 			}
4637 		} else {
4638 			PBD::warning << "OSC: new_send - can't send to self." << endmsg;
4639 		}
4640 	} else {
4641 		PBD::warning << "OSC: new_send - no FoldbackBus to send to." << endmsg;
4642 	}
4643 
4644 	return -1;
4645 }
4646 
4647 int
_strip_select(boost::shared_ptr<Stripable> s,lo_address addr)4648 OSC::_strip_select (boost::shared_ptr<Stripable> s, lo_address addr)
4649 {
4650 	if (!session) {
4651 		return -1;
4652 	}
4653 	OSCSurface *sur = get_surface(addr, true);
4654 	return _strip_select2 (s, sur, addr);
4655 }
4656 
4657 int
_strip_select2(boost::shared_ptr<Stripable> s,OSCSurface * sur,lo_address addr)4658 OSC::_strip_select2 (boost::shared_ptr<Stripable> s, OSCSurface *sur, lo_address addr)
4659 {
4660 	// this allows get_surface  to call this part without calling itself
4661 	boost::weak_ptr<Stripable> o_sel = sur->select;
4662 	boost::shared_ptr<Stripable> old_sel= o_sel.lock ();
4663 	boost::weak_ptr<Stripable> o_expand = sur->expand_strip;
4664 	boost::shared_ptr<Stripable> old_expand= o_expand.lock ();
4665 
4666 	// we got a null strip check that old strips are valid
4667 	if (!s) {
4668 		if (old_expand && sur->expand_enable) {
4669 			sur->expand = get_sid (old_expand, addr);
4670 			if (sur->strip_types[11] || sur->expand) {
4671 				s = old_expand;
4672 			} else {
4673 				sur->expand_strip = boost::shared_ptr<Stripable> ();
4674 			}
4675 		}
4676 	}
4677 	if (!s) {
4678 		sur->expand = 0;
4679 		sur->expand_enable = false;
4680 		if (ControlProtocol::first_selected_stripable()) {
4681 			s = ControlProtocol::first_selected_stripable();
4682 		} else {
4683 			s = session->master_out ();
4684 		}
4685 		_select = s;
4686 	}
4687 	if (s != old_sel) {
4688 		sur->select = s;
4689 	}
4690 	bool sends;
4691 	uint32_t nsends  = 0;
4692 	do {
4693 		sends = false;
4694 		if (s->send_level_controllable (nsends)) {
4695 			sends = true;
4696 			nsends++;
4697 		}
4698 	} while (sends);
4699 	sur->nsends = nsends;
4700 
4701 	s->DropReferences.connect (*this, MISSING_INVALIDATOR, boost::bind (&OSC::recalcbanks, this), this);
4702 
4703 	OSCSelectObserver* so = dynamic_cast<OSCSelectObserver*>(sur->sel_obs);
4704 	if (sur->feedback[13]) {
4705 		if (so != 0) {
4706 			so->refresh_strip (s, nsends, sur->gainmode, true);
4707 		} else {
4708 			OSCSelectObserver* sel_fb = new OSCSelectObserver (*this, *session, sur);
4709 			sur->sel_obs = sel_fb;
4710 		}
4711 		sur->sel_obs->set_expand (sur->expand_enable);
4712 	} else {
4713 		if (so != 0) {
4714 			delete so;
4715 			sur->sel_obs = 0;
4716 		}
4717 	}
4718 	if (sur->feedback[0] || sur->feedback[1]) {
4719 		uint32_t obs_expand = 0;
4720 		if (sur->expand_enable) {
4721 			sur->expand = get_sid (s, addr);
4722 			obs_expand = sur->expand;
4723 		} else {
4724 			obs_expand = 0;
4725 		}
4726 		for (uint32_t i = 0; i < sur->observers.size(); i++) {
4727 			sur->observers[i]->set_expand (obs_expand);
4728 		}
4729 	}
4730 	// need to set monitor for processor changed signal (for paging)
4731 	string address = lo_address_get_url (addr);
4732 	boost::shared_ptr<Route> r = boost::dynamic_pointer_cast<Route>(s);
4733 	if (r) {
4734 		r->processors_changed.connect  (sur->proc_connection, MISSING_INVALIDATOR, boost::bind (&OSC::processor_changed, this, address), this);
4735 		_sel_plugin (sur->plugin_id, addr);
4736 	}
4737 
4738 	return 0;
4739 }
4740 
4741 void
processor_changed(string address)4742 OSC::processor_changed (string address)
4743 {
4744 	lo_address addr = lo_address_new_from_url (address.c_str());
4745 	OSCSurface *sur = get_surface (addr);
4746 	_sel_plugin (sur->plugin_id, addr);
4747 	if (sur->sel_obs) {
4748 		sur->sel_obs->renew_sends ();
4749 		sur->sel_obs->eq_restart (-1);
4750 	}
4751 }
4752 
4753 int
sel_expand(uint32_t state,lo_message msg)4754 OSC::sel_expand (uint32_t state, lo_message msg)
4755 {
4756 	OSCSurface *sur = get_surface(get_address (msg));
4757 	boost::shared_ptr<Stripable> s;
4758 	if (!sur->expand_strip) {
4759 		state = 0;
4760 		float_message (X_("/select/expand"), 0.0, get_address (msg));
4761 	}
4762 	if (state) {
4763 		sur->expand_enable = (bool) state;
4764 		s = boost::shared_ptr<Stripable> ();
4765 	} else {
4766 		sur->expand_enable = false;
4767 		s = boost::shared_ptr<Stripable> ();
4768 	}
4769 
4770 	return _strip_select (s, get_address (msg));
4771 }
4772 
4773 int
sel_previous(lo_message msg)4774 OSC::sel_previous (lo_message msg)
4775 {
4776 	return sel_delta (-1, msg);
4777 }
4778 
4779 int
sel_next(lo_message msg)4780 OSC::sel_next (lo_message msg)
4781 {
4782 	return sel_delta (1, msg);
4783 }
4784 
4785 int
sel_delta(int delta,lo_message msg)4786 OSC::sel_delta (int delta, lo_message msg)
4787 {
4788 	if (!delta) {
4789 		return 0;
4790 	}
4791 	OSCSurface *sur = get_surface(get_address (msg));
4792 	Sorted sel_strips;
4793 	sel_strips = sur->strips;
4794 	// the current selected strip _should_ be in sel_strips
4795 	uint32_t nstps = sel_strips.size ();
4796 	if (!nstps) {
4797 		return -1;
4798 	}
4799 	boost::shared_ptr<Stripable> new_sel = boost::shared_ptr<Stripable> ();
4800 	boost::weak_ptr<Stripable> o_sel = sur->select;
4801 	boost::shared_ptr<Stripable> old_sel= o_sel.lock ();
4802 	for (uint32_t i = 0; i < nstps; i++) {
4803 		if (old_sel == sel_strips[i]) {
4804 			if (i && delta < 0) {
4805 				// i is > 0 and delta is -1
4806 				new_sel = sel_strips[i - 1];
4807 			} else if ((i + 1) < nstps && delta > 0) {
4808 				// i is at least 1 less than greatest and delta = 1
4809 				new_sel = sel_strips[i + 1];
4810 			} else if ((i + 1) >= nstps && delta > 0) {
4811 				// i is greatest strip and delta 1
4812 				new_sel = sel_strips[0];
4813 			} else if (!i && delta < 0) {
4814 				// i = 0 and delta -1
4815 				new_sel = sel_strips[nstps - 1];
4816 			} else {
4817 				// should not happen
4818 				return -1;
4819 			}
4820 		}
4821 	}
4822 	if (!new_sel) {
4823 		// our selected strip has vanished use the first one
4824 		new_sel = sel_strips[0];
4825 	}
4826 	if (new_sel) {
4827 		if (!sur->expand_enable) {
4828 			set_stripable_selection (new_sel);
4829 		} else {
4830 			sur->expand_strip = new_sel;
4831 			_strip_select (new_sel, get_address (msg));
4832 		}
4833 		return 0;
4834 	}
4835 	return -1;
4836 }
4837 
4838 int
route_set_send_gain_dB(int ssid,int id,float val,lo_message msg)4839 OSC::route_set_send_gain_dB (int ssid, int id, float val, lo_message msg)
4840 {
4841 	if (!session) {
4842 		return -1;
4843 	}
4844 	boost::shared_ptr<Stripable> s = get_strip (ssid, get_address (msg));
4845 	OSCSurface *sur = get_surface(get_address (msg));
4846 	float abs;
4847 	if (s) {
4848 		if (id > 0) {
4849 			--id;
4850 		}
4851 		if (val < -192) {
4852 			abs = 0;
4853 		} else {
4854 			abs = dB_to_coefficient (val);
4855 		}
4856 		if (s->send_level_controllable (id)) {
4857 			s->send_level_controllable (id)->set_value (abs, sur->usegroup);
4858 			return 0;
4859 		}
4860 	}
4861 	return 0;
4862 }
4863 
4864 int
route_set_send_fader(int ssid,int id,float val,lo_message msg)4865 OSC::route_set_send_fader (int ssid, int id, float val, lo_message msg)
4866 {
4867 	if (!session) {
4868 		return -1;
4869 	}
4870 	boost::shared_ptr<Stripable> s = get_strip (ssid, get_address (msg));
4871 	OSCSurface *sur = get_surface(get_address (msg));
4872 	float abs;
4873 	if (s) {
4874 
4875 		if (id > 0) {
4876 			--id;
4877 		}
4878 
4879 		if (s->send_level_controllable (id)) {
4880 			abs = s->send_level_controllable(id)->interface_to_internal (val);
4881 			s->send_level_controllable (id)->set_value (abs, sur->usegroup);
4882 			return 0;
4883 		}
4884 	}
4885 	return 0;
4886 }
4887 
4888 int
sel_sendgain(int id,float val,lo_message msg)4889 OSC::sel_sendgain (int id, float val, lo_message msg)
4890 {
4891 	OSCSurface *sur = get_surface(get_address (msg));
4892 	if (sur->send_page_size && (id > (int)sur->send_page_size)) {
4893 		return float_message_with_id (X_("/select/send_gain"), id, -193, sur->feedback[2], get_address (msg));
4894 	}
4895 	boost::shared_ptr<Stripable> s;
4896 	s = sur->select;
4897 	float abs;
4898 	int send_id = 0;
4899 	if (s) {
4900 		if (id > 0) {
4901 			send_id = id - 1;
4902 		}
4903 		if (val < -192) {
4904 			abs = 0;
4905 		} else {
4906 			abs = dB_to_coefficient (val);
4907 		}
4908 		if (sur->send_page_size) {
4909 			send_id = send_id + ((sur->send_page - 1) * sur->send_page_size);
4910 		}
4911 		if (s->send_level_controllable (send_id)) {
4912 			s->send_level_controllable (send_id)->set_value (abs, PBD::Controllable::NoGroup);
4913 			return 0;
4914 		}
4915 	}
4916 	return float_message_with_id (X_("/select/send_gain"), id, -193, sur->feedback[2], get_address (msg));
4917 }
4918 
4919 int
sel_sendfader(int id,float val,lo_message msg)4920 OSC::sel_sendfader (int id, float val, lo_message msg)
4921 {
4922 	OSCSurface *sur = get_surface(get_address (msg));
4923 	if (sur->send_page_size && (id > (int)sur->send_page_size)) {
4924 		return float_message_with_id (X_("/select/send_fader"), id, 0, sur->feedback[2], get_address (msg));
4925 	}
4926 	boost::shared_ptr<Stripable> s;
4927 	s = sur->select;
4928 	float abs;
4929 	int send_id = 0;
4930 	if (s) {
4931 
4932 		if (id > 0) {
4933 			send_id = id - 1;
4934 		}
4935 		if (sur->send_page_size) {
4936 			send_id = send_id + ((sur->send_page - 1) * sur->send_page_size);
4937 		}
4938 
4939 		if (s->send_level_controllable (send_id)) {
4940 			abs = s->send_level_controllable(send_id)->interface_to_internal (val);
4941 			s->send_level_controllable (send_id)->set_value (abs, PBD::Controllable::NoGroup);
4942 			return 0;
4943 		}
4944 	}
4945 	return float_message_with_id (X_("/select/send_fader"), id, 0, sur->feedback[2], get_address (msg));
4946 }
4947 
4948 int
route_set_send_enable(int ssid,int sid,float val,lo_message msg)4949 OSC::route_set_send_enable (int ssid, int sid, float val, lo_message msg)
4950 {
4951 	if (!session) {
4952 		return -1;
4953 	}
4954 	boost::shared_ptr<Stripable> s = get_strip (ssid, get_address (msg));
4955 	OSCSurface *sur = get_surface(get_address (msg));
4956 
4957 	if (s) {
4958 
4959 		/* revert to zero-based counting */
4960 
4961 		if (sid > 0) {
4962 			--sid;
4963 		}
4964 
4965 		if (s->send_enable_controllable (sid)) {
4966 			s->send_enable_controllable (sid)->set_value (val, sur->usegroup);
4967 			return 0;
4968 		}
4969 
4970 		if (s->send_level_controllable (sid)) {
4971 			boost::shared_ptr<Route> r = boost::dynamic_pointer_cast<Route> (s);
4972 			if (!r) {
4973 				return 0;
4974 			}
4975 			boost::shared_ptr<Send> snd = boost::dynamic_pointer_cast<Send> (r->nth_send(sid));
4976 			if (snd) {
4977 				if (val) {
4978 					snd->activate();
4979 				} else {
4980 					snd->deactivate();
4981 				}
4982 			}
4983 			return 0;
4984 		}
4985 
4986 	}
4987 
4988 	return -1;
4989 }
4990 
4991 int
sel_sendenable(int id,float val,lo_message msg)4992 OSC::sel_sendenable (int id, float val, lo_message msg)
4993 {
4994 	OSCSurface *sur = get_surface(get_address (msg));
4995 	if (sur->send_page_size && (id > (int)sur->send_page_size)) {
4996 		return float_message_with_id (X_("/select/send_enable"), id, 0, sur->feedback[2], get_address (msg));
4997 	}
4998 	boost::shared_ptr<Stripable> s;
4999 	s = sur->select;
5000 	int send_id = 0;
5001 	if (s) {
5002 		if (id > 0) {
5003 			send_id = id - 1;
5004 		}
5005 		if (sur->send_page_size) {
5006 			send_id = send_id + ((sur->send_page - 1) * sur->send_page_size);
5007 		}
5008 		if (s->send_enable_controllable (send_id)) {
5009 			s->send_enable_controllable (send_id)->set_value (val, PBD::Controllable::NoGroup);
5010 			return 0;
5011 		}
5012 		if (s->send_level_controllable (send_id)) {
5013 			boost::shared_ptr<Route> r = boost::dynamic_pointer_cast<Route> (s);
5014 			if (!r) {
5015 				// should never get here
5016 				return float_message_with_id (X_("/select/send_enable"), id, 0, sur->feedback[2], get_address (msg));
5017 			}
5018 			boost::shared_ptr<Send> snd = boost::dynamic_pointer_cast<Send> (r->nth_send(send_id));
5019 			if (snd) {
5020 				if (val) {
5021 					snd->activate();
5022 				} else {
5023 					snd->deactivate();
5024 				}
5025 			}
5026 			return 0;
5027 		}
5028 	}
5029 	return float_message_with_id (X_("/select/send_enable"), id, 0, sur->feedback[2], get_address (msg));
5030 }
5031 
5032 int
sel_master_send_enable(int state,lo_message msg)5033 OSC::sel_master_send_enable (int state, lo_message msg)
5034 {
5035 	OSCSurface *sur = get_surface(get_address (msg));
5036 	boost::shared_ptr<Stripable> s;
5037 	s = sur->select;
5038 	if (s) {
5039 		if (s->master_send_enable_controllable ()) {
5040 			s->master_send_enable_controllable()->set_value (state, PBD::Controllable::NoGroup);
5041 			return 0;
5042 		}
5043 	}
5044 	return float_message (X_("/select/master_send_enable"), 0, get_address(msg));
5045 }
5046 
5047 int
select_plugin_parameter(const char * path,const char * types,lo_arg ** argv,int argc,lo_message msg)5048 OSC::select_plugin_parameter (const char *path, const char* types, lo_arg **argv, int argc, lo_message msg) {
5049 	OSCSurface *sur = get_surface(get_address (msg));
5050 	int paid;
5051 	uint32_t piid = sur->plugin_id;
5052 	float value = 0;
5053 	if (argc > 1) {
5054 		// no inline args
5055 		if (argc == 2) {
5056 			// change parameter in already selected plugin
5057 			if (types[0]  == 'f') {
5058 				paid = (int) argv[0]->f;
5059 			} else {
5060 				paid = argv[0]->i;
5061 			}
5062 			value = argv[1]->f;
5063 		} else if (argc == 3) {
5064 			if (types[0] == 'f') {
5065 				piid = (int) argv[0]->f;
5066 			} else {
5067 				piid = argv[0]->i;
5068 			}
5069 			_sel_plugin (piid, get_address (msg));
5070 			if (types[1] == 'f') {
5071 				paid = (int) argv[1]->f;
5072 			} else {
5073 				paid = argv[1]->i;
5074 			}
5075 			value = argv[2]->f;
5076 		} else if (argc > 3) {
5077 			PBD::warning << "OSC: Too many parameters: " << argc << endmsg;
5078 			return -1;
5079 		}
5080 	} else if (argc) {
5081 		const char * par = strstr (&path[25], "/");
5082 		if (par) {
5083 			piid = atoi (&path[25]);
5084 			_sel_plugin (piid, get_address (msg));
5085 			paid = atoi (&par[1]);
5086 			value = argv[0]->f;
5087 			// we have plugin id too
5088 		} else {
5089 			// just parameter
5090 			paid = atoi (&path[25]);
5091 			value = argv[0]->f;
5092 		}
5093 	} else {
5094 		PBD::warning << "OSC: Must have parameters." << endmsg;
5095 		return -1;
5096 	}
5097 	if (!piid || piid > sur->plugins.size ()) {
5098 		return float_message_with_id (X_("/select/plugin/parameter"), paid, 0, sur->feedback[2], get_address (msg));
5099 	}
5100 	if (sur->plug_page_size && (paid > (int)sur->plug_page_size)) {
5101 		return float_message_with_id (X_("/select/plugin/parameter"), paid, 0, sur->feedback[2], get_address (msg));
5102 	}
5103 	boost::shared_ptr<Stripable> s = sur->select;
5104 	boost::shared_ptr<Route> r = boost::dynamic_pointer_cast<Route>(s);
5105 	if (!r) {
5106 		return 1;
5107 	}
5108 
5109 	boost::shared_ptr<Processor> proc = r->nth_plugin (sur->plugins[sur->plugin_id - 1]);
5110 	boost::shared_ptr<PluginInsert> pi;
5111 	if (!(pi = boost::dynamic_pointer_cast<PluginInsert>(proc))) {
5112 		return 1;
5113 	}
5114 	boost::shared_ptr<ARDOUR::Plugin> pip = pi->plugin();
5115 	// paid is paged parameter convert to absolute
5116 	int parid = paid + (int)sur->plug_page - 1;
5117 	if (parid > (int) sur->plug_params.size ()) {
5118 		if (sur->feedback[13]) {
5119 			float_message_with_id (X_("/select/plugin/parameter"), paid, 0, sur->feedback[2], get_address (msg));
5120 		}
5121 		return 0;
5122 	}
5123 
5124 	bool ok = false;
5125 	uint32_t controlid = pip->nth_parameter(sur->plug_params[parid - 1], ok);
5126 	if (!ok) {
5127 		return 1;
5128 	}
5129 	ParameterDescriptor pd;
5130 	pip->get_parameter_descriptor(controlid, pd);
5131 	if ( pip->parameter_is_input(controlid) || pip->parameter_is_control(controlid) ) {
5132 		boost::shared_ptr<AutomationControl> c = pi->automation_control(Evoral::Parameter(PluginAutomation, 0, controlid));
5133 		if (c) {
5134 			if (pd.integer_step && pd.upper == 1) {
5135 				if (c->get_value () && value < 1.0) {
5136 					c->set_value (0, PBD::Controllable::NoGroup);
5137 				} else if (!c->get_value () && value) {
5138 					c->set_value (1, PBD::Controllable::NoGroup);
5139 				}
5140 			} else {
5141 				c->set_value (c->interface_to_internal (value), PBD::Controllable::NoGroup);
5142 			}
5143 			return 0;
5144 		}
5145 	}
5146 	return 1;
5147 }
5148 
5149 int
sel_plugin_activate(float state,lo_message msg)5150 OSC::sel_plugin_activate (float state, lo_message msg)
5151 {
5152 	if (!session) {
5153 		return -1;
5154 	}
5155 	OSCSurface *sur = get_surface(get_address (msg));
5156 	if (sur->plugins.size() > 0) {
5157 		boost::shared_ptr<Stripable> s = sur->select;
5158 
5159 		boost::shared_ptr<Route> r = boost::dynamic_pointer_cast<Route> (s);
5160 
5161 		if (r) {
5162 			boost::shared_ptr<Processor> redi=r->nth_plugin (sur->plugins[sur->plugin_id -1]);
5163 			if (redi) {
5164 				boost::shared_ptr<PluginInsert> pi;
5165 				if ((pi = boost::dynamic_pointer_cast<PluginInsert>(redi))) {
5166 					if(state > 0) {
5167 						pi->activate();
5168 					} else {
5169 						pi->deactivate();
5170 					}
5171 					return 0;
5172 				}
5173 			}
5174 		}
5175 	}
5176 	float_message (X_("/select/plugin/activate"), 0, get_address (msg));
5177 	PBD::warning << "OSC: Select has no Plugin." << endmsg;
5178 	return 0;
5179 }
5180 
5181 int
route_plugin_list(int ssid,lo_message msg)5182 OSC::route_plugin_list (int ssid, lo_message msg) {
5183 	if (!session) {
5184 		return -1;
5185 	}
5186 
5187 	boost::shared_ptr<Route> r = boost::dynamic_pointer_cast<Route>(get_strip (ssid, get_address (msg)));
5188 
5189 	if (!r) {
5190 		PBD::error << "OSC: Invalid Remote Control ID '" << ssid << "'" << endmsg;
5191 		return -1;
5192 	}
5193 	int piid = 0;
5194 
5195 	lo_message reply = lo_message_new ();
5196 	lo_message_add_int32 (reply, ssid);
5197 
5198 
5199 	for (;;) {
5200 		boost::shared_ptr<Processor> redi = r->nth_plugin(piid);
5201 		if ( !redi ) {
5202 			break;
5203 		}
5204 
5205 		boost::shared_ptr<PluginInsert> pi;
5206 
5207 		if (!(pi = boost::dynamic_pointer_cast<PluginInsert>(redi))) {
5208 			PBD::error << "OSC: given processor # " << piid << " on RID '" << ssid << "' is not a Plugin." << endmsg;
5209 			continue;
5210 		}
5211 		lo_message_add_int32 (reply, piid + 1);
5212 
5213 		boost::shared_ptr<ARDOUR::Plugin> pip = pi->plugin();
5214 		lo_message_add_string (reply, pip->name());
5215 		lo_message_add_int32(reply, redi->enabled() ? 1 : 0);
5216 
5217 		piid++;
5218 	}
5219 
5220 	lo_send_message (get_address (msg), X_("/strip/plugin/list"), reply);
5221 	lo_message_free (reply);
5222 	return 0;
5223 }
5224 
5225 int
route_plugin_descriptor(int ssid,int piid,lo_message msg)5226 OSC::route_plugin_descriptor (int ssid, int piid, lo_message msg) {
5227 	if (!session) {
5228 		return -1;
5229 	}
5230 
5231 	boost::shared_ptr<Route> r = boost::dynamic_pointer_cast<Route>(get_strip (ssid, get_address (msg)));
5232 
5233 	if (!r) {
5234 		PBD::error << "OSC: Invalid Remote Control ID '" << ssid << "'" << endmsg;
5235 		return -1;
5236 	}
5237 
5238 	boost::shared_ptr<Processor> redi = r->nth_plugin(piid - 1);
5239 
5240 	if (!redi) {
5241 		PBD::error << "OSC: cannot find plugin # " << piid << " for RID '" << ssid << "'" << endmsg;
5242 		return -1;
5243 	}
5244 
5245 	boost::shared_ptr<PluginInsert> pi;
5246 
5247 	if (!(pi = boost::dynamic_pointer_cast<PluginInsert>(redi))) {
5248 		PBD::error << "OSC: given processor # " << piid << " on RID '" << ssid << "' is not a Plugin." << endmsg;
5249 		return -1;
5250 	}
5251 
5252 	boost::shared_ptr<ARDOUR::Plugin> pip = pi->plugin();
5253 	bool ok = false;
5254 
5255 	for ( uint32_t ppi = 0; ppi < pip->parameter_count(); ppi++) {
5256 
5257 		uint32_t controlid = pip->nth_parameter(ppi, ok);
5258 		if (!ok) {
5259 			continue;
5260 		}
5261 		boost::shared_ptr<AutomationControl> c = pi->automation_control(Evoral::Parameter(PluginAutomation, 0, controlid));
5262 
5263 		lo_message reply = lo_message_new();
5264 		lo_message_add_int32 (reply, ssid);
5265 		lo_message_add_int32 (reply, piid);
5266 
5267 		lo_message_add_int32 (reply, ppi + 1);
5268 		ParameterDescriptor pd;
5269 		pi->plugin()->get_parameter_descriptor(controlid, pd);
5270 		lo_message_add_string (reply, pd.label.c_str());
5271 
5272 		// I've combined those binary descriptor parts in a bit-field to reduce lilo message elements
5273 		int flags = 0;
5274 		flags |= pd.enumeration ? 1 : 0;
5275 		flags |= pd.integer_step ? 2 : 0;
5276 		flags |= pd.logarithmic ? 4 : 0;
5277 		flags |= pd.sr_dependent ? 32 : 0;
5278 		flags |= pd.toggled ? 64 : 0;
5279 		flags |= pip->parameter_is_input(controlid) ? 0x80 : 0;
5280 
5281 		std::string param_desc = pi->plugin()->describe_parameter(Evoral::Parameter(PluginAutomation, 0, controlid));
5282 		flags |= (param_desc == X_("hidden")) ? 0x100 : 0;
5283 		lo_message_add_int32 (reply, flags);
5284 
5285 		switch(pd.datatype) {
5286 			case ARDOUR::Variant::BEATS:
5287 				lo_message_add_string(reply, _("BEATS"));
5288 				break;
5289 			case ARDOUR::Variant::BOOL:
5290 				lo_message_add_string(reply, _("BOOL"));
5291 				break;
5292 			case ARDOUR::Variant::DOUBLE:
5293 				lo_message_add_string(reply, _("DOUBLE"));
5294 				break;
5295 			case ARDOUR::Variant::FLOAT:
5296 				lo_message_add_string(reply, _("FLOAT"));
5297 				break;
5298 			case ARDOUR::Variant::INT:
5299 				lo_message_add_string(reply, _("INT"));
5300 				break;
5301 			case ARDOUR::Variant::LONG:
5302 				lo_message_add_string(reply, _("LONG"));
5303 				break;
5304 			case ARDOUR::Variant::NOTHING:
5305 				lo_message_add_string(reply, _("NOTHING"));
5306 				break;
5307 			case ARDOUR::Variant::PATH:
5308 				lo_message_add_string(reply, _("PATH"));
5309 				break;
5310 			case ARDOUR::Variant::STRING:
5311 				lo_message_add_string(reply, _("STRING"));
5312 				break;
5313 			case ARDOUR::Variant::URI:
5314 				lo_message_add_string(reply, _("URI"));
5315 				break;
5316 			default:
5317 				lo_message_add_string(reply, _("UNKNOWN"));
5318 				break;
5319 		}
5320 		lo_message_add_float (reply, pd.lower);
5321 		lo_message_add_float (reply, pd.upper);
5322 		lo_message_add_string (reply, pd.print_fmt.c_str());
5323 		if ( pd.scale_points ) {
5324 			lo_message_add_int32 (reply, pd.scale_points->size());
5325 			for ( ARDOUR::ScalePoints::const_iterator i = pd.scale_points->begin(); i != pd.scale_points->end(); ++i) {
5326 				lo_message_add_float (reply, i->second);
5327 				lo_message_add_string (reply, ((std::string)i->first).c_str());
5328 			}
5329 		}
5330 		else {
5331 			lo_message_add_int32 (reply, 0);
5332 		}
5333 		if ( c ) {
5334 			lo_message_add_double (reply, c->get_value());
5335 		}
5336 		else {
5337 			lo_message_add_double (reply, 0);
5338 		}
5339 
5340 		lo_send_message (get_address (msg), X_("/strip/plugin/descriptor"), reply);
5341 		lo_message_free (reply);
5342 	}
5343 
5344 	lo_message reply = lo_message_new ();
5345 	lo_message_add_int32 (reply, ssid);
5346 	lo_message_add_int32 (reply, piid);
5347 	lo_send_message (get_address (msg), X_("/strip/plugin/descriptor_end"), reply);
5348 	lo_message_free (reply);
5349 
5350 	return 0;
5351 }
5352 
5353 int
route_plugin_reset(int ssid,int piid,lo_message msg)5354 OSC::route_plugin_reset (int ssid, int piid, lo_message msg) {
5355 	if (!session) {
5356 		return -1;
5357 	}
5358 
5359 	boost::shared_ptr<Route> r = boost::dynamic_pointer_cast<Route>(get_strip (ssid, get_address (msg)));
5360 
5361 	if (!r) {
5362 		PBD::error << "OSC: Invalid Remote Control ID '" << ssid << "'" << endmsg;
5363 		return -1;
5364 	}
5365 
5366 	boost::shared_ptr<Processor> redi = r->nth_plugin(piid - 1);
5367 
5368 	if (!redi) {
5369 		PBD::error << "OSC: cannot find plugin # " << piid << " for RID '" << ssid << "'" << endmsg;
5370 		return -1;
5371 	}
5372 
5373 	boost::shared_ptr<PluginInsert> pi;
5374 
5375 	if (!(pi = boost::dynamic_pointer_cast<PluginInsert>(redi))) {
5376 		PBD::error << "OSC: given processor # " << piid << " on RID '" << ssid << "' is not a Plugin." << endmsg;
5377 		return -1;
5378 	}
5379 
5380 	pi->reset_parameters_to_default ();
5381 
5382 	return 0;
5383 }
5384 
5385 int
route_plugin_parameter(int ssid,int piid,int par,float val,lo_message msg)5386 OSC::route_plugin_parameter (int ssid, int piid, int par, float val, lo_message msg)
5387 {
5388 	if (!session)
5389 		return -1;
5390 	boost::shared_ptr<Stripable> s = get_strip (ssid, get_address (msg));
5391 
5392 	boost::shared_ptr<Route> r = boost::dynamic_pointer_cast<Route> (s);
5393 
5394 	if (!r) {
5395 		PBD::error << "OSC: Invalid Remote Control ID '" << ssid << "'" << endmsg;
5396 		return -1;
5397 	}
5398 
5399 	boost::shared_ptr<Processor> redi=r->nth_plugin (piid - 1);
5400 
5401 	if (!redi) {
5402 		PBD::error << "OSC: cannot find plugin # " << piid << " for RID '" << ssid << "'" << endmsg;
5403 		return -1;
5404 	}
5405 
5406 	boost::shared_ptr<PluginInsert> pi;
5407 
5408 	if (!(pi = boost::dynamic_pointer_cast<PluginInsert>(redi))) {
5409 		PBD::error << "OSC: given processor # " << piid << " on RID '" << ssid << "' is not a Plugin." << endmsg;
5410 		return -1;
5411 	}
5412 
5413 	boost::shared_ptr<ARDOUR::Plugin> pip = pi->plugin();
5414 	bool ok=false;
5415 
5416 	uint32_t controlid = pip->nth_parameter (par - 1,ok);
5417 
5418 	if (!ok) {
5419 		PBD::error << "OSC: Cannot find parameter # " << par <<  " for plugin # " << piid << " on RID '" << ssid << "'" << endmsg;
5420 		return -1;
5421 	}
5422 
5423 	if (!pip->parameter_is_input(controlid)) {
5424 		PBD::error << "OSC: Parameter # " << par <<  " for plugin # " << piid << " on RID '" << ssid << "' is not a control input" << endmsg;
5425 		return -1;
5426 	}
5427 
5428 	ParameterDescriptor pd;
5429 	pi->plugin()->get_parameter_descriptor (controlid,pd);
5430 
5431 	if (val >= pd.lower && val <= pd.upper) {
5432 
5433 		boost::shared_ptr<AutomationControl> c = pi->automation_control (Evoral::Parameter(PluginAutomation, 0, controlid));
5434 		// cerr << "parameter:" << redi->describe_parameter(controlid) << " val:" << val << "\n";
5435 		c->set_value (val, PBD::Controllable::NoGroup);
5436 	} else {
5437 		PBD::warning << "OSC: Parameter # " << par <<  " for plugin # " << piid << " on RID '" << ssid << "' is out of range" << endmsg;
5438 		PBD::info << "OSC: Valid range min=" << pd.lower << " max=" << pd.upper << endmsg;
5439 	}
5440 
5441 	return 0;
5442 }
5443 
5444 //prints to cerr only
5445 int
route_plugin_parameter_print(int ssid,int piid,int par,lo_message msg)5446 OSC::route_plugin_parameter_print (int ssid, int piid, int par, lo_message msg)
5447 {
5448 	if (!session) {
5449 		return -1;
5450 	}
5451 	boost::shared_ptr<Stripable> s = get_strip (ssid, get_address (msg));
5452 
5453 	boost::shared_ptr<Route> r = boost::dynamic_pointer_cast<Route> (s);
5454 
5455 	if (!r) {
5456 		return -1;
5457 	}
5458 
5459 	boost::shared_ptr<Processor> redi=r->nth_plugin (piid - 1);
5460 
5461 	if (!redi) {
5462 		return -1;
5463 	}
5464 
5465 	boost::shared_ptr<PluginInsert> pi;
5466 
5467 	if (!(pi = boost::dynamic_pointer_cast<PluginInsert>(redi))) {
5468 		return -1;
5469 	}
5470 
5471 	boost::shared_ptr<ARDOUR::Plugin> pip = pi->plugin();
5472 	bool ok=false;
5473 
5474 	uint32_t controlid = pip->nth_parameter (par - 1,ok);
5475 
5476 	if (!ok) {
5477 		return -1;
5478 	}
5479 
5480 	ParameterDescriptor pd;
5481 
5482 	if (pi->plugin()->get_parameter_descriptor (controlid, pd) == 0) {
5483 		boost::shared_ptr<AutomationControl> c = pi->automation_control (Evoral::Parameter(PluginAutomation, 0, controlid));
5484 
5485 		cerr << "parameter:     " << pd.label  << "\n";
5486 		if (c) {
5487 			cerr << "current value: " << c->get_value () << "\n";
5488 		} else {
5489 			cerr << "current value not available, control does not exist\n";
5490 		}
5491 		cerr << "lower value:   " << pd.lower << "\n";
5492 		cerr << "upper value:   " << pd.upper << "\n";
5493 	}
5494 
5495 	return 0;
5496 }
5497 
5498 int
route_plugin_activate(int ssid,int piid,lo_message msg)5499 OSC::route_plugin_activate (int ssid, int piid, lo_message msg)
5500 {
5501 	if (!session)
5502 		return -1;
5503 	boost::shared_ptr<Stripable> s = get_strip (ssid, lo_message_get_source (msg));
5504 
5505 	boost::shared_ptr<Route> r = boost::dynamic_pointer_cast<Route> (s);
5506 
5507 	if (!r) {
5508 		PBD::error << "OSC: Invalid Remote Control ID '" << ssid << "'" << endmsg;
5509 		return -1;
5510 	}
5511 
5512 	boost::shared_ptr<Processor> redi=r->nth_plugin (piid - 1);
5513 
5514 	if (!redi) {
5515 		PBD::error << "OSC: cannot find plugin # " << piid << " for RID '" << ssid << "'" << endmsg;
5516 		return -1;
5517 	}
5518 
5519 	boost::shared_ptr<PluginInsert> pi;
5520 
5521 	if (!(pi = boost::dynamic_pointer_cast<PluginInsert>(redi))) {
5522 		PBD::error << "OSC: given processor # " << piid << " on RID '" << ssid << "' is not a Plugin." << endmsg;
5523 		return -1;
5524 	}
5525 
5526 	boost::shared_ptr<ARDOUR::Plugin> pip = pi->plugin();
5527 	pi->activate();
5528 
5529 	return 0;
5530 }
5531 
5532 int
route_plugin_deactivate(int ssid,int piid,lo_message msg)5533 OSC::route_plugin_deactivate (int ssid, int piid, lo_message msg)
5534 {
5535 	if (!session)
5536 		return -1;
5537 	boost::shared_ptr<Stripable> s = get_strip (ssid, lo_message_get_source (msg));
5538 
5539 	boost::shared_ptr<Route> r = boost::dynamic_pointer_cast<Route> (s);
5540 
5541 	if (!r) {
5542 		PBD::error << "OSC: Invalid Remote Control ID '" << ssid << "'" << endmsg;
5543 		return -1;
5544 	}
5545 
5546 	boost::shared_ptr<Processor> redi=r->nth_plugin (piid - 1);
5547 
5548 	if (!redi) {
5549 		PBD::error << "OSC: cannot find plugin # " << piid << " for RID '" << ssid << "'" << endmsg;
5550 		return -1;
5551 	}
5552 
5553 	boost::shared_ptr<PluginInsert> pi;
5554 
5555 	if (!(pi = boost::dynamic_pointer_cast<PluginInsert>(redi))) {
5556 		PBD::error << "OSC: given processor # " << piid << " on RID '" << ssid << "' is not a Plugin." << endmsg;
5557 		return -1;
5558 	}
5559 
5560 	boost::shared_ptr<ARDOUR::Plugin> pip = pi->plugin();
5561 	pi->deactivate();
5562 
5563 	return 0;
5564 }
5565 
5566 // select
5567 
5568 int
sel_pan_elevation(float val,lo_message msg)5569 OSC::sel_pan_elevation (float val, lo_message msg)
5570 {
5571 	OSCSurface *sur = get_surface(get_address (msg));
5572 	boost::shared_ptr<Stripable> s;
5573 	s = sur->select;
5574 	if (s) {
5575 		if (s->pan_elevation_control()) {
5576 			s->pan_elevation_control()->set_value (s->pan_elevation_control()->interface_to_internal (val), PBD::Controllable::NoGroup);
5577 			return 0;
5578 		}
5579 	}
5580 	return float_message(X_("/select/pan_elevation_position"), 0, get_address (msg));
5581 }
5582 
5583 int
sel_pan_frontback(float val,lo_message msg)5584 OSC::sel_pan_frontback (float val, lo_message msg)
5585 {
5586 	OSCSurface *sur = get_surface(get_address (msg));
5587 	boost::shared_ptr<Stripable> s;
5588 	s = sur->select;
5589 	if (s) {
5590 		if (s->pan_frontback_control()) {
5591 			s->pan_frontback_control()->set_value (s->pan_frontback_control()->interface_to_internal (val), PBD::Controllable::NoGroup);
5592 			return 0;
5593 		}
5594 	}
5595 	return float_message(X_("/select/pan_frontback_position"), 0.5, get_address (msg));
5596 }
5597 
5598 int
sel_pan_lfe(float val,lo_message msg)5599 OSC::sel_pan_lfe (float val, lo_message msg)
5600 {
5601 	OSCSurface *sur = get_surface(get_address (msg));
5602 	boost::shared_ptr<Stripable> s;
5603 	s = sur->select;
5604 	if (s) {
5605 		if (s->pan_lfe_control()) {
5606 			s->pan_lfe_control()->set_value (s->pan_lfe_control()->interface_to_internal (val), PBD::Controllable::NoGroup);
5607 			return 0;
5608 		}
5609 	}
5610 	return float_message(X_("/select/pan_lfe_control"), 0, get_address (msg));
5611 }
5612 
5613 // compressor control
5614 int
sel_comp_enable(float val,lo_message msg)5615 OSC::sel_comp_enable (float val, lo_message msg)
5616 {
5617 	OSCSurface *sur = get_surface(get_address (msg));
5618 	boost::shared_ptr<Stripable> s;
5619 	s = sur->select;
5620 	if (s) {
5621 		if (s->comp_enable_controllable()) {
5622 			s->comp_enable_controllable()->set_value (s->comp_enable_controllable()->interface_to_internal (val), PBD::Controllable::NoGroup);
5623 			return 0;
5624 		}
5625 	}
5626 	return float_message(X_("/select/comp_enable"), 0, get_address (msg));
5627 }
5628 
5629 int
sel_comp_threshold(float val,lo_message msg)5630 OSC::sel_comp_threshold (float val, lo_message msg)
5631 {
5632 	OSCSurface *sur = get_surface(get_address (msg));
5633 	boost::shared_ptr<Stripable> s;
5634 	s = sur->select;
5635 	if (s) {
5636 		if (s->comp_threshold_controllable()) {
5637 			s->comp_threshold_controllable()->set_value (s->comp_threshold_controllable()->interface_to_internal (val), PBD::Controllable::NoGroup);
5638 			return 0;
5639 		}
5640 	}
5641 	return float_message(X_("/select/comp_threshold"), 0, get_address (msg));
5642 }
5643 
5644 int
sel_comp_speed(float val,lo_message msg)5645 OSC::sel_comp_speed (float val, lo_message msg)
5646 {
5647 	OSCSurface *sur = get_surface(get_address (msg));
5648 	boost::shared_ptr<Stripable> s;
5649 	s = sur->select;
5650 	if (s) {
5651 		if (s->comp_speed_controllable()) {
5652 			s->comp_speed_controllable()->set_value (s->comp_speed_controllable()->interface_to_internal (val), PBD::Controllable::NoGroup);
5653 			return 0;
5654 		}
5655 	}
5656 	return float_message(X_("/select/comp_speed"), 0, get_address (msg));
5657 }
5658 
5659 int
sel_comp_mode(float val,lo_message msg)5660 OSC::sel_comp_mode (float val, lo_message msg)
5661 {
5662 	OSCSurface *sur = get_surface(get_address (msg));
5663 	boost::shared_ptr<Stripable> s;
5664 	s = sur->select;
5665 	if (s) {
5666 		if (s->comp_mode_controllable()) {
5667 			s->comp_mode_controllable()->set_value (s->comp_mode_controllable()->interface_to_internal (val), PBD::Controllable::NoGroup);
5668 			return 0;
5669 		}
5670 	}
5671 	return float_message(X_("/select/comp_mode"), 0, get_address (msg));
5672 }
5673 
5674 int
sel_comp_makeup(float val,lo_message msg)5675 OSC::sel_comp_makeup (float val, lo_message msg)
5676 {
5677 	OSCSurface *sur = get_surface(get_address (msg));
5678 	boost::shared_ptr<Stripable> s;
5679 	s = sur->select;
5680 	if (s) {
5681 		if (s->comp_makeup_controllable()) {
5682 			s->comp_makeup_controllable()->set_value (s->comp_makeup_controllable()->interface_to_internal (val), PBD::Controllable::NoGroup);
5683 			return 0;
5684 		}
5685 	}
5686 	return float_message(X_("/select/comp_makeup"), 0, get_address (msg));
5687 }
5688 
5689 // EQ control
5690 
5691 int
sel_eq_enable(float val,lo_message msg)5692 OSC::sel_eq_enable (float val, lo_message msg)
5693 {
5694 	OSCSurface *sur = get_surface(get_address (msg));
5695 	boost::shared_ptr<Stripable> s;
5696 	s = sur->select;
5697 	if (s) {
5698 		if (s->eq_enable_controllable()) {
5699 			s->eq_enable_controllable()->set_value (s->eq_enable_controllable()->interface_to_internal (val), PBD::Controllable::NoGroup);
5700 			return 0;
5701 		}
5702 	}
5703 	return float_message(X_("/select/eq_enable"), 0, get_address (msg));
5704 }
5705 
5706 int
sel_eq_hpf_freq(float val,lo_message msg)5707 OSC::sel_eq_hpf_freq (float val, lo_message msg)
5708 {
5709 	OSCSurface *sur = get_surface(get_address (msg));
5710 	boost::shared_ptr<Stripable> s;
5711 	s = sur->select;
5712 	if (s) {
5713 		if (s->filter_freq_controllable(true)) {
5714 			s->filter_freq_controllable(true)->set_value (s->filter_freq_controllable(true)->interface_to_internal (val), PBD::Controllable::NoGroup);
5715 			return 0;
5716 		}
5717 	}
5718 	return float_message(X_("/select/eq_hpf/freq"), 0, get_address (msg));
5719 }
5720 
5721 int
sel_eq_lpf_freq(float val,lo_message msg)5722 OSC::sel_eq_lpf_freq (float val, lo_message msg)
5723 {
5724 	OSCSurface *sur = get_surface(get_address (msg));
5725 	boost::shared_ptr<Stripable> s;
5726 	s = sur->select;
5727 	if (s) {
5728 		if (s->filter_freq_controllable(false)) {
5729 			s->filter_freq_controllable(false)->set_value (s->filter_freq_controllable(false)->interface_to_internal (val), PBD::Controllable::NoGroup);
5730 			return 0;
5731 		}
5732 	}
5733 	return float_message(X_("/select/eq_lpf/freq"), 0, get_address (msg));
5734 }
5735 
5736 int
sel_eq_hpf_enable(float val,lo_message msg)5737 OSC::sel_eq_hpf_enable (float val, lo_message msg)
5738 {
5739 	OSCSurface *sur = get_surface(get_address (msg));
5740 	boost::shared_ptr<Stripable> s;
5741 	s = sur->select;
5742 	if (s) {
5743 		if (s->filter_enable_controllable(true)) {
5744 			s->filter_enable_controllable(true)->set_value (s->filter_enable_controllable(true)->interface_to_internal (val), PBD::Controllable::NoGroup);
5745 			return 0;
5746 		}
5747 	}
5748 	return float_message(X_("/select/eq_hpf/enable"), 0, get_address (msg));
5749 }
5750 
5751 int
sel_eq_lpf_enable(float val,lo_message msg)5752 OSC::sel_eq_lpf_enable (float val, lo_message msg)
5753 {
5754 	OSCSurface *sur = get_surface(get_address (msg));
5755 	boost::shared_ptr<Stripable> s;
5756 	s = sur->select;
5757 	if (s) {
5758 		if (s->filter_enable_controllable(false)) {
5759 			s->filter_enable_controllable(false)->set_value (s->filter_enable_controllable(false)->interface_to_internal (val), PBD::Controllable::NoGroup);
5760 			return 0;
5761 		}
5762 	}
5763 	return float_message(X_("/select/eq_lpf/enable"), 0, get_address (msg));
5764 }
5765 
5766 int
sel_eq_hpf_slope(float val,lo_message msg)5767 OSC::sel_eq_hpf_slope (float val, lo_message msg)
5768 {
5769 	OSCSurface *sur = get_surface(get_address (msg));
5770 	boost::shared_ptr<Stripable> s;
5771 	s = sur->select;
5772 	if (s) {
5773 		if (s->filter_slope_controllable(true)) {
5774 			s->filter_slope_controllable(true)->set_value (s->filter_slope_controllable(true)->interface_to_internal (val), PBD::Controllable::NoGroup);
5775 			return 0;
5776 		}
5777 	}
5778 	return float_message(X_("/select/eq_hpf/slope"), 0, get_address (msg));
5779 }
5780 
5781 int
sel_eq_lpf_slope(float val,lo_message msg)5782 OSC::sel_eq_lpf_slope (float val, lo_message msg)
5783 {
5784 	OSCSurface *sur = get_surface(get_address (msg));
5785 	boost::shared_ptr<Stripable> s;
5786 	s = sur->select;
5787 	if (s) {
5788 		if (s->filter_slope_controllable(false)) {
5789 			s->filter_slope_controllable(false)->set_value (s->filter_slope_controllable(false)->interface_to_internal (val), PBD::Controllable::NoGroup);
5790 			return 0;
5791 		}
5792 	}
5793 	return float_message(X_("/select/eq_lpf/slope"), 0, get_address (msg));
5794 }
5795 
5796 int
sel_eq_gain(int id,float val,lo_message msg)5797 OSC::sel_eq_gain (int id, float val, lo_message msg)
5798 {
5799 	OSCSurface *sur = get_surface(get_address (msg));
5800 	boost::shared_ptr<Stripable> s;
5801 	s = sur->select;
5802 	if (s) {
5803 		if (id > 0) {
5804 			--id;
5805 		}
5806 		if (s->eq_gain_controllable (id)) {
5807 			s->eq_gain_controllable (id)->set_value (s->eq_gain_controllable(id)->interface_to_internal (val), PBD::Controllable::NoGroup);
5808 			return 0;
5809 		}
5810 	}
5811 	return float_message_with_id (X_("/select/eq_gain"), id + 1, 0, sur->feedback[2], get_address (msg));
5812 }
5813 
5814 int
sel_eq_freq(int id,float val,lo_message msg)5815 OSC::sel_eq_freq (int id, float val, lo_message msg)
5816 {
5817 	OSCSurface *sur = get_surface(get_address (msg));
5818 	boost::shared_ptr<Stripable> s;
5819 	s = sur->select;
5820 	if (s) {
5821 		if (id > 0) {
5822 			--id;
5823 		}
5824 		if (s->eq_freq_controllable (id)) {
5825 			s->eq_freq_controllable (id)->set_value (s->eq_freq_controllable(id)->interface_to_internal (val), PBD::Controllable::NoGroup);
5826 			return 0;
5827 		}
5828 	}
5829 	return float_message_with_id (X_("/select/eq_freq"), id + 1, 0, sur->feedback[2], get_address (msg));
5830 }
5831 
5832 int
sel_eq_q(int id,float val,lo_message msg)5833 OSC::sel_eq_q (int id, float val, lo_message msg)
5834 {
5835 	OSCSurface *sur = get_surface(get_address (msg));
5836 	boost::shared_ptr<Stripable> s;
5837 	s = sur->select;
5838 	if (s) {
5839 		if (id > 0) {
5840 			--id;
5841 		}
5842 		if (s->eq_q_controllable (id)) {
5843 			s->eq_q_controllable (id)->set_value (s->eq_q_controllable(id)->interface_to_internal (val), PBD::Controllable::NoGroup);
5844 			return 0;
5845 		}
5846 	}
5847 	return float_message_with_id (X_("/select/eq_q"), id + 1, 0, sur->feedback[2], get_address (msg));
5848 }
5849 
5850 int
sel_eq_shape(int id,float val,lo_message msg)5851 OSC::sel_eq_shape (int id, float val, lo_message msg)
5852 {
5853 	OSCSurface *sur = get_surface(get_address (msg));
5854 	boost::shared_ptr<Stripable> s;
5855 	s = sur->select;
5856 	if (s) {
5857 		if (id > 0) {
5858 			--id;
5859 		}
5860 		if (s->eq_shape_controllable (id)) {
5861 			s->eq_shape_controllable (id)->set_value (s->eq_shape_controllable(id)->interface_to_internal (val), PBD::Controllable::NoGroup);
5862 			return 0;
5863 		}
5864 	}
5865 	return float_message_with_id (X_("/select/eq_shape"), id + 1, 0, sur->feedback[2], get_address (msg));
5866 }
5867 
5868 // timer callbacks
5869 bool
periodic(void)5870 OSC::periodic (void)
5871 {
5872 	if (observer_busy) {
5873 		return true;
5874 	}
5875 	if (!tick) {
5876 		Glib::usleep(100); // let flurry of signals subside
5877 		if (global_init) {
5878 			for (uint32_t it = 0; it < _surface.size(); it++) {
5879 				OSCSurface* sur = &_surface[it];
5880 				global_feedback (sur);
5881 			}
5882 			global_init = false;
5883 			tick = true;
5884 		}
5885 		if (bank_dirty) {
5886 			_recalcbanks ();
5887 			bank_dirty = false;
5888 			tick = true;
5889 		}
5890 		return true;
5891 	}
5892 
5893 	if (scrub_speed != 0) {
5894 		// for those jog wheels that don't have 0 on release (touch), time out.
5895 		int64_t now = PBD::get_microseconds ();
5896 		int64_t diff = now - scrub_time;
5897 		if (diff > 120000) {
5898 			scrub_speed = 0;
5899 			// locate to the place PH was at last tick
5900 			session->request_locate (scrub_place, MustStop);
5901 		}
5902 	}
5903 	for (uint32_t it = 0; it < _surface.size(); it++) {
5904 		OSCSurface* sur = &_surface[it];
5905 		OSCSelectObserver* so;
5906 		if ((so = dynamic_cast<OSCSelectObserver*>(sur->sel_obs)) != 0) {
5907 			so->tick ();
5908 		}
5909 		OSCCueObserver* co;
5910 		if ((co = dynamic_cast<OSCCueObserver*>(sur->cue_obs)) != 0) {
5911 			co->tick ();
5912 		}
5913 		OSCGlobalObserver* go;
5914 		if ((go = dynamic_cast<OSCGlobalObserver*>(sur->global_obs)) != 0) {
5915 			go->tick ();
5916 		}
5917 		for (uint32_t i = 0; i < sur->observers.size(); i++) {
5918 			OSCRouteObserver* ro;
5919 			if ((ro = dynamic_cast<OSCRouteObserver*>(sur->observers[i])) != 0) {
5920 				ro->tick ();
5921 			}
5922 		}
5923 
5924 	}
5925 	for (FakeTouchMap::iterator x = _touch_timeout.begin(); x != _touch_timeout.end();) {
5926 		_touch_timeout[(*x).first] = (*x).second - 1;
5927 		if (!(*x).second) {
5928 			boost::shared_ptr<ARDOUR::AutomationControl> ctrl = (*x).first;
5929 			// turn touch off
5930 			ctrl->stop_touch (ctrl->session().transport_sample());
5931 			_touch_timeout.erase (x++);
5932 		} else {
5933 			x++;
5934 		}
5935 	}
5936 	return true;
5937 }
5938 
5939 XMLNode&
get_state()5940 OSC::get_state ()
5941 {
5942 	XMLNode& node (ControlProtocol::get_state());
5943 	node.set_property (X_("debugmode"), (int32_t) _debugmode); // TODO: enum2str
5944 	node.set_property (X_("address-only"), address_only);
5945 	node.set_property (X_("remote-port"), remote_port);
5946 	node.set_property (X_("banksize"), default_banksize);
5947 	node.set_property (X_("striptypes"), default_strip);
5948 	node.set_property (X_("feedback"), default_feedback);
5949 	node.set_property (X_("gainmode"), default_gainmode);
5950 	node.set_property (X_("send-page-size"), default_send_size);
5951 	node.set_property (X_("plug-page-size"), default_plugin_size);
5952 	return node;
5953 }
5954 
5955 int
set_state(const XMLNode & node,int version)5956 OSC::set_state (const XMLNode& node, int version)
5957 {
5958 	if (ControlProtocol::set_state (node, version)) {
5959 		return -1;
5960 	}
5961 	int32_t debugmode;
5962 	if (node.get_property (X_("debugmode"), debugmode)) {
5963 		_debugmode = OSCDebugMode (debugmode);
5964 	}
5965 
5966 	node.get_property (X_("address-only"), address_only);
5967 	node.get_property (X_("remote-port"), remote_port);
5968 	node.get_property (X_("banksize"), default_banksize);
5969 	node.get_property (X_("striptypes"), default_strip);
5970 	node.get_property (X_("feedback"), default_feedback);
5971 	node.get_property (X_("gainmode"), default_gainmode);
5972 	node.get_property (X_("send-page-size"), default_send_size);
5973 	node.get_property (X_("plugin-page-size"), default_plugin_size);
5974 
5975 	global_init = true;
5976 	tick = false;
5977 
5978 	return 0;
5979 }
5980 
5981 // predicate for sort call in get_sorted_stripables
5982 struct StripableByPresentationOrder
5983 {
operator ()StripableByPresentationOrder5984 	bool operator () (const boost::shared_ptr<Stripable> & a, const boost::shared_ptr<Stripable> & b) const
5985 	{
5986 		return a->presentation_info().order() < b->presentation_info().order();
5987 	}
5988 
operator ()StripableByPresentationOrder5989 	bool operator () (const Stripable & a, const Stripable & b) const
5990 	{
5991 		return a.presentation_info().order() < b.presentation_info().order();
5992 	}
5993 
operator ()StripableByPresentationOrder5994 	bool operator () (const Stripable * a, const Stripable * b) const
5995 	{
5996 		return a->presentation_info().order() < b->presentation_info().order();
5997 	}
5998 };
5999 
6000 OSC::Sorted
get_sorted_stripables(std::bitset<32> types,bool cue,uint32_t custom,Sorted my_list)6001 OSC::get_sorted_stripables(std::bitset<32> types, bool cue, uint32_t custom, Sorted my_list)
6002 {
6003 	Sorted sorted;
6004 	StripableList stripables;
6005 	StripableList custom_list;
6006 
6007 	// fetch all stripables
6008 	session->get_stripables (stripables, PresentationInfo::AllStripables);
6009 	if (custom) {
6010 		uint32_t nstps = my_list.size ();
6011 		// check each custom strip to see if it still exists
6012 		boost::shared_ptr<Stripable> s;
6013 		for (uint32_t i = 0; i < nstps; i++) {
6014 			bool exists = false;
6015 			s = my_list[i];
6016 			for (StripableList::iterator it = stripables.begin(); it != stripables.end(); ++it) {
6017 				boost::shared_ptr<Stripable> sl = *it;
6018 				if (s == sl) {
6019 					exists = true;
6020 					break;
6021 				}
6022 			}
6023 			if(!exists) {
6024 				my_list[i] = boost::shared_ptr<Stripable>();
6025 			} else {
6026 				custom_list.push_back (s);
6027 			}
6028 		}
6029 		if (custom == 1) {
6030 			return my_list;
6031 		} else {
6032 			stripables = custom_list;
6033 		}
6034 	}
6035 	// Look for stripables that match bit in sur->strip_types
6036 	for (StripableList::iterator it = stripables.begin(); it != stripables.end(); ++it) {
6037 
6038 		boost::shared_ptr<Stripable> s = *it;
6039 		if (!s) {
6040 			break;
6041 		}
6042 		if (custom == 2) {
6043 			// banking off use all valid custom strips
6044 			sorted.push_back (s);
6045 		} else
6046 		if ((!cue) && (!types[9]) && (s->presentation_info().flags() & PresentationInfo::Hidden)) {
6047 			// do nothing... skip it
6048 		} else if (types[8] && (s->is_selected())) {
6049 			sorted.push_back (s);
6050 		} else if (types[9] && (s->presentation_info().flags() & PresentationInfo::Hidden)) {
6051 			sorted.push_back (s);
6052 		} else if (s->is_master() || s->is_monitor() || s->is_auditioner()) {
6053 			// do nothing for these either (we add them later)
6054 		} else {
6055 			if (types[0] && boost::dynamic_pointer_cast<AudioTrack>(s)) {
6056 				sorted.push_back (s);
6057 			} else if (types[1] && boost::dynamic_pointer_cast<MidiTrack>(s)) {
6058 				sorted.push_back (s);
6059 			} else if (types[4] && boost::dynamic_pointer_cast<VCA>(s)) {
6060 				sorted.push_back (s);
6061 			} else  if (s->is_foldbackbus()) {
6062 				if (types[7]) {
6063 					sorted.push_back (s);
6064 				}
6065 			} else
6066 #ifdef MIXBUS
6067 			if (types[2] && Profile->get_mixbus() && s->mixbus()) {
6068 				sorted.push_back (s);
6069 			} else
6070 #endif
6071 			if (boost::dynamic_pointer_cast<Route>(s) && !boost::dynamic_pointer_cast<Track>(s)) {
6072 				boost::shared_ptr<Route> r = boost::dynamic_pointer_cast<Route>(s);
6073 				if (!(s->presentation_info().flags() & PresentationInfo::MidiBus)) {
6074 					// note some older sessions will show midibuses as busses
6075 					// this is a bus
6076 					if (types[2]) {
6077 						sorted.push_back (s);
6078 					}
6079 				} else if (types[3]) {
6080 						sorted.push_back (s);
6081 				}
6082 			}
6083 		}
6084 	}
6085 	if (!custom || (custom & 0x2)) {
6086 		sort (sorted.begin(), sorted.end(), StripableByPresentationOrder());
6087 	}
6088 	if (!custom) {
6089 		// Master/Monitor might be anywhere... we put them at the end - Sorry ;)
6090 		if (types[5]) {
6091 			if (session->master_out()) {
6092 				sorted.push_back (session->master_out());
6093 			}
6094 		}
6095 		if (types[6]) {
6096 			if (session->monitor_out()) {
6097 				sorted.push_back (session->monitor_out());
6098 			}
6099 		}
6100 	}
6101 	return sorted;
6102 }
6103 
6104 int
cue_parse(const char * path,const char * types,lo_arg ** argv,int argc,lo_message msg)6105 OSC::cue_parse (const char *path, const char* types, lo_arg **argv, int argc, lo_message msg)
6106 {
6107 	OSCSurface *s = get_surface(get_address (msg), true);
6108 	s->bank_size = 0;
6109 	float value = 0;
6110 	if (argc == 1) {
6111 		if (types[0] == 'f') {
6112 			value = argv[0]->f;
6113 		} else if (types[0] == 'i') {
6114 			value = (float) argv[0]->i;
6115 		}
6116 	}
6117 	int ret = 1; /* unhandled */
6118 	if (!strncmp (path, X_("/cue/bus"), 8) || !strncmp (path, X_("/cue/aux"), 8)) {
6119 		// set our Foldback bus
6120 		if (argc) {
6121 			if (value) {
6122 				ret = cue_set ((uint32_t) value, msg);
6123 			} else {
6124 				ret = 0;
6125 			}
6126 		}
6127 	}
6128 	else if (!strncmp (path, X_("/cue/connect_output"), 16) || !strncmp (path, X_("/cue/connect_aux"), 16)) {
6129 		// connect Foldback bus output
6130 		string dest = "";
6131 		if (argc == 1 && types[0] == 's') {
6132 			dest = &argv[0]->s;
6133 			ret = cue_connect_aux (dest, msg);
6134 		} else {
6135 			PBD::warning << "OSC: connect_aux has wrong number or type of parameters." << endmsg;
6136 		}
6137 	}
6138 	else if (!strncmp (path, X_("/cue/connect"), 12)) {
6139 		// Connect to default Aux bus
6140 		if ((!argc) || argv[0]->f || argv[0]->i) {
6141 			ret = cue_set (1, msg);
6142 		} else {
6143 			ret = 0;
6144 		}
6145 	}
6146 	else if (!strncmp (path, X_("/cue/new_bus"), 12) || !strncmp (path, X_("/cue/new_aux"), 12)) {
6147 		// Create new Aux bus
6148 		string name = "";
6149 		string dest_1 = "";
6150 		string dest_2 = "";
6151 		if (argc == 3 && types[0] == 's' && types[1] == 's' && types[2] == 's') {
6152 			name = &argv[0]->s;
6153 			dest_1 = &argv[1]->s;
6154 			dest_2 = &argv[2]->s;
6155 			ret = cue_new_aux (name, dest_1, dest_2, 2, msg);
6156 		} else if (argc == 2 && types[0] == 's' && types[1] == 's') {
6157 			name = &argv[0]->s;
6158 			dest_1 = &argv[1]->s;
6159 			dest_2 = dest_1;
6160 			ret = cue_new_aux (name, dest_1, dest_2, 1, msg);
6161 		} else if (argc == 1 && types[0] == 's') {
6162 			name = &argv[0]->s;
6163 			ret = cue_new_aux (name, dest_1, dest_2, 1, msg);
6164 		} else {
6165 			PBD::warning << "OSC: new_aux has wrong number or type of parameters." << endmsg;
6166 		}
6167 	}
6168 	else if (!strncmp (path, X_("/cue/new_send"), 13)) {
6169 		// Create new send to Foldback
6170 		string rt_name = "";
6171 		if (argc == 1 && types[0] == 's') {
6172 			rt_name = &argv[0]->s;
6173 			ret = cue_new_send (rt_name, msg);
6174 		} else {
6175 			PBD::warning << "OSC: new_send has wrong number or type of parameters." << endmsg;
6176 		}
6177 	}
6178 	else if (!strncmp (path, X_("/cue/next_bus"), 13) || !strncmp (path, X_("/cue/next_aux"), 13)) {
6179 		// switch to next Foldback bus
6180 		if ((!argc) || argv[0]->f || argv[0]->i) {
6181 			ret = cue_next (msg);
6182 		} else {
6183 			ret = 0;
6184 		}
6185 	}
6186 	else if (!strncmp (path, X_("/cue/previous_bus"), 17) || !strncmp (path, X_("/cue/previous_aux"), 17)) {
6187 		// switch to previous Foldback bus
6188 		if ((!argc) || argv[0]->f || argv[0]->i) {
6189 			ret = cue_previous (msg);
6190 		} else {
6191 			ret = 0;
6192 		}
6193 	}
6194 	else if (!strncmp (path, X_("/cue/send/fader/"), 16) && strlen (path) > 16) {
6195 		if (argc == 1) {
6196 			int id = atoi (&path[16]);
6197 			ret = cue_send_fader (id, value, msg);
6198 		}
6199 	}
6200 	else if (!strncmp (path, X_("/cue/send/enable/"), 17) && strlen (path) > 17) {
6201 		if (argc == 1) {
6202 			int id = atoi (&path[17]);
6203 			ret = cue_send_enable (id, value, msg);
6204 		}
6205 	}
6206 	else if (!strncmp (path, X_("/cue/fader"), 10)) {
6207 		if (argc == 1) {
6208 			ret = cue_aux_fader (value, msg);
6209 		}
6210 	}
6211 	else if (!strncmp (path, X_("/cue/mute"), 9)) {
6212 		if (argc == 1) {
6213 			ret = cue_aux_mute (value, msg);
6214 		}
6215 	}
6216 
6217 	return ret;
6218 }
6219 
6220 int
cue_set(uint32_t aux,lo_message msg)6221 OSC::cue_set (uint32_t aux, lo_message msg)
6222 {
6223 	return _cue_set (aux, get_address (msg));
6224 }
6225 
6226 int
_cue_set(uint32_t aux,lo_address addr)6227 OSC::_cue_set (uint32_t aux, lo_address addr)
6228 {
6229 	int ret = 1;
6230 	OSCSurface *s = get_surface(addr, true);
6231 	s->bank_size = 0;
6232 	s->strip_types = 128;
6233 	s->feedback = 0;
6234 	s->gainmode = 1;
6235 	s->cue = true;
6236 	s->strips = get_sorted_stripables(s->strip_types, s->cue, false, s->custom_strips);
6237 
6238 	s->nstrips = s->strips.size();
6239 	if (!s->nstrips) {
6240 		surface_destroy (s);
6241 		return 0;
6242 	}
6243 	if (aux < 1) {
6244 		aux = 1;
6245 	} else if (aux > s->nstrips) {
6246 		aux = s->nstrips;
6247 	}
6248 	s->aux = aux;
6249 	// get a list of Auxes
6250 	for (uint32_t n = 0; n < s->nstrips; ++n) {
6251 		boost::shared_ptr<Stripable> stp = s->strips[n];
6252 		if (stp) {
6253 			text_message (string_compose (X_("/cue/name/%1"), n+1), stp->name(), addr);
6254 			if (aux == n+1) {
6255 				// aux must be at least one
6256 
6257 				stp->DropReferences.connect (*this, MISSING_INVALIDATOR, boost::bind (&OSC::_cue_set, this, aux, addr), this);
6258 				// make a list of stripables with sends that go to this bus
6259 				s->sends = cue_get_sorted_stripables(stp, aux, addr);
6260 				if (s->cue_obs) {
6261 					s->cue_obs->refresh_strip (stp, s->sends, true);
6262 				} else {
6263 					// start cue observer
6264 					OSCCueObserver* co = new OSCCueObserver (*this, s);
6265 					s->cue_obs = co;
6266 				}
6267 				ret = 0;
6268 			}
6269 
6270 		}
6271 	}
6272 
6273 	return ret;
6274 }
6275 
6276 int
cue_new_aux(string name,string dest_1,string dest_2,uint32_t count,lo_message msg)6277 OSC::cue_new_aux (string name, string dest_1, string dest_2, uint32_t count, lo_message msg)
6278 {
6279 	// create a new bus named name - monitor
6280 	RouteList list;
6281 	boost::shared_ptr<Stripable> aux;
6282 	name = string_compose ("%1 - FB", name);
6283 	list = session->new_audio_route (count, count, 0, 1, name, PresentationInfo::FoldbackBus, (uint32_t) -1);
6284 	aux = *(list.begin());
6285 	if (aux) {
6286 		boost::shared_ptr<Route> r = boost::dynamic_pointer_cast<Route>(aux);
6287 		if (dest_1.size()) {
6288 			PortSet& ports = r->output()->ports ();
6289 			if (atoi( dest_1.c_str())) {
6290 				dest_1 = string_compose ("system:playback_%1", dest_1);
6291 			}
6292 			r->output ()->connect (*(ports.begin()), dest_1, this);
6293 			if (count == 2) {
6294 				if (atoi( dest_2.c_str())) {
6295 					dest_2 = string_compose ("system:playback_%1", dest_2);
6296 				}
6297 				PortSet::iterator i = ports.begin();
6298 				++i;
6299 				r->output ()->connect (*(i), dest_2, this);
6300 			}
6301 		}
6302 		cue_set ((uint32_t) -1, msg);
6303 		session->set_dirty();
6304 		return 0;
6305 	}
6306 	return -1;
6307 }
6308 
6309 int
cue_new_send(string rt_name,lo_message msg)6310 OSC::cue_new_send (string rt_name, lo_message msg)
6311 {
6312 	OSCSurface *sur = get_surface(get_address (msg), true);
6313 	if (sur->cue) {
6314 		boost::shared_ptr<Route> aux = boost::dynamic_pointer_cast<Route> (get_strip (sur->aux, get_address(msg)));
6315 		if (aux) {
6316 			boost::shared_ptr<Route> rt_send = session->route_by_name (rt_name);
6317 			if (rt_send && (aux != rt_send)) {
6318 				// make sure there isn't one already
6319 				bool s_only = true;
6320 				if (!rt_send->feeds (aux, &s_only)) {
6321 					// create send
6322 					rt_send->add_foldback_send (aux, false);
6323 					boost::shared_ptr<Send> snd = rt_send->internal_send_for (aux);
6324 					session->dirty ();
6325 					return 0;
6326 				} else {
6327 					PBD::warning << "OSC: new_send - duplicate send, ignored." << endmsg;
6328 				}
6329 			} else {
6330 				PBD::warning << "OSC: new_send - route doesn't exist or is aux." << endmsg;
6331 			}
6332 		} else {
6333 			PBD::warning << "OSC: new_send - No Aux to send to." << endmsg;
6334 		}
6335 	} else {
6336 		PBD::warning << "OSC: new_send - monitoring not set, select aux first." << endmsg;
6337 	}
6338 	return 1;
6339 }
6340 
6341 int
cue_connect_aux(std::string dest,lo_message msg)6342 OSC::cue_connect_aux (std::string dest, lo_message msg)
6343 {
6344 	OSCSurface *sur = get_surface(get_address (msg), true);
6345 	int ret = 1;
6346 	if (sur->cue) {
6347 		boost::shared_ptr<Route> rt = boost::dynamic_pointer_cast<Route> (get_strip (sur->aux, get_address(msg)));
6348 		if (rt) {
6349 			if (dest.size()) {
6350 				rt->output()->disconnect (this);
6351 				if (atoi( dest.c_str())) {
6352 					dest = string_compose ("system:playback_%1", dest);
6353 				}
6354 				PortSet& ports = rt->output()->ports ();
6355 				rt->output ()->connect (*(ports.begin()), dest, this);
6356 				session->set_dirty();
6357 				ret = 0;
6358 			}
6359 		}
6360 	}
6361 	if (ret) {
6362 		PBD::warning << "OSC: cannot connect, no Aux bus chosen." << endmsg;
6363 	}
6364 	return ret;
6365 }
6366 
6367 int
cue_next(lo_message msg)6368 OSC::cue_next (lo_message msg)
6369 {
6370 	OSCSurface *s = get_surface(get_address (msg), true);
6371 	int ret = 1;
6372 
6373 	if (!s->cue) {
6374 		ret = cue_set (1, msg);
6375 	}
6376 	if (s->aux < s->nstrips) {
6377 		ret = cue_set (s->aux + 1, msg);
6378 	} else {
6379 		ret = cue_set (s->nstrips, msg);
6380 	}
6381 	return ret;
6382 }
6383 
6384 int
cue_previous(lo_message msg)6385 OSC::cue_previous (lo_message msg)
6386 {
6387 	OSCSurface *s = get_surface(get_address (msg), true);
6388 	int ret = 1;
6389 	if (!s->cue) {
6390 		ret = cue_set (1, msg);
6391 	}
6392 	if (s->aux > 1) {
6393 		ret = cue_set (s->aux - 1, msg);
6394 	} else {
6395 		ret = cue_set (1, msg);
6396 	}
6397 	return ret;
6398 }
6399 
6400 boost::shared_ptr<Send>
cue_get_send(uint32_t id,lo_address addr)6401 OSC::cue_get_send (uint32_t id, lo_address addr)
6402 {
6403 	OSCSurface *s = get_surface(addr, true);
6404 	if (id && s->aux > 0 && id <= s->sends.size()) {
6405 		boost::shared_ptr<Route> r = boost::dynamic_pointer_cast<Route> (s->sends[id - 1]);
6406 		boost::shared_ptr<Stripable> aux = get_strip (s->aux, addr);
6407 		if (r && aux) {
6408 			return r->internal_send_for (boost::dynamic_pointer_cast<Route> (aux));
6409 		}
6410 	}
6411 	return boost::shared_ptr<Send>();
6412 
6413 }
6414 
6415 int
cue_aux_fader(float position,lo_message msg)6416 OSC::cue_aux_fader (float position, lo_message msg)
6417 {
6418 	if (!session) return -1;
6419 
6420 	OSCSurface *sur = get_surface(get_address (msg), true);
6421 	if (sur->cue) {
6422 		if (sur->aux) {
6423 			boost::shared_ptr<Stripable> s = get_strip (sur->aux, get_address (msg));
6424 
6425 			if (s) {
6426 				if (s->gain_control()) {
6427 					s->gain_control()->set_value (s->gain_control()->interface_to_internal (position), PBD::Controllable::NoGroup);
6428 					return 0;
6429 				}
6430 			}
6431 		}
6432 	}
6433 	float_message (X_("/cue/fader"), 0, get_address (msg));
6434 	return -1;
6435 }
6436 
6437 int
cue_aux_mute(float state,lo_message msg)6438 OSC::cue_aux_mute (float state, lo_message msg)
6439 {
6440 	if (!session) return -1;
6441 
6442 	OSCSurface *sur = get_surface(get_address (msg), true);
6443 	if (sur->cue) {
6444 		if (sur->aux) {
6445 			boost::shared_ptr<Stripable> s = get_strip (sur->aux, get_address (msg));
6446 			if (s) {
6447 				if (s->mute_control()) {
6448 					s->mute_control()->set_value (state ? 1.0 : 0.0, PBD::Controllable::NoGroup);
6449 					return 0;
6450 				}
6451 			}
6452 		}
6453 	}
6454 	float_message (X_("/cue/mute"), 0, get_address (msg));
6455 	return -1;
6456 }
6457 
6458 int
cue_send_fader(uint32_t id,float val,lo_message msg)6459 OSC::cue_send_fader (uint32_t id, float val, lo_message msg)
6460 {
6461 	if (!session) {
6462 		return -1;
6463 	}
6464 	boost::shared_ptr<Send> s = cue_get_send (id, get_address (msg));
6465 	if (s) {
6466 		if (s->gain_control()) {
6467 			s->gain_control()->set_value (s->gain_control()->interface_to_internal(val), PBD::Controllable::NoGroup);
6468 			return 0;
6469 		}
6470 	}
6471 	float_message (string_compose (X_("/cue/send/fader/%1"), id), 0, get_address (msg));
6472 	return -1;
6473 }
6474 
6475 int
cue_send_enable(uint32_t id,float state,lo_message msg)6476 OSC::cue_send_enable (uint32_t id, float state, lo_message msg)
6477 {
6478 	if (!session)
6479 		return -1;
6480 	boost::shared_ptr<Send> s = cue_get_send (id, get_address (msg));
6481 	if (s) {
6482 		if (state) {
6483 			s->activate ();
6484 		} else {
6485 			s->deactivate ();
6486 		}
6487 		return 0;
6488 	}
6489 	float_message (string_compose (X_("/cue/send/enable/%1"), id), 0, get_address (msg));
6490 	return -1;
6491 }
6492 
6493 // generic send message
6494 int
float_message(string path,float val,lo_address addr)6495 OSC::float_message (string path, float val, lo_address addr)
6496 {
6497 	_lo_lock.lock ();
6498 
6499 	lo_message reply;
6500 	reply = lo_message_new ();
6501 	lo_message_add_float (reply, (float) val);
6502 
6503 	lo_send_message (addr, path.c_str(), reply);
6504 	Glib::usleep(1);
6505 	lo_message_free (reply);
6506 	_lo_lock.unlock ();
6507 
6508 	return 0;
6509 }
6510 
6511 int
float_message_with_id(std::string path,uint32_t ssid,float value,bool in_line,lo_address addr)6512 OSC::float_message_with_id (std::string path, uint32_t ssid, float value, bool in_line, lo_address addr)
6513 {
6514 	_lo_lock.lock ();
6515 	lo_message msg = lo_message_new ();
6516 	if (in_line) {
6517 		path = string_compose ("%1/%2", path, ssid);
6518 	} else {
6519 		lo_message_add_int32 (msg, ssid);
6520 	}
6521 	lo_message_add_float (msg, value);
6522 
6523 	lo_send_message (addr, path.c_str(), msg);
6524 	Glib::usleep(1);
6525 	lo_message_free (msg);
6526 	_lo_lock.unlock ();
6527 	return 0;
6528 }
6529 
6530 int
int_message(string path,int val,lo_address addr)6531 OSC::int_message (string path, int val, lo_address addr)
6532 {
6533 	_lo_lock.lock ();
6534 
6535 	lo_message reply;
6536 	reply = lo_message_new ();
6537 	lo_message_add_int32 (reply, (float) val);
6538 
6539 	lo_send_message (addr, path.c_str(), reply);
6540 	Glib::usleep(1);
6541 	lo_message_free (reply);
6542 	_lo_lock.unlock ();
6543 
6544 	return 0;
6545 }
6546 
6547 int
int_message_with_id(std::string path,uint32_t ssid,int value,bool in_line,lo_address addr)6548 OSC::int_message_with_id (std::string path, uint32_t ssid, int value, bool in_line, lo_address addr)
6549 {
6550 	_lo_lock.lock ();
6551 	lo_message msg = lo_message_new ();
6552 	if (in_line) {
6553 		path = string_compose ("%1/%2", path, ssid);
6554 	} else {
6555 		lo_message_add_int32 (msg, ssid);
6556 	}
6557 	lo_message_add_int32 (msg, value);
6558 
6559 	lo_send_message (addr, path.c_str(), msg);
6560 	Glib::usleep(1);
6561 	lo_message_free (msg);
6562 	_lo_lock.unlock ();
6563 	return 0;
6564 }
6565 
6566 int
text_message(string path,string val,lo_address addr)6567 OSC::text_message (string path, string val, lo_address addr)
6568 {
6569 	_lo_lock.lock ();
6570 
6571 	lo_message reply;
6572 	reply = lo_message_new ();
6573 	lo_message_add_string (reply, val.c_str());
6574 
6575 	lo_send_message (addr, path.c_str(), reply);
6576 	Glib::usleep(1);
6577 	lo_message_free (reply);
6578 	_lo_lock.unlock ();
6579 
6580 	return 0;
6581 }
6582 
6583 int
text_message_with_id(std::string path,uint32_t ssid,std::string val,bool in_line,lo_address addr)6584 OSC::text_message_with_id (std::string path, uint32_t ssid, std::string val, bool in_line, lo_address addr)
6585 {
6586 	_lo_lock.lock ();
6587 	lo_message msg = lo_message_new ();
6588 	if (in_line) {
6589 		path = string_compose ("%1/%2", path, ssid);
6590 	} else {
6591 		lo_message_add_int32 (msg, ssid);
6592 	}
6593 
6594 	lo_message_add_string (msg, val.c_str());
6595 
6596 	lo_send_message (addr, path.c_str(), msg);
6597 	Glib::usleep(1);
6598 	lo_message_free (msg);
6599 	_lo_lock.unlock ();
6600 	return 0;
6601 }
6602 
6603 // we have to have a sorted list of stripables that have sends pointed at our aux
6604 // we can use the one in osc.cc to get an aux list
6605 OSC::Sorted
cue_get_sorted_stripables(boost::shared_ptr<Stripable> aux,uint32_t id,lo_address addr)6606 OSC::cue_get_sorted_stripables(boost::shared_ptr<Stripable> aux, uint32_t id, lo_address addr)
6607 {
6608 	Sorted sorted;
6609 
6610 	boost::shared_ptr<Route> aux_rt = boost::dynamic_pointer_cast<Route> (aux);
6611 	Route::FedBy fed_by = aux_rt->fed_by();
6612 	for (Route::FedBy::iterator i = fed_by.begin(); i != fed_by.end(); ++i) {
6613 		if (i->sends_only) {
6614 			boost::shared_ptr<Stripable> s (i->r.lock());
6615 			sorted.push_back (s);
6616 			s->DropReferences.connect (*this, MISSING_INVALIDATOR, boost::bind (&OSC::_cue_set, this, id, addr), this);
6617 		}
6618 	}
6619 	sort (sorted.begin(), sorted.end(), StripableByPresentationOrder());
6620 
6621 	return sorted;
6622 }
6623 
6624