summaryrefslogtreecommitdiff
path: root/libs/surfaces/osc/osc.h
blob: 41d0531617d16dbfdbe46ed40ad21f42878bd306 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
/*
 * Copyright (C) 2006-2009 Paul Davis
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 */

#ifndef ardour_osc_h
#define ardour_osc_h

#include <string>
#include <vector>
#include <bitset>

#include <sys/time.h>
#include <pthread.h>

#include <boost/shared_ptr.hpp>

#include <lo/lo.h>

#include <glibmm/main.h>

#define ABSTRACT_UI_EXPORTS
#include "pbd/abstract_ui.h"

#include "ardour/types.h"
#include "ardour/send.h"
#include "ardour/plugin.h"
#include "control_protocol/control_protocol.h"

#include "pbd/i18n.h"

class OSCControllable;
class OSCRouteObserver;
class OSCGlobalObserver;
class OSCSelectObserver;
class OSCCueObserver;

namespace ARDOUR {
class Session;
class Route;
}

/* this is mostly a placeholder because I suspect that at some
   point we will want to add more members to accomodate
   certain types of requests to the OSC UI
*/

namespace ArdourSurface {

struct OSCUIRequest : public BaseUI::BaseRequestObject {
  public:
	OSCUIRequest () {}
	~OSCUIRequest() {}
};

class OSC : public ARDOUR::ControlProtocol, public AbstractUI<OSCUIRequest>
{
  public:
	OSC (ARDOUR::Session&, uint32_t port);
	virtual ~OSC();

	static OSC* instance() { return _instance; }

	XMLNode& get_state ();
	int set_state (const XMLNode&, int version);

	void stripable_selection_changed () {}

	bool has_editor () const { return true; }
	void* get_gui () const;
	void  tear_down_gui ();

	int set_active (bool yn);
	bool get_active () const;

	// generic osc send
	Glib::Threads::Mutex _lo_lock;
	int float_message (std::string, float value, lo_address addr);
	int int_message (std::string, int value, lo_address addr);
	int text_message (std::string path, std::string val, lo_address addr);
	int float_message_with_id (std::string, uint32_t ssid, float value, bool in_line, lo_address addr);
	int int_message_with_id (std::string, uint32_t ssid, int value, bool in_line, lo_address addr);
	int text_message_with_id (std::string path, uint32_t ssid, std::string val, bool in_line, lo_address addr);

	int send_group_list (lo_address addr);

	int start ();
	int stop ();

	static void* request_factory (uint32_t);

	enum OSCDebugMode {
		Off,
		Unhandled,
		All
	};

	enum OSCTempMode {
		TempOff = 0,
		GroupOnly = 1,
		VCAOnly = 2,
		BusOnly = 3
	};

