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