Real Time Open Sound Control librtosc
include
rtosc
port-sugar.h
1
/*
2
* Copyright (c) 2016 Mark McCurry
3
*
4
* Permission is hereby granted, free of charge, to any person obtaining a
5
* copy of this software and associated documentation files (the "Software"),
6
* to deal in the Software without restriction, including without limitation
7
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
8
* and/or sell copies of the Software, and to permit persons to whom the
9
* Software is furnished to do so, subject to the following conditions:
10
*
11
* The above copyright notice and this permission notice (including the next
12
* paragraph) shall be included in all copies or substantial portions of the
13
* Software.
14
*
15
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22
* DEALINGS IN THE SOFTWARE.
23
*/
24
25
#include <assert.h>
26
#include <type_traits>
27
#include <cstring>
28
29
#ifndef RTOSC_PORT_SUGAR
30
#define RTOSC_PORT_SUGAR
31
32
//Hack to workaround old incomplete decltype implementations
33
#ifdef __GNUC__
34
#ifndef __clang__
35
#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ <= 7)
36
template
<
typename
T>
37
struct
rtosc_hack_decltype_t
38
{
39
typedef
T type;
40
};
41
42
#define decltype(expr) rtosc_hack_decltype_t<decltype(expr)>::type
43
#endif
44
#endif
45
#endif
46
47
//General macro utilities
48
#define STRINGIFY2(a) #a
49
#define STRINGIFY(a) STRINGIFY2(a)
50
51
//Helper for documenting varargs
52
#define IMPL(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,N, ...) N
53
#define LAST_IMP(...) IMPL(__VA_ARGS__,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,0,0,0)
54
#define DOC_IMP12(a,b,c,d,e,f,g,h,i,j,k,l) a b c d e f g h i j k rDoc(l)
55
#define DOC_IMP11(a,b,c,d,e,f,g,h,i,j,k) a b c d e f g h i j rDoc(k)
56
#define DOC_IMP10(a,b,c,d,e,f,g,h,i,j) a b c d e f g h i rDoc(j)
57
#define DOC_IMP9(a,b,c,d,e,f,g,h,i) a b c d e f g h rDoc(i)
58
#define DOC_IMP8(a,b,c,d,e,f,g,h) a b c d e f g rDoc(h)
59
#define DOC_IMP7(a,b,c,d,e,f,g) a b c d e f rDoc(g)
60
#define DOC_IMP6(a,b,c,d,e,f) a b c d e rDoc(f)
61
#define DOC_IMP5(a,b,c,d,e) a b c d rDoc(e)
62
#define DOC_IMP4(a,b,c,d) a b c rDoc(d)
63
#define DOC_IMP3(a,b,c) a b rDoc(c)
64
#define DOC_IMP2(a,b) a rDoc(b)
65
#define DOC_IMP1(a) rDoc(a)
66
#define DOC_IMP0() YOU_MUST_DOCUMENT_YOUR_PORTS
67
#define DOC_IMP(count, ...) DOC_IMP ##count(__VA_ARGS__)
68
#define DOC_I(count, ...) DOC_IMP(count,__VA_ARGS__)
69
#define DOC(...) DOC_I(LAST_IMP(__VA_ARGS__), __VA_ARGS__)
70
71
72
#define rINC(x) rINC_ ## x
73
#define rINC_0 1
74
#define rINC_1 2
75
#define rINC_2 3
76
#define rINC_3 4
77
#define rINC_4 5
78
#define rINC_5 6
79
#define rINC_6 7
80
#define rINC_7 8
81
#define rINC_8 9
82
#define rINC_9 10
83
#define rINC_10 11
84
#define rINC_11 12
85
#define rINC_12 13
86
#define rINC_13 14
87
#define rINC_14 15
88
#define rINC_15 16
89
90
//Helper for applying macro on varargs
91
//arguments: counting offset, macro, macro args
92
#define MAC_EACH_0(o,m,d,x, ...) INSUFFICIENT_ARGUMENTS_PROVIDED_TO_MAC_EACH
93
#define MAC_EACH_1(o,m,d,x, ...) m(o,d,x)
94
#define MAC_EACH_2(o,m,d,x, ...) m(o,d,x) MAC_EACH_1(rINC(o),m,d, __VA_ARGS__)
95
#define MAC_EACH_3(o,m,d,x, ...) m(o,d,x) MAC_EACH_2(rINC(o),m,d, __VA_ARGS__)
96
#define MAC_EACH_4(o,m,d,x, ...) m(o,d,x) MAC_EACH_3(rINC(o),m,d, __VA_ARGS__)
97
#define MAC_EACH_5(o,m,d,x, ...) m(o,d,x) MAC_EACH_4(rINC(o),m,d, __VA_ARGS__)
98
#define MAC_EACH_6(o,m,d,x, ...) m(o,d,x) MAC_EACH_5(rINC(o),m,d, __VA_ARGS__)
99
#define MAC_EACH_7(o,m,d,x, ...) m(o,d,x) MAC_EACH_6(rINC(o),m,d, __VA_ARGS__)
100
#define MAC_EACH_8(o,m,d,x, ...) m(o,d,x) MAC_EACH_7(rINC(o),m,d, __VA_ARGS__)
101
#define MAC_EACH_9(o,m,d,x, ...) m(o,d,x) MAC_EACH_8(rINC(o),m,d, __VA_ARGS__)
102
#define MAC_EACH_10(o,m,d,x, ...) m(o,d,x) MAC_EACH_9(rINC(o),m,d, __VA_ARGS__)
103
#define MAC_EACH_11(o,m,d,x, ...) m(o,d,x) MAC_EACH_10(rINC(o),m,d, __VA_ARGS__)
104
#define MAC_EACH_12(o,m,d,x, ...) m(o,d,x) MAC_EACH_11(rINC(o),m,d, __VA_ARGS__)
105
#define MAC_EACH_13(o,m,d,x, ...) m(o,d,x) MAC_EACH_12(rINC(o),m,d, __VA_ARGS__)
106
#define MAC_EACH_14(o,m,d,x, ...) m(o,d,x) MAC_EACH_13(rINC(o),m,d, __VA_ARGS__)
107
#define MAC_EACH_15(o,m,d,x, ...) m(o,d,x) MAC_EACH_14(rINC(o),m,d, __VA_ARGS__)
108
#define MAC_EACH_16(o,m,d,x, ...) m(o,d,x) MAC_EACH_15(rINC(o),m,d, __VA_ARGS__)
109
110
#define MAC_EACH_IMP(off, mac, data, count, ...) \
111
MAC_EACH_ ##count(off, mac, data, __VA_ARGS__)
112
#define MAC_EACH_I(off, mac, data, count, ...) \
113
MAC_EACH_IMP(off, mac, data, count, __VA_ARGS__)
114
#define MAC_EACH_OFF(off, mac, data, ...) \
115
MAC_EACH_I(off, mac, data, LAST_IMP(__VA_ARGS__), __VA_ARGS__)
116
#define MAC_EACH(mac, data, ...) MAC_EACH_OFF(0, mac, data, __VA_ARGS__)
117
118
// 1 2 3 4 5 6 7 8 910111213141516
119
#define OPTIONS_IMP16(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) \
120
rOpt(0,a) rOpt(1,b) rOpt(2,c) rOpt(3,d) rOpt(4,e) rOpt(5,f) rOpt(6,g) \
121
rOpt(7,h) rOpt(8,i) rOpt(9,j) rOpt(10,k)rOpt(11,l)rOpt(12,m)rOpt(13,n)\
122
rOpt(14,o)rOpt(15,p)
123
#define OPTIONS_IMP15(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o) \
124
rOpt(0,a) rOpt(1,b) rOpt(2,c) rOpt(3,d) rOpt(4,e) rOpt(5,f) rOpt(6,g) \
125
rOpt(7,h) rOpt(8,i) rOpt(9,j) rOpt(10,k)rOpt(11,l)rOpt(12,m)rOpt(13,n)\
126
rOpt(14,o)
127
#define OPTIONS_IMP14(a,b,c,d,e,f,g,h,i,j,k,l,m,n) \
128
rOpt(0,a) rOpt(1,b) rOpt(2,c) rOpt(3,d) rOpt(4,e) rOpt(5,f) rOpt(6,g) \
129
rOpt(7,h) rOpt(8,i) rOpt(9,j) rOpt(10,k)rOpt(11,l)rOpt(12,m)rOpt(13,n)
130
#define OPTIONS_IMP13(a,b,c,d,e,f,g,h,i,j,k,l,m) \
131
rOpt(0,a) rOpt(1,b) rOpt(2,c) rOpt(3,d) rOpt(4,e) rOpt(5,f) rOpt(6,g) \
132
rOpt(7,h) rOpt(8,i) rOpt(9,j) rOpt(10,k)rOpt(11,l)rOpt(12,m)
133
#define OPTIONS_IMP12(a,b,c,d,e,f,g,h,i,j,k,l) \
134
rOpt(0,a) rOpt(1,b) rOpt(2,c) rOpt(3,d) rOpt(4,e) rOpt(5,f) rOpt(6,g) \
135
rOpt(7,h) rOpt(8,i) rOpt(9,j) rOpt(10,k)rOpt(11,l)
136
#define OPTIONS_IMP11(a,b,c,d,e,f,g,h,i,j,k) \
137
rOpt(0,a) rOpt(1,b) rOpt(2,c) rOpt(3,d) rOpt(4,e) rOpt(5,f) rOpt(6,g) \
138
rOpt(7,h) rOpt(8,i) rOpt(9,j) rOpt(10,k)
139
#define OPTIONS_IMP10(a,b,c,d,e,f,g,h,i,j) \
140
rOpt(0,a) rOpt(1,b) rOpt(2,c) rOpt(3,d) rOpt(4,e) rOpt(5,f) rOpt(6,g) \
141
rOpt(7,h) rOpt(8,i) rOpt(9,j)
142
#define OPTIONS_IMP9(a,b,c,d,e,f,g,h,i) \
143
rOpt(0,a) rOpt(1,b) rOpt(2,c) rOpt(3,d) rOpt(4,e) rOpt(5,f) rOpt(6,g) \
144
rOpt(7,h) rOpt(8,i)
145
#define OPTIONS_IMP8(a,b,c,d,e,f,g,h) \
146
rOpt(0,a) rOpt(1,b) rOpt(2,c) rOpt(3,d) rOpt(4,e) rOpt(5,f) rOpt(6,g) \
147
rOpt(7,h)
148
#define OPTIONS_IMP7(a,b,c,d,e,f,g) \
149
rOpt(0,a) rOpt(1,b) rOpt(2,c) rOpt(3,d) rOpt(4,e) rOpt(5,f) rOpt(6,g)
150
#define OPTIONS_IMP6(a,b,c,d,e,f) \
151
rOpt(0,a) rOpt(1,b) rOpt(2,c) rOpt(3,d) rOpt(4,e) rOpt(5,f)
152
#define OPTIONS_IMP5(a,b,c,d,e) \
153
rOpt(0,a) rOpt(1,b) rOpt(2,c) rOpt(3,d) rOpt(4,e)
154
#define OPTIONS_IMP4(a,b,c,d) \
155
rOpt(0,a) rOpt(1,b) rOpt(2,c) rOpt(3,d)
156
#define OPTIONS_IMP3(a,b,c) \
157
rOpt(0,a) rOpt(1,b) rOpt(2,c)
158
#define OPTIONS_IMP2(a,b) \
159
rOpt(0,a) rOpt(1,b)
160
#define OPTIONS_IMP1(a) \
161
rOpt(0,a)
162
#define OPTIONS_IMP0() YOU_MUST_PROVIDE_OPTIONS
163
#define OPTIONS_IMP(count, ...) OPTIONS_IMP ##count(__VA_ARGS__)
164
#define OPTIONS_I(count, ...) OPTIONS_IMP(count, __VA_ARGS__)
165
#define OPTIONS(...) OPTIONS_I(LAST_IMP(__VA_ARGS__), __VA_ARGS__)
166
167
//Additional Change Callback (after parameters have been changed)
168
//This can be used to queue up interpolation or parameter regen
169
#define rChangeCb
170
171
//Normal parameters
172
#define rParam(name, ...) \
173
{STRINGIFY(name) "::c", rProp(parameter) rMap(min, 0) rMap(max, 127) DOC(__VA_ARGS__), NULL, rParamCb(name)}
174
#define rParamF(name, ...) \
175
{STRINGIFY(name) "::f", rProp(parameter) DOC(__VA_ARGS__), NULL, rParamFCb(name)}
176
#define rParamI(name, ...) \
177
{STRINGIFY(name) "::i", rProp(parameter) DOC(__VA_ARGS__), NULL, rParamICb(name)}
178
#define rToggle(name, ...) \
179
{STRINGIFY(name) "::T:F",rProp(parameter) DOC(__VA_ARGS__), NULL, rToggleCb(name)}
180
#define rOption(name, ...) \
181
{STRINGIFY(name) "::i:c:S",rProp(parameter) rProp(enumerated) DOC(__VA_ARGS__), NULL, rOptionCb(name)}
182
183
//Array operators
184
#define rArrayF(name, length, ...) \
185
{STRINGIFY(name) "#" STRINGIFY(length) "::f", rProp(parameter) DOC(__VA_ARGS__), NULL, rArrayFCb(name)}
186
#define rArrayT(name, length, ...) \
187
{STRINGIFY(name) "#" STRINGIFY(length) "::T:F", rProp(parameter) DOC(__VA_ARGS__), NULL, rArrayTCb(name)}
188
#define rArrayI(name, length, ...) \
189
{STRINGIFY(name) "#" STRINGIFY(length) "::i", rProp(parameter) DOC(__VA_ARGS__), NULL, rArrayICb(name)}
190
#define rArrayOption(name, length, ...) \
191
{STRINGIFY(name) "#" STRINGIFY(length) "::i:c:S", rProp(parameter) DOC(__VA_ARGS__), NULL, rArrayOptionCb(name)}
192
#define rArray rArrayI
193
194
//Method callback Actions
195
#define rAction(name, ...) \
196
{STRINGIFY(name) ":", DOC(__VA_ARGS__), NULL, rActionCb(name)}
197
#define rActioni(name, ...) \
198
{STRINGIFY(name) ":i", DOC(__VA_ARGS__), NULL, rActioniCb(name)}
199
200
201
//Alias operators
202
#define rParams(name, length, ...) \
203
rArray(name, length, __VA_ARGS__), \
204
{STRINGIFY(name) ":", rProp(alias) rDoc("get all data from aliased array"), NULL, rParamsCb(name, length)}
205
206
207
template
<
class
T> constexpr T spice(T*t) {
return
*t;}
208
209
//Recursion [two ports in one for pointer manipulation]
210
#define rRecur(name, ...) \
211
{STRINGIFY(name) "/", DOC(__VA_ARGS__), &decltype(rObject::name)::ports, rRecurCb(name)}, \
212
{STRINGIFY(name) ":", rProp(internal) rDoc("get obj pointer"), NULL, rRecurPtrCb(name)}
213
214
#define rRecurp(name, ...) \
215
{STRINGIFY(name) "/", DOC(__VA_ARGS__), \
216
&decltype(spice(rObject::name))::ports, \
217
rRecurpCb(name)}
218
219
#define rRecurs(name, length, ...) \
220
{STRINGIFY(name) "#" STRINGIFY(length)"/", DOC(__VA_ARGS__), \
221
&decltype(spice(&rObject::name[0]))::ports, \
222
rRecursCb(name, length)}
223
224
//Technically this is a pointer pointer method...
225
#define rRecursp(name, length, ...) \
226
{STRINGIFY(name)"#" STRINGIFY(length) "/", DOC(__VA_ARGS__), \
227
&decltype(spice(rObject::name[0]))::ports, \
228
rRecurspCb(name)}
229
230
//{STRINGIFY(name) ":", rProp(internal), NULL, rRecurPtrCb(name)}
231
232
//let this recurring parameter depend on another port
233
//the path of the other port must be at the current level or one level above
234
#define rEnabledBy(portname) rMap(enabled by, portname)
235
#define rEnabledByCondition(cond_name) rEnabledBy(cond_name)
236
#define rEnabledCondition(cond_name, condition) \
237
{STRINGIFY(cond_name) ":", rProp(internal), NULL, rEnabledIfCb(condition)}
238
#define rEnabledIfCb(condition) rBOIL_BEGIN \
239
assert(!rtosc_narguments(msg)); \
240
data.reply(loc, (condition)?"T":"F"); \
241
rBOIL_END \
242
243
#define rSelf(type, ...) \
244
{"self:", rProp(internal) rMap(class, type) __VA_ARGS__ rDoc("port metadata"), 0, \
245
[](const char *, rtosc::RtData &d){ \
246
d.reply(d.loc, "b", sizeof(d.obj), &d.obj);}}\
247
248
//Misc
249
#define rDummy(name, ...) {STRINGIFY(name), rProp(dummy), NULL, [](msg_t, rtosc::RtData &){}}
250
#define rString(name, len, ...) \
251
{STRINGIFY(name) "::s", rMap(length, len) rProp(parameter) DOC(__VA_ARGS__), NULL, rStringCb(name,len)}
252
253
//General property operators
254
#define rMap(name, value) ":" STRINGIFY(name) "\0=" STRINGIFY(value) "\0"
255
#define rProp(name) ":" STRINGIFY(name) "\0"
256
257
//Scaling property
258
//This property describes the variable's input scale, which is in most cases
259
//(not always) equal to the perception. Thus, if 0 is in the input scale, and
260
//has no special meaning, rLinear shall be used.
261
#define rLinear(min_, max_) rMap(min, min_) rMap(max, max_) rMap(scale, linear)
262
#define rLog(min_, max_) rMap(min, min_) rMap(max, max_) rMap(scale, logarithmic)
263
264
//Special values
265
#define rSpecial(doc) ":special\0" STRINGIFY(doc) "\0"
266
#define rCentered ":centered\0"
267
268
//Default values
269
#define rDefault(default_value_) rMap(default, default_value_)
270
#define rDefaultId(default_value_) ":default\0=\"" STRINGIFY(default_value_) "\"S\0"
271
//#define rDefaultArr(default_value_, idx_) rMap(default[idx_], default_value_)
272
#define rPreset(no, default_value) \
273
":default " STRINGIFY(no) "\0=" STRINGIFY(default_value) "\0"
274
#define _rPreset(no, data, default_value) rPreset(no, default_value)
275
#define rPresetsAt(offs, ...) MAC_EACH_OFF(offs, _rPreset, offs, __VA_ARGS__)
276
#define _rPreset2(offs, data, preset_no) rPreset(preset_no, data)
277
#define rPresetAtMulti(val, ...) MAC_EACH_OFF(0, _rPreset2, val, __VA_ARGS__)
278
#define rPresets(...) rPresetsAt(0, __VA_ARGS__)
279
#define rDefaultDepends(dep_path_) rMap(default depends, dep_path_)
280
#define rDefaultMissing "" // macro to denote yet missing default values
281
#define rNoDefaults ":no defaults\0"
283
284
//Misc properties
285
#define rDoc(doc) ":documentation\0=" doc "\0"
286
#define rOpt(numeric,symbolic) rMap(map numeric, symbolic)
287
#define rOptions(...) OPTIONS(__VA_ARGS__)
288
289
//Zest Metadata
290
#define rShort(name) ":shortname\0=" name "\0"
291
292
293
//Callback Implementations
294
#define rBOIL_BEGIN [](const char *msg, rtosc::RtData &data) { \
295
(void) msg; (void) data; \
296
rObject *obj = (rObject*) data.obj;(void) obj; \
297
const char *args = rtosc_argument_string(msg); (void) args;\
298
const char *loc = data.loc; (void) loc;\
299
auto prop = data.port->meta(); (void) prop;
300
301
#define rBOIL_END }
302
303
#define rLIMIT(var, convert) \
304
if(prop["min"] && var < (decltype(var)) convert(prop["min"])) \
305
var = convert(prop["min"]);\
306
if(prop["max"] && var > (decltype(var)) convert(prop["max"])) \
307
var = convert(prop["max"]);
308
309
#define rTYPE(n) decltype(obj->n)
310
311
//#define rAPPLY(n,t) if(obj->n != var) data.reply("/undo_change", "s" #t #t, data.loc, obj->n, var); obj->n = var;
312
#define rCAPPLY(getcode, t, setcode) if(getcode != var) data.reply("/undo_change", "s" #t #t, data.loc, getcode, var); setcode;
313
#define rAPPLY(n,t) rCAPPLY(obj->n, t, obj->n = var)
314
315
#define rParamCb(name) rBOIL_BEGIN \
316
if(!strcmp("", args)) {\
317
data.reply(loc, "c", obj->name); \
318
} else { \
319
rTYPE(name) var = rtosc_argument(msg, 0).i; \
320
rLIMIT(var, atoi) \
321
rAPPLY(name, c) \
322
data.broadcast(loc, "c", obj->name);\
323
rChangeCb \
324
} rBOIL_END
325
326
#define rParamFCb(name) rBOIL_BEGIN \
327
if(!strcmp("", args)) {\
328
data.reply(loc, "f", obj->name); \
329
} else { \
330
rTYPE(name) var = rtosc_argument(msg, 0).f; \
331
rLIMIT(var, atof) \
332
rAPPLY(name, f) \
333
data.broadcast(loc, "f", obj->name);\
334
rChangeCb \
335
} rBOIL_END
336
337
#define rParamICb(name) rBOIL_BEGIN \
338
if(!strcmp("", args)) {\
339
data.reply(loc, "i", obj->name); \
340
} else { \
341
rTYPE(name) var = rtosc_argument(msg, 0).i; \
342
rLIMIT(var, atoi) \
343
rAPPLY(name, i) \
344
data.broadcast(loc, "i", obj->name);\
345
rChangeCb \
346
} rBOIL_END
347
348
#define rCOptionCb_(getcode, setcode) { \
349
if(!strcmp("", args)) {\
350
data.reply(loc, "i", getcode); \
351
} else if(!strcmp("s", args) || !strcmp("S", args)) { \
352
auto var = \
353
enum_key(prop, rtosc_argument(msg, 0).s); \
354
/* make sure we have no out-of-bound options */
\
355
assert(!prop["min"] || \
356
var >= atoi(prop["min"])); \
357
assert(!prop["max"] || \
358
var <= atoi(prop["max"])); \
359
rCAPPLY(getcode, i, setcode) \
360
data.broadcast(loc, "i", getcode); \
361
rChangeCb \
362
} else {\
363
auto var = \
364
rtosc_argument(msg, 0).i; \
365
rLIMIT(var, atoi) \
366
rCAPPLY(getcode, i, setcode) \
367
data.broadcast(loc, rtosc_argument_string(msg), getcode);\
368
rChangeCb \
369
} \
370
}
371
372
#define rOptionCb_(name) rCOptionCb_(obj->name, obj->name = var)
373
374
#define rOptionCb(name) rBOIL_BEGIN \
375
rOptionCb_(name) \
376
rBOIL_END
377
378
#define rCOptionCb(getcode, setcode) rBOIL_BEGIN \
379
rCOptionCb_(getcode, setcode) \
380
rBOIL_END
381
382
383
#define rToggleCb(name) rBOIL_BEGIN \
384
if(!strcmp("", args)) {\
385
data.reply(loc, obj->name ? "T" : "F"); \
386
} else { \
387
if(obj->name != rtosc_argument(msg, 0).T) { \
388
data.broadcast(loc, args);\
389
obj->name = rtosc_argument(msg, 0).T; \
390
rChangeCb \
391
} \
392
} rBOIL_END
393
394
#define SNIP \
395
while(*msg && *msg!='/') ++msg; \
396
msg = *msg ? msg+1 : msg;
397
398
#define rRecurCb(name) rBOIL_BEGIN \
399
data.obj = &obj->name; \
400
SNIP \
401
decltype(obj->name)::ports.dispatch(msg, data); \
402
rBOIL_END
403
404
#define rRecurPtrCb(name) rBOIL_BEGIN \
405
void *ptr = &obj->name; \
406
data.reply(loc, "b", sizeof(void*), &ptr); \
407
rBOIL_END
408
409
#define rRecurpCb(name) rBOIL_BEGIN \
410
data.obj = obj->name; \
411
if(obj->name == NULL) return; \
412
SNIP \
413
decltype(spice(rObject::name))::ports.dispatch(msg, data); \
414
rBOIL_END
415
416
#define rRecursCb(name, length) rBOILS_BEGIN \
417
data.obj = &obj->name[idx]; \
418
SNIP \
419
decltype(spice(rObject::name))::ports.dispatch(msg, data); \
420
rBOILS_END
421
422
#define rRecurspCb(name) rBOILS_BEGIN \
423
data.obj = obj->name[idx]; \
424
SNIP \
425
decltype(spice(rObject::name[0]))::ports.dispatch(msg, data); \
426
rBOILS_END
427
428
#define rActionCb(name) rBOIL_BEGIN obj->name(); rBOIL_END
429
#define rActioniCb(name) rBOIL_BEGIN \
430
obj->name(rtosc_argument(msg,0).i); rBOIL_END
431
432
//Array ops
433
434
#define rBOILS_BEGIN rBOIL_BEGIN \
435
const char *mm = msg; \
436
while(*mm && !isdigit(*mm)) ++mm; \
437
unsigned idx = atoi(mm);
438
439
#define rBOILS_END rBOIL_END
440
441
442
#define rArrayFCb(name) rBOILS_BEGIN \
443
if(!strcmp("", args)) {\
444
data.reply(loc, "f", obj->name[idx]); \
445
} else { \
446
float var = rtosc_argument(msg, 0).f; \
447
rLIMIT(var, atof) \
448
rAPPLY(name[idx], f) \
449
data.broadcast(loc, "f", obj->name[idx]);\
450
} rBOILS_END
451
452
#define rArrayTCb(name) rBOILS_BEGIN \
453
if(!strcmp("", args)) {\
454
data.reply(loc, obj->name[idx] ? "T" : "F"); \
455
} else { \
456
if(obj->name[idx] != rtosc_argument(msg, 0).T) { \
457
data.broadcast(loc, args);\
458
rChangeCb \
459
} \
460
obj->name[idx] = rtosc_argument(msg, 0).T; \
461
} rBOILS_END
462
463
#define rArrayTCbMember(name, member) rBOILS_BEGIN \
464
if(!strcmp("", args)) {\
465
data.reply(loc, obj->name[idx].member ? "T" : "F"); \
466
} else { \
467
if(obj->name[idx].member != rtosc_argument(msg, 0).T) { \
468
data.broadcast(loc, args);\
469
rChangeCb \
470
} \
471
obj->name[idx].member = rtosc_argument(msg, 0).T; \
472
} rBOILS_END
473
474
475
#define rArrayICb(name) rBOILS_BEGIN \
476
if(!strcmp("", args)) {\
477
data.reply(loc, "i", obj->name[idx]); \
478
} else { \
479
char var = rtosc_argument(msg, 0).i; \
480
rLIMIT(var, atoi) \
481
rAPPLY(name[idx], i) \
482
data.broadcast(loc, "i", obj->name[idx]);\
483
rChangeCb \
484
} rBOILS_END
485
486
487
#define rArrayOptionCb(name) rBOILS_BEGIN \
488
rOptionCb_(name[idx]) \
489
rBOILS_END
490
491
#define rParamsCb(name, length) rBOIL_BEGIN \
492
data.reply(loc, "b", length, obj->name); rBOIL_END
493
494
#define rStringCb(name, length) rBOIL_BEGIN \
495
if(!strcmp("", args)) {\
496
data.reply(loc, "s", obj->name); \
497
} else { \
498
strncpy(obj->name, rtosc_argument(msg, 0).s, length-1); \
499
obj->name[length-1] = '\0'; \
500
data.broadcast(loc, "s", obj->name);\
501
rChangeCb \
502
} rBOIL_END
503
504
505
#endif
Generated on Thu Apr 18 2019 23:18:10 for Real Time Open Sound Control librtosc by
1.8.15