	typedef std::vector<boost::shared_ptr<ARDOUR::Stripable> > Sorted;
	Sorted get_sorted_stripables(std::bitset<32> types, bool cue, uint32_t custom, Sorted my_list);
	typedef std::map<boost::shared_ptr<ARDOUR::AutomationControl>, uint32_t> FakeTouchMap;
	FakeTouchMap _touch_timeout;

// keep a surface's global setup by remote server url
	struct OSCSurface {
	public:
		//global
		std::string remote_url;		// the url these setting belong to
		bool no_clear;				// don't send osc clear messages on strip change
		uint32_t jogmode;			// current jogmode
		OSCGlobalObserver* global_obs;	// pointer to this surface's global observer
		uint32_t nstrips;			// how many strips are there for strip_types
		std::bitset<32> feedback;	// What is fed back? strips/meters/timecode/bar_beat/global
		int gainmode;				// what kind of faders do we have Gain db or position 0 to 1?
		PBD::Controllable::GroupControlDisposition usegroup;	// current group disposition
		Sorted custom_strips;		// a sorted list of user selected strips
		uint32_t custom_mode;		// use custom strip list
		OSCTempMode temp_mode;		// use temp strip list
		Sorted temp_strips;			// temp strip list for grouponly, vcaonly, auxonly
		boost::shared_ptr<ARDOUR::Stripable> temp_master; // stripable this surface uses as temp master
		Sorted strips;				// list of stripables for this surface
		// strips
		uint32_t bank;				// current bank
		uint32_t bank_size;			// size of banks for this surface
		std::vector<OSCRouteObserver*> observers;	// route observers for this surface
		std::bitset<32> strip_types;// what strip types are a part of this bank
		//select
		OSCSelectObserver* sel_obs;	// So we can sync select feedback with selected channel
		uint32_t expand;			// Used by /select/select
		bool expand_enable;			// use expand instead of select
		boost::shared_ptr<ARDOUR::Stripable> expand_strip; // stripable this surface uses for expand
		boost::shared_ptr<ARDOUR::Stripable> select; // stripable this surface uses as selected
		int plug_page;				// current plugin page
		uint32_t plug_page_size;	// plugin page size (number of controls)
		int plugin_id;			// id of current plugin
		std::vector<int> plug_params; // vector to store ports that are controls
		std::vector<int> plugins;	// stores allowable plugins with index (work around MB strip PIs)
		int send_page;				// current send page
		uint32_t send_page_size;	// send page size in channels
		uint32_t nsends;			// number of sends select has
		PBD::ScopedConnection proc_connection; // for processor signal monitoring
		// cue
		bool cue;					// is this a cue surface
		uint32_t aux;				// aux index for this cue surface
		Sorted sends;				// list of sends for cue aux
		OSCCueObserver* cue_obs;	// pointer to this surface's cue observer
		uint32_t linkset;			// ID of a set of surfaces used as one
		uint32_t linkid;			// ID of this surface within a linkset
	};
		/*
		 * feedback bits:
		 * [0] - Strips - buttons
		 * [1] - Strips - variables (pots/faders)
		 * [2] - Strips - Send SSID as path extension
		 * [3] - Send heart beat to surface
		 * [4] - Send feedback for master/global buttons/variables
		 * [5] - Send Bar and Beat
		 * [6] - Send Time code
		 * [7] - Send metering as dB or positional depending on gainmode
		 * [8] - Send metering as 16 bits (led strip)
		 * [9] - Send signal present (signal greater than -20dB)
		 * [10] - Send Playhead position as samples
		 * [11] - Send Playhead position as minutes seconds
		 * [12]	- Send Playhead position like primary/secondary GUI clocks
		 * [13] - Send well known feedback (for /select/command
		 * [14] - use OSC 1.0 only (#reply -> /reply)
		 *
		 * Strip_type bits:
		 * [0] - Audio Tracks
		 * [1] - Midi Tracks
		 * [2] - Audio Bus
		 * [3] - Midi Bus
		 * [4] - VCAs
		 * [5] - master
		 * [6] - Monitor
		 * [7] - Aux Bus
		 * [8] - Selected
		 * [9] - Hidden
		 * [10] - Use Groups
		 * [11] - Global Expand
		 */

// storage for  each surface's settings
	mutable Glib::Threads::Mutex surfaces_lock;
	typedef std::vector<OSCSurface> Surface;
	Surface _surface;

// linked surfaces
	struct LinkSet {
	public:
		std::vector<std::string> urls;	//urls of linked surfaces
		uint32_t banksize;				// linkset banksize
		uint32_t bank;					// linkset current bank
		bool autobank;					// banksize is derived from total
		uint32_t not_ready;				// number of 1st device, 0 = ready
		Sorted custom_strips;			// a sorted list of user selected strips
		uint32_t custom_mode;			// use custom strip list
		OSCTempMode temp_mode;			// use custom strip list
		Sorted temp_strips;				// temp strip list for grouponly, vcaonly, auxonly
		boost::shared_ptr<ARDOUR::Stripable> temp_master; // temp master stripable
		std::bitset<32> strip_types;	// strip_types for this linkset
		Sorted strips;					// list of valid strips in order for this set
	};

	std::map<uint32_t, LinkSet> link_sets;
	 // list of linksets

	struct PortAdd {
	public:
		std::string host;
		std::string port;
	};

	std::vector<PortAdd> _ports;

// GUI calls
	std::string get_server_url ();
	void set_debug_mode (OSCDebugMode m) { _debugmode = m; }
	OSCDebugMode get_debug_mode () { return _debugmode; }
	int get_portmode() { return address_only; }
	void set_portmode (int pm) { address_only = pm; }
	int get_banksize () { return default_banksize; }
	void set_banksize (int bs) {default_banksize = bs; }
	int get_gainmode() { return default_gainmode; }
	void set_gainmode (int gm) { default_gainmode = gm; }
	int get_defaultstrip() { return default_strip; }
	void set_defaultstrip (int st) { default_strip = st; }
	int get_defaultfeedback() { return default_feedback; }
	void set_defaultfeedback (int fb) { default_feedback = fb; }
	int get_send_size() { return default_send_size; }
	void set_send_size (int ss) { default_send_size = ss; }
	int get_plugin_size() { return default_plugin_size; }
	void set_plugin_size (int ps) { default_plugin_size = ps; }
	void clear_devices ();
	void gui_changed ();
	void get_surfaces ();
	std::string get_remote_port () { return remote_port; }
	void set_remote_port (std::string pt) { remote_port = pt; }

  protected:
        void thread_init ();
	void do_request (OSCUIRequest*);

	GSource* local_server;
	GSource* remote_server;

	bool osc_input_handler (Glib::IOCondition, lo_server);

