1 /*
2 * Copyright (c) 2015-2016 Hanspeter Portner (dev@open-music-kontrollers.ch)
3 *
4 * This is free software: you can redistribute it and/or modify
5 * it under the terms of the Artistic License 2.0 as published by
6 * The Perl Foundation.
7 *
8 * This source is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * Artistic License 2.0 for more details.
12 *
13 * You should have received a copy of the Artistic License 2.0
14 * along the source as a COPYING file. If not, obtain it from
15 * http://www.perlfoundation.org/artistic_license_2_0.
16 */
17
18 #ifndef LV2_OSC_FORGE_H
19 #define LV2_OSC_FORGE_H
20
21 #include <inttypes.h>
22
23 #include <osc.lv2/osc.h>
24 #include <osc.lv2/util.h>
25 #include <osc.lv2/reader.h>
26
27 #include <lv2/lv2plug.in/ns/ext/atom/forge.h>
28
29 #ifdef __cplusplus
30 extern "C" {
31 #endif
32
33 #define lv2_osc_forge_int(forge, osc_urid, val) \
34 lv2_atom_forge_int((forge), (val))
35
36 #define lv2_osc_forge_float(forge, osc_urid, val) \
37 lv2_atom_forge_float((forge), (val))
38
39 #define lv2_osc_forge_string(forge, osc_urid, val, len) \
40 lv2_atom_forge_string((forge), (val), (len))
41
42 #define lv2_osc_forge_long(forge, osc_urid, val) \
43 lv2_atom_forge_long((forge), (val))
44
45 #define lv2_osc_forge_double(forge, osc_urid, val) \
46 lv2_atom_forge_double((forge), (val))
47
48 #define lv2_osc_forge_true(forge, osc_urid) \
49 lv2_atom_forge_bool((forge), 1)
50
51 #define lv2_osc_forge_false(forge, osc_urid) \
52 lv2_atom_forge_bool((forge), 0)
53
54 #define lv2_osc_forge_nil(forge, osc_urid) \
55 lv2_atom_forge_literal((forge), "", 0, (osc_urid)->OSC_Nil, 0)
56
57 #define lv2_osc_forge_impulse(forge, osc_urid) \
58 lv2_atom_forge_literal((forge), "", 0, (osc_urid)->OSC_Impulse, 0)
59
60 #define lv2_osc_forge_symbol(forge, osc_urid, val) \
61 lv2_atom_forge_urid((forge), (val))
62
63 static inline LV2_Atom_Forge_Ref
lv2_osc_forge_chunk(LV2_Atom_Forge * forge,LV2_URID type,const uint8_t * buf,uint32_t size)64 lv2_osc_forge_chunk(LV2_Atom_Forge *forge, LV2_URID type,
65 const uint8_t *buf, uint32_t size)
66 {
67 LV2_Atom_Forge_Ref ref;
68
69 if( (ref = lv2_atom_forge_atom(forge, size, type))
70 && (ref = lv2_atom_forge_raw(forge, buf, size)) )
71 {
72 lv2_atom_forge_pad(forge, size);
73 return ref;
74 }
75
76 return 0;
77 }
78
79 static inline LV2_Atom_Forge_Ref
lv2_osc_forge_midi(LV2_Atom_Forge * forge,LV2_OSC_URID * osc_urid,const uint8_t * buf,uint32_t size)80 lv2_osc_forge_midi(LV2_Atom_Forge *forge, LV2_OSC_URID *osc_urid,
81 const uint8_t *buf, uint32_t size)
82 {
83 assert(size <= 3);
84 return lv2_osc_forge_chunk(forge, osc_urid->MIDI_MidiEvent, buf, size);
85 }
86
87 static inline LV2_Atom_Forge_Ref
lv2_osc_forge_blob(LV2_Atom_Forge * forge,LV2_OSC_URID * osc_urid,const uint8_t * buf,uint32_t size)88 lv2_osc_forge_blob(LV2_Atom_Forge* forge, LV2_OSC_URID *osc_urid,
89 const uint8_t *buf, uint32_t size)
90 {
91 return lv2_osc_forge_chunk(forge, osc_urid->ATOM_Chunk, buf, size);
92 }
93
94 static inline LV2_Atom_Forge_Ref
lv2_osc_forge_char(LV2_Atom_Forge * forge,LV2_OSC_URID * osc_urid,char val)95 lv2_osc_forge_char(LV2_Atom_Forge* forge, LV2_OSC_URID *osc_urid,
96 char val)
97 {
98 return lv2_atom_forge_literal(forge, &val, 1, osc_urid->OSC_Char, 0);
99 }
100
101 static inline LV2_Atom_Forge_Ref
lv2_osc_forge_rgba(LV2_Atom_Forge * forge,LV2_OSC_URID * osc_urid,uint8_t r,uint8_t g,uint8_t b,uint8_t a)102 lv2_osc_forge_rgba(LV2_Atom_Forge* forge, LV2_OSC_URID *osc_urid,
103 uint8_t r, uint8_t g, uint8_t b, uint8_t a)
104 {
105 char val [9];
106 sprintf(val, "%02"PRIx8"%02"PRIx8"%02"PRIx8"%02"PRIx8, r, g, b, a);
107 return lv2_atom_forge_literal(forge, val, 8, osc_urid->OSC_RGBA, 0);
108 }
109
110 static inline LV2_Atom_Forge_Ref
lv2_osc_forge_timetag(LV2_Atom_Forge * forge,LV2_OSC_URID * osc_urid,const LV2_OSC_Timetag * timetag)111 lv2_osc_forge_timetag(LV2_Atom_Forge *forge, LV2_OSC_URID *osc_urid,
112 const LV2_OSC_Timetag *timetag)
113 {
114 LV2_Atom_Forge_Frame frame;
115 LV2_Atom_Forge_Ref ref;
116
117 if( (ref = lv2_atom_forge_object(forge, &frame, 0, osc_urid->OSC_Timetag))
118 && (ref = lv2_atom_forge_key(forge, osc_urid->OSC_timetagIntegral))
119 && (ref = lv2_atom_forge_long(forge, timetag->integral))
120 && (ref = lv2_atom_forge_key(forge, osc_urid->OSC_timetagFraction))
121 && (ref = lv2_atom_forge_long(forge, timetag->fraction)) )
122 {
123 lv2_atom_forge_pop(forge, &frame);
124 return ref;
125 }
126
127 return 0;
128 }
129
130 static inline LV2_Atom_Forge_Ref
lv2_osc_forge_bundle_head(LV2_Atom_Forge * forge,LV2_OSC_URID * osc_urid,LV2_Atom_Forge_Frame frame[2],const LV2_OSC_Timetag * timetag)131 lv2_osc_forge_bundle_head(LV2_Atom_Forge* forge, LV2_OSC_URID *osc_urid,
132 LV2_Atom_Forge_Frame frame [2], const LV2_OSC_Timetag *timetag)
133 {
134 LV2_Atom_Forge_Ref ref;
135
136 if( (ref = lv2_atom_forge_object(forge, &frame[0], 0, osc_urid->OSC_Bundle))
137 && (ref = lv2_atom_forge_key(forge, osc_urid->OSC_bundleTimetag))
138 && (ref = lv2_osc_forge_timetag(forge, osc_urid, timetag))
139 && (ref = lv2_atom_forge_key(forge, osc_urid->OSC_bundleItems))
140 && (ref = lv2_atom_forge_tuple(forge, &frame[1])) )
141 {
142 return ref;
143 }
144
145 return 0;
146 }
147
148 /**
149 TODO
150 */
151 static inline LV2_Atom_Forge_Ref
lv2_osc_forge_message_head(LV2_Atom_Forge * forge,LV2_OSC_URID * osc_urid,LV2_Atom_Forge_Frame frame[2],const char * path)152 lv2_osc_forge_message_head(LV2_Atom_Forge *forge, LV2_OSC_URID *osc_urid,
153 LV2_Atom_Forge_Frame frame [2], const char *path)
154 {
155 assert(path);
156
157 LV2_Atom_Forge_Ref ref;
158 if( (ref = lv2_atom_forge_object(forge, &frame[0], 0, osc_urid->OSC_Message))
159 && (ref = lv2_atom_forge_key(forge, osc_urid->OSC_messagePath))
160 && (ref = lv2_atom_forge_string(forge, path, strlen(path)))
161 && (ref = lv2_atom_forge_key(forge, osc_urid->OSC_messageArguments))
162 && (ref = lv2_atom_forge_tuple(forge, &frame[1])) )
163 {
164 return ref;
165 }
166
167 return 0;
168 }
169
170 /**
171 TODO
172 */
173 static inline void
lv2_osc_forge_pop(LV2_Atom_Forge * forge,LV2_Atom_Forge_Frame frame[2])174 lv2_osc_forge_pop(LV2_Atom_Forge *forge, LV2_Atom_Forge_Frame frame [2])
175 {
176 lv2_atom_forge_pop(forge, &frame[1]); // a LV2_Atom_Tuple
177 lv2_atom_forge_pop(forge, &frame[0]); // a LV2_Atom_Object
178 }
179
180 static inline LV2_Atom_Forge_Ref
lv2_osc_forge_message_varlist(LV2_Atom_Forge * forge,LV2_OSC_URID * osc_urid,const char * path,const char * fmt,va_list args)181 lv2_osc_forge_message_varlist(LV2_Atom_Forge *forge, LV2_OSC_URID *osc_urid,
182 const char *path, const char *fmt, va_list args)
183 {
184 LV2_Atom_Forge_Frame frame [2];
185 LV2_Atom_Forge_Ref ref;
186
187 if(!lv2_osc_check_path(path) || !lv2_osc_check_fmt(fmt, 0))
188 return 0;
189 if(!(ref = lv2_osc_forge_message_head(forge, osc_urid, frame, path)))
190 return 0;
191
192 for(const char *type = fmt; *type; type++)
193 {
194 switch( (LV2_OSC_Type)*type)
195 {
196 case LV2_OSC_INT32:
197 {
198 if(!(ref = lv2_osc_forge_int(forge, osc_urid, va_arg(args, int32_t))))
199 return 0;
200 break;
201 }
202 case LV2_OSC_FLOAT:
203 {
204 if(!(ref = lv2_osc_forge_float(forge, osc_urid, (float)va_arg(args, double))))
205 return 0;
206 break;
207 }
208 case LV2_OSC_STRING:
209 {
210 const char *s = va_arg(args, const char *);
211 if(!s || !(ref = lv2_osc_forge_string(forge, osc_urid, s, strlen(s))))
212 return 0;
213 break;
214 }
215 case LV2_OSC_BLOB:
216 {
217 const int32_t size = va_arg(args, int32_t);
218 const uint8_t *b = va_arg(args, const uint8_t *);
219 if(!b || !(ref = lv2_osc_forge_blob(forge, osc_urid, b, size)))
220 return 0;
221 break;
222 }
223
224 case LV2_OSC_INT64:
225 {
226 if(!(ref = lv2_osc_forge_long(forge, osc_urid, va_arg(args, int64_t))))
227 return 0;
228 break;
229 }
230 case LV2_OSC_DOUBLE:
231 {
232 if(!(ref = lv2_osc_forge_double(forge, osc_urid, va_arg(args, double))))
233 return 0;
234 break;
235 }
236 case LV2_OSC_TIMETAG:
237 {
238 const LV2_OSC_Timetag timetag = {
239 .integral = va_arg(args, uint32_t),
240 .fraction = va_arg(args, uint32_t)
241 };
242 if(!(ref = lv2_osc_forge_timetag(forge, osc_urid, &timetag)))
243 return 0;
244 break;
245 }
246
247 case LV2_OSC_TRUE:
248 {
249 if(!(ref = lv2_osc_forge_true(forge, osc_urid)))
250 return 0;
251 break;
252 }
253 case LV2_OSC_FALSE:
254 {
255 if(!(ref = lv2_osc_forge_false(forge, osc_urid)))
256 return 0;
257 break;
258 }
259 case LV2_OSC_NIL:
260 {
261 if(!(ref = lv2_osc_forge_nil(forge, osc_urid)))
262 return 0;
263 break;
264 }
265 case LV2_OSC_IMPULSE:
266 {
267 if(!(ref = lv2_osc_forge_impulse(forge, osc_urid)))
268 return 0;
269 break;
270 }
271
272 case LV2_OSC_SYMBOL:
273 {
274 if(!(ref = lv2_osc_forge_symbol(forge, osc_urid, va_arg(args, uint32_t))))
275 return 0;
276 break;
277 }
278 case LV2_OSC_MIDI:
279 {
280 const int32_t size = va_arg(args, int32_t);
281 const uint8_t *m = va_arg(args, const uint8_t *);
282 if(!m || !(ref = lv2_osc_forge_midi(forge, osc_urid, m, size)))
283 return 0;
284 break;
285 }
286 case LV2_OSC_CHAR:
287 {
288 if(!(ref = lv2_osc_forge_char(forge, osc_urid, (char)va_arg(args, int))))
289 return 0;
290 break;
291 }
292 case LV2_OSC_RGBA:
293 {
294 if(!(ref = lv2_osc_forge_rgba(forge, osc_urid,
295 (uint8_t)va_arg(args, unsigned),
296 (uint8_t)va_arg(args, unsigned),
297 (uint8_t)va_arg(args, unsigned),
298 (uint8_t)va_arg(args, unsigned))))
299 return 0;
300 break;
301 }
302 }
303 }
304
305 lv2_osc_forge_pop(forge, frame);
306
307 return ref;
308 }
309
310 static inline LV2_Atom_Forge_Ref
lv2_osc_forge_message_vararg(LV2_Atom_Forge * forge,LV2_OSC_URID * osc_urid,const char * path,const char * fmt,...)311 lv2_osc_forge_message_vararg(LV2_Atom_Forge *forge, LV2_OSC_URID *osc_urid,
312 const char *path, const char *fmt, ...)
313 {
314 LV2_Atom_Forge_Ref ref;
315 va_list args;
316
317 va_start(args, fmt);
318
319 ref = lv2_osc_forge_message_varlist(forge, osc_urid, path, fmt, args);
320
321 va_end(args);
322
323 return ref;
324 }
325
326 static inline LV2_Atom_Forge_Ref
lv2_osc_forge_packet(LV2_Atom_Forge * forge,LV2_OSC_URID * osc_urid,LV2_URID_Map * map,const uint8_t * buf,size_t size)327 lv2_osc_forge_packet(LV2_Atom_Forge *forge, LV2_OSC_URID *osc_urid,
328 LV2_URID_Map *map, const uint8_t *buf, size_t size)
329 {
330 LV2_OSC_Reader reader;
331 LV2_Atom_Forge_Frame frame [2];
332 LV2_Atom_Forge_Ref ref;
333
334 lv2_osc_reader_initialize(&reader, buf, size);
335
336 if(lv2_osc_reader_is_bundle(&reader))
337 {
338 LV2_OSC_Item *itm = OSC_READER_BUNDLE_BEGIN(&reader, size);
339
340 if(itm && (ref = lv2_osc_forge_bundle_head(forge, osc_urid, frame,
341 LV2_OSC_TIMETAG_CREATE(itm->timetag))))
342 {
343 OSC_READER_BUNDLE_ITERATE(&reader, itm)
344 {
345 if(!(ref = lv2_osc_forge_packet(forge, osc_urid, map, itm->body, itm->size)))
346 return 0;
347 }
348
349 lv2_osc_forge_pop(forge, frame);
350
351 return ref;
352 }
353 }
354 else if(lv2_osc_reader_is_message(&reader))
355 {
356 LV2_OSC_Arg *arg = OSC_READER_MESSAGE_BEGIN(&reader, size);
357
358 if(arg && (ref = lv2_osc_forge_message_head(forge, osc_urid, frame, arg->path)))
359 {
360 OSC_READER_MESSAGE_ITERATE(&reader, arg)
361 {
362 switch( (LV2_OSC_Type)*arg->type)
363 {
364 case LV2_OSC_INT32:
365 {
366 if(!(ref = lv2_osc_forge_int(forge, osc_urid, arg->i)))
367 return 0;
368 break;
369 }
370 case LV2_OSC_FLOAT:
371 {
372 if(!(ref = lv2_osc_forge_float(forge, osc_urid, arg->f)))
373 return 0;
374 break;
375 }
376 case LV2_OSC_STRING:
377 {
378 if(!(ref = lv2_osc_forge_string(forge, osc_urid, arg->s, arg->size - 1)))
379 return 0;
380 break;
381 }
382 case LV2_OSC_BLOB:
383 {
384 if(!(ref = lv2_osc_forge_blob(forge, osc_urid, arg->b, arg->size)))
385 return 0;
386 break;
387 }
388
389 case LV2_OSC_INT64:
390 {
391 if(!(ref = lv2_osc_forge_long(forge, osc_urid, arg->h)))
392 return 0;
393 break;
394 }
395 case LV2_OSC_DOUBLE:
396 {
397 if(!(ref = lv2_osc_forge_double(forge, osc_urid, arg->d)))
398 return 0;
399 break;
400 }
401 case LV2_OSC_TIMETAG:
402 {
403 if(!(ref = lv2_osc_forge_timetag(forge, osc_urid, LV2_OSC_TIMETAG_CREATE(arg->t))))
404 return 0;
405 break;
406 }
407
408 case LV2_OSC_TRUE:
409 {
410 if(!(ref = lv2_osc_forge_true(forge, osc_urid)))
411 return 0;
412 break;
413 }
414 case LV2_OSC_FALSE:
415 {
416 if(!(ref = lv2_osc_forge_false(forge, osc_urid)))
417 return 0;
418 break;
419 }
420 case LV2_OSC_NIL:
421 {
422 if(!(ref = lv2_osc_forge_nil(forge, osc_urid)))
423 return 0;
424 break;
425 }
426 case LV2_OSC_IMPULSE:
427 {
428 if(!(ref = lv2_osc_forge_impulse(forge, osc_urid)))
429 return 0;
430 break;
431 }
432
433 case LV2_OSC_SYMBOL:
434 {
435 if(!(ref = lv2_osc_forge_symbol(forge, osc_urid,
436 map->map(map->handle, arg->S))))
437 return 0;
438 break;
439 }
440 case LV2_OSC_MIDI:
441 {
442 if(!(ref = lv2_osc_forge_midi(forge, osc_urid, &arg->b[1], arg->size - 1)))
443 return 0;
444 break;
445 }
446 case LV2_OSC_CHAR:
447 {
448 if(!(ref = lv2_osc_forge_char(forge, osc_urid, arg->c)))
449 return 0;
450 break;
451 }
452 case LV2_OSC_RGBA:
453 {
454 if(!(ref = lv2_osc_forge_rgba(forge, osc_urid, arg->R, arg->G, arg->B, arg->A)))
455 return 0;
456 break;
457 }
458 }
459 }
460
461 lv2_osc_forge_pop(forge, frame);
462
463 return ref;
464 }
465 }
466
467 return 0;
468 }
469
470 #ifdef __cplusplus
471 } // extern "C"
472 #endif
473
474 #endif // LV2_OSC_FORGE_H
475