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