  private:
	uint32_t _port;
	volatile bool _ok;
	volatile bool _shutdown;
	lo_server _osc_server;
	lo_server _osc_unix_server;
	std::string _osc_unix_socket_path;
	std::string _osc_url_file;
	OSCDebugMode _debugmode;
	bool address_only;
	std::string remote_port;
	uint32_t default_banksize;
	uint32_t default_strip;
	uint32_t default_feedback;
	uint32_t default_gainmode;
	uint32_t default_send_size;
	uint32_t default_plugin_size;
	bool tick;
	bool bank_dirty;
	bool observer_busy;
	float scrub_speed;		// Current scrub speed
	double scrub_place;		// place of play head at latest jog/scrub wheel tick
	int64_t scrub_time;		// when did the wheel move last?
	bool global_init;
	boost::shared_ptr<ARDOUR::Stripable> _select;	// which stripable out of /surface/stripables is gui selected

	void register_callbacks ();

	void route_added (ARDOUR::RouteList&);

	// Handlers for "Application Hook" signals
	void session_loaded (ARDOUR::Session&);
	void session_exported (std::string, std::string);

	// end "Application Hook" handles

	std::string get_unix_server_url ();
	lo_address get_address (lo_message msg);
	std::string get_port (std::string host);
	OSCSurface * get_surface (lo_address addr, bool quiet = false);
	int check_surface (lo_message msg);
	uint32_t get_sid (boost::shared_ptr<ARDOUR::Stripable> strip, lo_address addr);
	boost::shared_ptr<ARDOUR::Stripable> get_strip (uint32_t ssid, lo_address addr);
	void global_feedback (OSCSurface* sur);
	void strip_feedback (OSCSurface* sur, bool new_bank_size);
	void surface_destroy (OSCSurface* sur);
	uint32_t bank_limits_check (uint32_t bank, uint32_t size, uint32_t total);
	void bank_leds (OSCSurface* sur);

	void send_current_value (const char* path, lo_arg** argv, int argc, lo_message msg);
	void current_value_query (const char* path, size_t len, lo_arg **argv, int argc, lo_message msg);

	int current_value (const char *path, const char *types, lo_arg **argv, int argc, void *data, void *user_data);

	int catchall (const char *path, const char *types, lo_arg **argv, int argc, void *data);
	static int _catchall (const char *path, const char *types, lo_arg **argv, int argc, void *data, void *user_data);

	int set_automation (const char *path, const char* types, lo_arg **argv, int argc, lo_message msg);
	int touch_detect (const char *path, const char* types, lo_arg **argv, int argc, lo_message msg);
	int fake_touch (boost::shared_ptr<ARDOUR::AutomationControl> ctrl);

	int spill (const char *path, const char* types, lo_arg **argv, int argc, lo_message msg);

	int route_get_sends (lo_message msg);
	int route_get_receives(lo_message msg);
	void routes_list (lo_message msg);
	int group_list (lo_message msg);
	void surface_list (lo_message msg);
	void transport_sample (lo_message msg);
	void transport_speed (lo_message msg);
	void record_enabled (lo_message msg);

	// cue
	Sorted cue_get_sorted_stripables(boost::shared_ptr<ARDOUR::Stripable> aux, uint32_t id, lo_message msg);
	int cue_parse (const char *path, const char* types, lo_arg **argv, int argc, lo_message msg);
	int cue_set (uint32_t aux, lo_message msg);
	int _cue_set (uint32_t aux, lo_address addr);
	int cue_new_aux (std::string name, std::string dest, lo_message msg);
	int cue_next (lo_message msg);
	int cue_previous (lo_message msg);
	int cue_send_fader (uint32_t id, float position, lo_message msg);
	int cue_send_enable (uint32_t id, float state, lo_message msg);
	int cue_aux_fader (float position, lo_message msg);
	int cue_aux_mute (float state, lo_message msg);
	void cue_set_aux (uint32_t aux, lo_message msg);
	boost::shared_ptr<ARDOUR::Send> cue_get_send (uint32_t id, lo_address addr);
	// end cue

	// link
	LinkSet * get_linkset (uint32_t set, lo_address addr);
	int parse_link (const char *path, const char* types, lo_arg **argv, int argc, lo_message msg);
	int link_check (uint32_t linkset);
	int set_link (uint32_t set, uint32_t id, lo_address addr);
	void surface_link_state (LinkSet * set);
	void link_strip_types (uint32_t linkset, uint32_t striptypes);

#define OSC_DEBUG \
	if (_debugmode == All) { \
		debugmsg (dgettext(PACKAGE, "OSC"), path, types, argv, argc); \
	}

#define PATH_CALLBACK_MSG(name) \
	static int _ ## name (const char *path, const char *types, lo_arg **argv, int argc, void *data, void *user_data) { \
		return static_cast<OSC*>(user_data)->cb_ ## name (path, types, argv, argc, data); \
	} \
	int cb_ ## name (const char *path, const char *types, lo_arg **argv, int argc, void *data) { \
		OSC_DEBUG; \
		if (argc > 0 && !strcmp (types, "f") && argv[0]->f != 1.0) { return 0; } \
		name (data); \
		return 0; \
	}

	PATH_CALLBACK_MSG(route_get_sends);
	PATH_CALLBACK_MSG(route_get_receives);
	PATH_CALLBACK_MSG(routes_list);
	PATH_CALLBACK_MSG(group_list);
	PATH_CALLBACK_MSG(sel_previous);
	PATH_CALLBACK_MSG(sel_next);
	PATH_CALLBACK_MSG(surface_list);
	PATH_CALLBACK_MSG(transport_sample);
	PATH_CALLBACK_MSG(transport_speed);
	PATH_CALLBACK_MSG(record_enabled);
	PATH_CALLBACK_MSG(refresh_surface);
	PATH_CALLBACK_MSG(bank_up);
	PATH_CALLBACK_MSG(bank_down);
	PATH_CALLBACK_MSG(master_select);
	PATH_CALLBACK_MSG(custom_clear);

#define PATH_CALLBACK(name) \
	static int _ ## name (const char *path, const char *types, lo_arg **argv, int argc, void *data, void *user_data) { \
		return static_cast<OSC*>(user_data)->cb_ ## name (path, types, argv, argc, data); \
	} \
	int cb_ ## name (const char *path, const char *types, lo_arg ** argv, int argc, void *data) { \
		OSC_DEBUG; \
		check_surface (data); \
		if (argc > 0 && !strcmp (types, "f") && argv[0]->f != 1.0) { return 0; } \
		name (); \
		return 0; \
	}

	PATH_CALLBACK(add_marker);
	PATH_CALLBACK(loop_toggle);
	PATH_CALLBACK(goto_start);
	PATH_CALLBACK(goto_end);
	PATH_CALLBACK(rewind);
	PATH_CALLBACK(ffwd);
	PATH_CALLBACK(transport_stop);
	PATH_CALLBACK(transport_play);
	PATH_CALLBACK(save_state);
	PATH_CALLBACK(prev_marker);
	PATH_CALLBACK(next_marker);
	PATH_CALLBACK(undo);
	PATH_CALLBACK(redo);
	PATH_CALLBACK(toggle_punch_in);
	PATH_CALLBACK(toggle_punch_out);
	PATH_CALLBACK(rec_enable_toggle);
	PATH_CALLBACK(toggle_all_rec_enables);
	PATH_CALLBACK(all_tracks_rec_in);
	PATH_CALLBACK(all_tracks_rec_out);
	PATH_CALLBACK(cancel_all_solos);
	PATH_CALLBACK(remove_marker_at_playhead);
	PATH_CALLBACK(mark_in);
	PATH_CALLBACK(mark_out);
	PATH_CALLBACK(toggle_click);
	PATH_CALLBACK(midi_panic);
	PATH_CALLBACK(toggle_roll);
	PATH_CALLBACK(stop_forget);
	PATH_CALLBACK(set_punch_range);
	PATH_CALLBACK(set_loop_range);
	PATH_CALLBACK(set_session_range);
	PATH_CALLBACK(toggle_monitor_mute);
	PATH_CALLBACK(toggle_monitor_dim);
	PATH_CALLBACK(toggle_monitor_mono);
	PATH_CALLBACK(quick_snapshot_stay);
	PATH_CALLBACK(quick_snapshot_switch);
	PATH_CALLBACK(fit_1_track);
	PATH_CALLBACK(fit_2_tracks);
	PATH_CALLBACK(fit_4_tracks);
	PATH_CALLBACK(fit_8_tracks);
	PATH_CALLBACK(fit_16_tracks);
	PATH_CALLBACK(fit_32_tracks);
	PATH_CALLBACK(fit_all_tracks);
	PATH_CALLBACK(zoom_100_ms);
	PATH_CALLBACK(zoom_1_sec);
	PATH_CALLBACK(zoom_10_sec);
	PATH_CALLBACK(zoom_1_min);
	PATH_CALLBACK(zoom_5_min);
	PATH_CALLBACK(zoom_10_min);
	PATH_CALLBACK(zoom_to_session);
	PATH_CALLBACK(temporal_zoom_in);
	PATH_CALLBACK(temporal_zoom_out);
	PATH_CALLBACK(scroll_up_1_track);
	PATH_CALLBACK(scroll_dn_1_track);
	PATH_CALLBACK(scroll_up_1_page);
	PATH_CALLBACK(scroll_dn_1_page);

#define PATH_CALLBACK1(name,type,optional) \
	static int _ ## name (const char *path, const char *types, lo_arg **argv, int argc, void *data, void *user_data) { \
		return static_cast<OSC*>(user_data)->cb_ ## name (path, types, argv, argc, data); \
	} \
	int cb_ ## name (const char *path, const char *types, lo_arg **argv, int argc, void *data) { \
		OSC_DEBUG; \
		check_surface (data); \
		if (argc > 0) { \
			name (optional argv[0]->type); \
		} \
		return 0; \
	}

	PATH_CALLBACK1(set_transport_speed,f,);
	PATH_CALLBACK1(access_action,s,&);

	PATH_CALLBACK1(jump_by_bars,f,);
	PATH_CALLBACK1(jump_by_seconds,f,);
	PATH_CALLBACK1(master_set_gain,f,);
	PATH_CALLBACK1(master_set_fader,f,);
	PATH_CALLBACK1(master_delta_gain,f,);
	PATH_CALLBACK1(master_set_trim,f,);
	PATH_CALLBACK1(master_set_mute,i,);
	PATH_CALLBACK1(monitor_set_gain,f,);
	PATH_CALLBACK1(monitor_set_fader,f,);
	PATH_CALLBACK1(monitor_delta_gain,f,);
	PATH_CALLBACK1(monitor_set_mute,i,);
	PATH_CALLBACK1(monitor_set_dim,i,);
	PATH_CALLBACK1(monitor_set_mono,i,);
	PATH_CALLBACK1(click_level,f,);

#define PATH_CALLBACK1_MSG(name,arg1type) \
	static int _ ## name (const char *path, const char *types, lo_arg **argv, int argc, void *data, void *user_data) { \
		return static_cast<OSC*>(user_data)->cb_ ## name (path, types, argv, argc, data); \
	} \
	int cb_ ## name (const char *path, const char *types, lo_arg **argv, int argc, void *data) { \
		OSC_DEBUG; \
		if (argc > 0) { \
			name (argv[0]->arg1type, data); \
		} \
		return 0; \
	}

#define PATH_CALLBACK1_MSG_s(name,arg1type) \
	static int _ ## name (const char *path, const char *types, lo_arg **argv, int argc, void *data, void *user_data) { \
		return static_cast<OSC*>(user_data)->cb_ ## name (path, types, argv, argc, data); \
	} \
	int cb_ ## name (const char *path, const char *types, lo_arg **argv, int argc, void *data) { \
		OSC_DEBUG; \
		if (argc > 0) { \
			name (&argv[0]->arg1type, data); \
		} \
		return 0; \
	}

	// pan position needs message info to send feedback
	PATH_CALLBACK1_MSG(master_set_pan_stereo_position,f);

	PATH_CALLBACK1_MSG(scrub,f);
	PATH_CALLBACK1_MSG(jog,f);
	PATH_CALLBACK1_MSG(jog_mode,f);
	PATH_CALLBACK1_MSG(bank_delta,f);
	PATH_CALLBACK1_MSG(use_group,f);
	PATH_CALLBACK1_MSG_s(name_session,s);
	PATH_CALLBACK1_MSG_s(sel_rename,s);
	PATH_CALLBACK1_MSG_s(sel_comment,s);
	PATH_CALLBACK1_MSG(sel_recenable,i);
	PATH_CALLBACK1_MSG(sel_recsafe,i);
	PATH_CALLBACK1_MSG(sel_mute,i);
	PATH_CALLBACK1_MSG(sel_master_send_enable,i);
	PATH_CALLBACK1_MSG(sel_solo,i);
	PATH_CALLBACK1_MSG(sel_solo_iso,i);
	PATH_CALLBACK1_MSG(sel_solo_safe,i);
	PATH_CALLBACK1_MSG(sel_monitor_input,i);
	PATH_CALLBACK1_MSG(sel_monitor_disk,i);
	PATH_CALLBACK1_MSG(sel_phase,i);
	PATH_CALLBACK1_MSG(sel_gain,f);
	PATH_CALLBACK1_MSG(sel_fader,f);
	PATH_CALLBACK1_MSG(sel_dB_delta,f);
	PATH_CALLBACK1_MSG(sel_trim,f);
	PATH_CALLBACK1_MSG(sel_hide,i);
	PATH_CALLBACK1_MSG(sel_pan_position,f);
	PATH_CALLBACK1_MSG(sel_pan_width,f);
	PATH_CALLBACK1_MSG(sel_pan_elevation,f);
	PATH_CALLBACK1_MSG(sel_pan_frontback,f);
	PATH_CALLBACK1_MSG(sel_pan_lfe,f);
	PATH_CALLBACK1_MSG(sel_send_page,f);
	PATH_CALLBACK1_MSG(sel_plug_page,f);
	PATH_CALLBACK1_MSG(sel_plugin,f);
	PATH_CALLBACK1_MSG(sel_plugin_activate,f);
	PATH_CALLBACK1_MSG(sel_comp_enable,f);
	PATH_CALLBACK1_MSG(sel_comp_threshold,f);
	PATH_CALLBACK1_MSG(sel_comp_speed,f);
	PATH_CALLBACK1_MSG(sel_comp_mode,f);
	PATH_CALLBACK1_MSG(sel_comp_makeup,f);
	PATH_CALLBACK1_MSG(sel_eq_enable,f);
	PATH_CALLBACK1_MSG(sel_eq_hpf_freq,f);
	PATH_CALLBACK1_MSG(sel_eq_hpf_enable,f);
	PATH_CALLBACK1_MSG(sel_eq_hpf_slope,f);
	PATH_CALLBACK1_MSG(sel_eq_lpf_freq,f);
	PATH_CALLBACK1_MSG(sel_eq_lpf_enable,f);
	PATH_CALLBACK1_MSG(sel_eq_lpf_slope,f);
	PATH_CALLBACK1_MSG(sel_expand,i);
	PATH_CALLBACK1_MSG(custom_mode,f);

#define PATH_CALLBACK2(name,arg1type,arg2type) \
	static int _ ## name (const char *path, const char *types, lo_arg **argv, int argc, void *data, void *user_data) { \
		return static_cast<OSC*>(user_data)->cb_ ## name (path, types, argv, argc, data); \
	} \
	int cb_ ## name (const char *path, const char *types, lo_arg **argv, int argc, void *data) { \
		OSC_DEBUG; \
		check_surface (data); \
		if (argc > 1) { \
			name (argv[0]->arg1type, argv[1]->arg2type); \
		} \
		return 0; \
	}

#define PATH_CALLBACK2_MSG(name,arg1type,arg2type) \
	static int _ ## name (const char *path, const char *types, lo_arg **argv, int argc, void *data, void *user_data) { \
		return static_cast<OSC*>(user_data)->cb_ ## name (path, types, argv, argc, data); \
	} \
	int cb_ ## name (const char *path, const char *types, lo_arg **argv, int argc, void *data) { \
		OSC_DEBUG; \
		if (argc > 1) {	\
			name (argv[0]->arg1type, argv[1]->arg2type, data); \
		} \
		return 0; \
	}

#define PATH_CALLBACK2_MSG_s(name,arg1type,arg2type) \
	static int _ ## name (const char *path, const char *types, lo_arg **argv, int argc, void *data, void *user_data) { \
		return static_cast<OSC*>(user_data)->cb_ ## name (path, types, argv, argc, data); \
	} \
	int cb_ ## name (const char *path, const char *types, lo_arg **argv, int argc, void *data) { \
		OSC_DEBUG; \
		if (argc > 1) {	\
			name (argv[0]->arg1type, &argv[1]->arg2type, data); \
		} \
		return 0; \
	}

#define PATH_CALLBACK3(name,arg1type,arg2type,arg3type) \
	static int _ ## name (const char *path, const char *types, lo_arg **argv, int argc, void *data, void *user_data) { \
		return static_cast<OSC*>(user_data)->cb_ ## name (path, types, argv, argc, data); \
	} \
	int cb_ ## name (const char *path, const char *types, lo_arg **argv, int argc, void *data) { \
		OSC_DEBUG; \
		if (argc > 1) { \
			name (argv[0]->arg1type, argv[1]->arg2type,argv[2]->arg3type, data); \
		} \
		return 0; \
	}

#define PATH_CALLBACK4(name,arg1type,arg2type,arg3type,arg4type) \
	static int _ ## name (const char *path, const char *types, lo_arg **argv, int argc, void *data, void *user_data) { \
		return static_cast<OSC*>(user_data)->cb_ ## name (path, types, argv, argc, data); \
	} \
	int cb_ ## name (const char *path, const char *types, lo_arg **argv, int argc, void *data) { \
		OSC_DEBUG; \
		if (argc > 1) { \
			name (argv[0]->arg1type, argv[1]->arg2type,argv[2]->arg3type,argv[3]->arg4type, data); \
		} \
		return 0; \
	}

	PATH_CALLBACK2_MSG(sel_sendgain,i,f);
	PATH_CALLBACK2_MSG(sel_sendfader,i,f);
	PATH_CALLBACK2_MSG(sel_sendenable,i,f);
	PATH_CALLBACK2_MSG(sel_eq_gain,i,f);
	PATH_CALLBACK2_MSG(sel_eq_freq,i,f);
	PATH_CALLBACK2_MSG(sel_eq_q,i,f);
	PATH_CALLBACK2_MSG(sel_eq_shape,i,f);

	PATH_CALLBACK2(locate,i,i);
	PATH_CALLBACK2(loop_location,i,i);
	PATH_CALLBACK2_MSG_s(route_rename,i,s);
	PATH_CALLBACK2_MSG_s(strip_group,i,s);
	PATH_CALLBACK2_MSG(route_mute,i,i);
	PATH_CALLBACK2_MSG(route_solo,i,i);
	PATH_CALLBACK2_MSG(route_solo_iso,i,i);
	PATH_CALLBACK2_MSG(route_solo_safe,i,i);
	PATH_CALLBACK2_MSG(route_recenable,i,i);
	PATH_CALLBACK2_MSG(route_recsafe,i,i);
	PATH_CALLBACK2_MSG(route_monitor_input,i,i);
	PATH_CALLBACK2_MSG(route_monitor_disk,i,i);
	PATH_CALLBACK2_MSG(strip_phase,i,i);
	PATH_CALLBACK2_MSG(strip_expand,i,i);
	PATH_CALLBACK2_MSG(strip_hide,i,i);
	PATH_CALLBACK2_MSG(strip_gui_select,i,i);
	PATH_CALLBACK2_MSG(route_set_gain_dB,i,f);
	PATH_CALLBACK2_MSG(route_set_gain_fader,i,f);
	PATH_CALLBACK2_MSG(strip_db_delta,i,f);
	PATH_CALLBACK2_MSG(route_set_trim_dB,i,f);
	PATH_CALLBACK2_MSG(route_set_pan_stereo_position,i,f);
	PATH_CALLBACK2_MSG(route_set_pan_stereo_width,i,f);
	PATH_CALLBACK3(route_set_send_gain_dB,i,i,f);
	PATH_CALLBACK3(route_set_send_fader,i,i,f);
	PATH_CALLBACK3(route_set_send_enable,i,i,f);
	PATH_CALLBACK4(route_plugin_parameter,i,i,i,f);
	PATH_CALLBACK3(route_plugin_parameter_print,i,i,i);
	PATH_CALLBACK2_MSG(route_plugin_activate,i,i);
	PATH_CALLBACK2_MSG(route_plugin_deactivate,i,i);
	PATH_CALLBACK1_MSG(route_plugin_list,i);
	PATH_CALLBACK2_MSG(route_plugin_descriptor,i,i);
	PATH_CALLBACK2_MSG(route_plugin_reset,i,i);

	int route_rename (int rid, char *s, lo_message msg);
	int strip_group (int ssid, char *g, lo_message msg);
	int strip_select_group (boost::shared_ptr<ARDOUR::Stripable> s, char *g);
	int route_mute (int rid, int yn, lo_message msg);
	int route_solo (int rid, int yn, lo_message msg);
	int route_solo_iso (int rid, int yn, lo_message msg);
	int route_solo_safe (int rid, int yn, lo_message msg);
	int route_recenable (int rid, int yn, lo_message msg);
	int route_recsafe (int ssid, int yn, lo_message msg);
	int route_monitor_input (int rid, int yn, lo_message msg);
	int route_monitor_disk (int rid, int yn, lo_message msg);
	int strip_phase (int rid, int yn, lo_message msg);
	int strip_expand (int rid, int yn, lo_message msg);
	int strip_hide (int ssid, int yn, lo_message msg);
	int _strip_select (boost::shared_ptr<ARDOUR::Stripable> s, lo_address addr);
	int strip_gui_select (int rid, int yn, lo_message msg);
	int route_set_gain_dB (int rid, float dB, lo_message msg);
	int route_set_gain_fader (int rid, float pos, lo_message msg);
	int strip_db_delta (int ssid, float delta, lo_message msg);
	int route_set_trim_abs (int rid, float level, lo_message msg);
	int route_set_trim_dB (int rid, float dB, lo_message msg);
	int route_set_pan_stereo_position (int rid, float left_right_fraction, lo_message msg);
	int route_set_pan_stereo_width (int rid, float percent, lo_message msg);
	int route_set_send_gain_dB (int rid, int sid, float val, lo_message msg);
	int route_set_send_fader (int rid, int sid, float val, lo_message msg);
	int route_set_send_enable (int rid, int sid, float val, lo_message msg);
	int route_plugin_parameter (int rid, int piid,int par, float val, lo_message msg);
	int route_plugin_parameter_print (int rid, int piid,int par, lo_message msg);
	int route_plugin_activate (int rid, int piid, lo_message msg);
	int route_plugin_deactivate (int rid, int piid, lo_message msg);
	int route_plugin_list(int ssid, lo_message msg);
	int route_plugin_descriptor(int ssid, int piid, lo_message msg);
	int route_plugin_reset(int ssid, int piid, lo_message msg);

	//banking functions
	int set_bank (uint32_t bank_start, lo_message msg);
	int _set_bank (uint32_t bank_start, lo_address addr);
	int bank_up (lo_message msg);
	int bank_delta (float delta, lo_message msg);
	int use_group (float value, lo_message msg);
	int bank_down (lo_message msg);
	// surface set up
	int surface_parse (const char *path, const char* types, lo_arg **argv, int argc, lo_message msg);
	int set_surface (uint32_t b_size, uint32_t strips, uint32_t fb, uint32_t gmode, uint32_t se_size, uint32_t pi_size, lo_message msg);
	int set_surface_bank_size (uint32_t bs, lo_message msg);
	int set_surface_strip_types (uint32_t st, lo_message msg);
	int set_surface_feedback (uint32_t fb, lo_message msg);
	int set_surface_gainmode (uint32_t gm, lo_message msg);
	int set_surface_port (uint32_t po, lo_message msg);
	int refresh_surface (lo_message msg);
	int custom_clear (lo_message msg);
	int custom_mode (float state, lo_message msg);
	int _custom_mode (uint32_t state, lo_address addr);
	int name_session (char *n, lo_message msg);
	// select
	int sel_send_pagesize (uint32_t size, lo_message msg);
	int sel_send_page (int page, lo_message msg);
	int sel_plug_pagesize (uint32_t size, lo_message msg);
	int sel_plug_page (int page, lo_message msg);
	int sel_plugin (int delta, lo_message msg);
	int _sel_plugin (int id, lo_address addr);
	int sel_plugin_activate (float state, lo_message msg);
	int select_plugin_parameter (const char *path, const char* types, lo_arg **argv, int argc, lo_message msg);
	void processor_changed (std::string remote_url);

	int scrub (float delta, lo_message msg);
	int jog (float delta, lo_message msg);
	int jog_mode (float mode, lo_message msg);
	int set_marker (const char* types, lo_arg **argv, int argc, lo_message msg);
	int click_level (float position);
	int master_set_gain (float dB);
	int master_set_fader (float position);
	int master_delta_gain (float delta);
	int master_set_trim (float dB);
	int master_set_pan_stereo_position (float position, lo_message msg);
	int master_set_mute (uint32_t state);
	int master_select (lo_message msg);
	int monitor_set_gain (float dB);
	int monitor_set_fader (float position);
	int monitor_delta_gain (float delta);
	int monitor_set_mute (uint32_t state);
	int monitor_set_dim (uint32_t state);
	int monitor_set_mono (uint32_t state);
	int sel_group (char *g, lo_message msg);
	int sel_rename (char *n, lo_message msg);
	int sel_comment (char *c, lo_message msg);
	int sel_recenable (uint32_t state, lo_message msg);
	int sel_recsafe (uint32_t state, lo_message msg);
	int sel_mute (uint32_t state, lo_message msg);
	int sel_solo (uint32_t state, lo_message msg);
	int sel_solo_iso (uint32_t state, lo_message msg);
	int sel_solo_safe (uint32_t state, lo_message msg);
	int sel_monitor_input (uint32_t state, lo_message msg);
	int sel_monitor_disk (uint32_t state, lo_message msg);
	int sel_phase (uint32_t state, lo_message msg);
	int sel_gain (float state, lo_message msg);
	int sel_fader (float state, lo_message msg);
	int sel_dB_delta (float delta, lo_message msg);
	int sel_trim (float val, lo_message msg);
	int sel_hide (uint32_t state, lo_message msg);
	int sel_previous (lo_message msg);
	int sel_next (lo_message msg);
	int sel_delta (int delta, lo_message msg);
	boost::shared_ptr<ARDOUR::Send> get_send (boost::shared_ptr<ARDOUR::Stripable> st, lo_address addr);
	int sel_pan_position (float val, lo_message msg);
	int sel_pan_width (float val, lo_message msg);
	int sel_sendgain (int id, float dB, lo_message msg);
	int sel_sendfader (int id, float pos, lo_message msg);
	int sel_sendenable (int id, float pos, lo_message msg);
	int sel_master_send_enable (int state, lo_message msg);
	int sel_expand (uint32_t state, lo_message msg);
	int sel_pan_elevation (float val, lo_message msg);
	int sel_pan_frontback (float val, lo_message msg);
	int sel_pan_lfe (float val, lo_message msg);
	int sel_comp_enable (float val, lo_message msg);
	int sel_comp_threshold (float val, lo_message msg);
	int sel_comp_speed (float val, lo_message msg);
	int sel_comp_mode (float val, lo_message msg);
	int sel_comp_makeup (float val, lo_message msg);
	int sel_eq_enable (float val, lo_message msg);
	int sel_eq_hpf_freq (float val, lo_message msg);
	int sel_eq_hpf_enable (float val, lo_message msg);
	int sel_eq_hpf_slope (float val, lo_message msg);
	int sel_eq_lpf_freq (float val, lo_message msg);
	int sel_eq_lpf_enable (float val, lo_message msg);
	int sel_eq_lpf_slope (float val, lo_message msg);
	int sel_eq_gain (int id, float val, lo_message msg);
	int sel_eq_freq (int id, float val, lo_message msg);
	int sel_eq_q (int id, float val, lo_message msg);
	int sel_eq_shape (int id, float val, lo_message msg);
	int set_temp_mode (lo_address addr);
	int parse_sel_group (const char *path, const char* types, lo_arg **argv, int argc, lo_message msg);
	int parse_sel_vca (const char *path, const char* types, lo_arg **argv, int argc, lo_message msg);
	boost::shared_ptr<ARDOUR::VCA> get_vca_by_name (std::string vname);

	void listen_to_route (boost::shared_ptr<ARDOUR::Stripable>, lo_address);

	void route_name_changed (const PBD::PropertyChange&, boost::weak_ptr<ARDOUR::Route> r, lo_address addr);
	void recalcbanks ();
	void _recalcbanks ();
	void notify_routes_added (ARDOUR::RouteList &);
	void notify_vca_added (ARDOUR::VCAList &);

	int cancel_all_solos ();
	bool periodic (void);
	sigc::connection periodic_connection;
	PBD::ScopedConnectionList session_connections;

	void debugmsg (const char *prefix, const char *path, const char* types, lo_arg **argv, int argc);

	static OSC* _instance;

	mutable void *gui;
	void build_gui ();
};

} // namespace

#endif // ardour_osc_h