1 /*
2  * Copyright (c) 2016-2021 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 #include <stdio.h>
19 #include <stdlib.h>
20 
21 #include <eteroj.h>
22 #include <varchunk.h>
23 #include <osc.lv2/util.h>
24 #include <osc.lv2/forge.h>
25 #include <props.h>
26 #include <jsmn.h>
27 
28 #define MAX_NPROPS 1
29 #define MAX_TOKENS 256
30 
31 typedef struct _plugstate_t plugstate_t;
32 typedef struct _plughandle_t plughandle_t;
33 
34 struct _plugstate_t {
35 	int32_t query_refresh;
36 };
37 
38 struct _plughandle_t {
39 	LV2_URID_Map *map;
40 	LV2_URID_Unmap *unmap;
41 	struct {
42 		LV2_URID subject;
43 
44 		LV2_URID patch_message;
45 		LV2_URID patch_set;
46 		LV2_URID patch_get;
47 		LV2_URID patch_subject;
48 		LV2_URID patch_property;
49 		LV2_URID patch_value;
50 		LV2_URID patch_wildcard;
51 		LV2_URID patch_patch;
52 		LV2_URID patch_add;
53 		LV2_URID patch_remove;
54 		LV2_URID patch_writable;
55 		LV2_URID patch_readable;
56 
57 		LV2_URID rdfs_label;
58 		LV2_URID rdfs_comment;
59 		LV2_URID rdfs_range;
60 
61 		LV2_URID rdf_value;
62 
63 		LV2_URID lv2_minimum;
64 		LV2_URID lv2_maximum;
65 		LV2_URID lv2_scale_point;
66 
67 		LV2_URID query_refresh;
68 	} urid;
69 
70 	LV2_OSC_URID osc_urid;
71 	LV2_Atom_Forge forge;
72 	LV2_Atom_Forge_Ref ref;
73 	int64_t frames;
74 
75 	PROPS_T(props, MAX_NPROPS);
76 
77 	plugstate_t state;
78 	plugstate_t stash;
79 
80 	LV2_Log_Log *log;
81 	LV2_Log_Logger logger;
82 
83 	const LV2_Atom_Sequence *osc_in;
84 	LV2_Atom_Sequence *osc_out;
85 
86 	int32_t cnt;
87 
88 	jsmn_parser parser;
89 	jsmntok_t tokens [MAX_TOKENS];
90 
91 	varchunk_t *rb;
92 };
93 
94 static void
_add(plughandle_t * handle,int64_t frame_time,char type,bool read,bool write,const char * json,int range_cnt,jsmntok_t * range,int values_cnt,jsmntok_t * values,LV2_URID property,const char * label,uint32_t label_len,const char * comment,uint32_t comment_len)95 _add(plughandle_t *handle, int64_t frame_time, char type, bool read, bool write,
96 	const char *json, int range_cnt, jsmntok_t *range, int values_cnt, jsmntok_t *values,
97 	LV2_URID property, const char *label, uint32_t label_len, const char *comment, uint32_t comment_len)
98 {
99 	LV2_Atom_Forge *forge = &handle->forge;
100 	LV2_Atom_Forge_Frame obj_frame;
101 	LV2_Atom_Forge_Ref ref = handle->ref;
102 
103 	if(write && !read) //TODO handle this
104 		return;
105 
106 	if(!range_cnt && !values_cnt) //TODO handle this
107 		return;
108 
109 	LV2_URID access = write
110 		? handle->urid.patch_writable
111 		: handle->urid.patch_readable;
112 
113 	LV2_URID _type = forge->Int;
114 	switch((LV2_OSC_Type)type)
115 	{
116 		case LV2_OSC_INT32:
117 			_type = forge->Int;
118 			break;
119 		case LV2_OSC_INT64:
120 			_type = forge->Long;
121 			break;
122 		case LV2_OSC_FLOAT:
123 			_type = forge->Float;
124 			break;
125 		case LV2_OSC_DOUBLE:
126 			_type = forge->Double;
127 			break;
128 		case LV2_OSC_STRING:
129 			_type = forge->String;
130 			break;
131 		default:
132 			//TODO do other types
133 			break;
134 	}
135 
136 	jsmntok_t *mintok = NULL;
137 	jsmntok_t *maxtok = NULL;
138 	double min = 0.f;
139 	double max = 1.f;
140 
141 	if(range_cnt && range)
142 	{
143 		mintok = &range[0];
144 		maxtok = &range[1];
145 		min = strtod(&json[mintok->start], NULL);
146 		max = strtod(&json[maxtok->start], NULL);
147 		if( (_type == forge->Int) && (min == 0.0) && (max == 1.0) )
148 			_type = forge->Bool;
149 	}
150 
151 	lv2_atom_forge_frame_time(forge, frame_time);
152 	lv2_atom_forge_object(forge, &obj_frame, 0, handle->urid.patch_patch);
153 	{
154 		lv2_atom_forge_key(forge, handle->urid.patch_subject);
155 		lv2_atom_forge_urid(forge, handle->urid.subject);
156 
157 		lv2_atom_forge_key(forge, handle->urid.patch_remove);
158 		LV2_Atom_Forge_Frame remove_frame;
159 		lv2_atom_forge_object(forge, &remove_frame, 0, 0);
160 		{
161 			lv2_atom_forge_key(forge, access);
162 			lv2_atom_forge_urid(forge, property);
163 		}
164 		lv2_atom_forge_pop(forge, &remove_frame);
165 
166 		lv2_atom_forge_key(forge, handle->urid.patch_add);
167 		LV2_Atom_Forge_Frame add_frame;
168 		lv2_atom_forge_object(forge, &add_frame, 0, 0);
169 		{
170 			lv2_atom_forge_key(forge, access);
171 			lv2_atom_forge_urid(forge, property);
172 		}
173 		lv2_atom_forge_pop(forge, &add_frame);
174 	}
175 	lv2_atom_forge_pop(forge, &obj_frame);
176 
177 	lv2_atom_forge_frame_time(forge, frame_time);
178 	lv2_atom_forge_object(forge, &obj_frame, 0, handle->urid.patch_patch);
179 	{
180 		lv2_atom_forge_key(forge, handle->urid.patch_subject);
181 		lv2_atom_forge_urid(forge, property);
182 
183 		lv2_atom_forge_key(forge, handle->urid.patch_remove);
184 		LV2_Atom_Forge_Frame remove_frame;
185 		lv2_atom_forge_object(forge, &remove_frame, 0, 0);
186 		{
187 			lv2_atom_forge_key(forge, handle->urid.rdfs_label);
188 			lv2_atom_forge_urid(forge, handle->urid.patch_wildcard);
189 
190 			lv2_atom_forge_key(forge, handle->urid.rdfs_range);
191 			lv2_atom_forge_urid(forge, handle->urid.patch_wildcard);
192 
193 			lv2_atom_forge_key(forge, handle->urid.rdfs_comment);
194 			lv2_atom_forge_urid(forge, handle->urid.patch_wildcard);
195 
196 			lv2_atom_forge_key(forge, handle->urid.lv2_minimum);
197 			lv2_atom_forge_urid(forge, handle->urid.patch_wildcard);
198 
199 			lv2_atom_forge_key(forge, handle->urid.lv2_maximum);
200 			lv2_atom_forge_urid(forge, handle->urid.patch_wildcard);
201 
202 			lv2_atom_forge_key(forge, handle->urid.lv2_scale_point);
203 			lv2_atom_forge_urid(forge, handle->urid.patch_wildcard);
204 		}
205 		lv2_atom_forge_pop(forge, &remove_frame);
206 
207 		lv2_atom_forge_key(forge, handle->urid.patch_add);
208 		LV2_Atom_Forge_Frame add_frame;
209 		lv2_atom_forge_object(forge, &add_frame, 0, 0);
210 		{
211 			if(label)
212 			{
213 				lv2_atom_forge_key(forge, handle->urid.rdfs_label);
214 				lv2_atom_forge_string(forge, label, label_len);
215 			}
216 
217 			if(comment)
218 			{
219 				lv2_atom_forge_key(forge, handle->urid.rdfs_comment);
220 				lv2_atom_forge_string(forge, comment, comment_len);
221 			}
222 
223 			lv2_atom_forge_key(forge, handle->urid.rdfs_range);
224 			lv2_atom_forge_urid(forge, _type);
225 
226 			if(mintok && (_type != forge->Bool) )
227 			{
228 				lv2_atom_forge_key(forge, handle->urid.lv2_minimum);
229 				if(_type == forge->Int)
230 					lv2_atom_forge_int(forge, min);
231 				else if(_type == forge->Long)
232 					lv2_atom_forge_long(forge, min);
233 				else if(_type == forge->Float)
234 					lv2_atom_forge_float(forge, min);
235 				else if(_type == forge->Double)
236 					lv2_atom_forge_double(forge, min);
237 				else
238 					lv2_atom_forge_atom(forge, 0, 0); // blank
239 				//TODO do other types
240 			}
241 
242 			if(maxtok && (_type != forge->Bool) )
243 			{
244 				lv2_atom_forge_key(forge, handle->urid.lv2_maximum);
245 				if(_type == forge->Int)
246 					lv2_atom_forge_int(forge, max);
247 				else if(_type == forge->Long)
248 					lv2_atom_forge_long(forge, max);
249 				else if(_type == forge->Float)
250 					lv2_atom_forge_float(forge, max);
251 				else if(_type == forge->Double)
252 					lv2_atom_forge_double(forge, max);
253 				else
254 					lv2_atom_forge_atom(forge, 0, 0); // blank
255 				//TODO do other types
256 			}
257 
258 			if(values_cnt && values)
259 			{
260 				LV2_Atom_Forge_Frame tuple_frame;
261 				lv2_atom_forge_key(forge, handle->urid.lv2_scale_point);
262 				lv2_atom_forge_tuple(forge, &tuple_frame);
263 
264 				//iterate over all scale_points
265 				for(int i=0; i<values_cnt; i++)
266 				{
267 					jsmntok_t *tok = &values[i];
268 
269 					LV2_Atom_Forge_Frame scale_point_frame;
270 					lv2_atom_forge_object(forge, &scale_point_frame, 0, 0);
271 					{
272 						lv2_atom_forge_key(forge, handle->urid.rdfs_label);
273 						lv2_atom_forge_string(forge, &json[tok->start], tok->end - tok->start);
274 
275 						lv2_atom_forge_key(forge, handle->urid.rdf_value);
276 						if(_type == forge->Int)
277 							lv2_atom_forge_int(forge, strtol(&json[tok->start], NULL, 0));
278 						else if(_type == forge->Long)
279 							lv2_atom_forge_long(forge, strtol(&json[tok->start], NULL, 0));
280 						else if(_type == forge->Float)
281 							lv2_atom_forge_float(forge, strtod(&json[tok->start], NULL));
282 						else if(_type == forge->Double)
283 							lv2_atom_forge_double(forge, strtod(&json[tok->start], NULL));
284 						else if(_type == forge->String)
285 							lv2_atom_forge_string(forge, &json[tok->start], tok->end - tok->start);
286 						else
287 							lv2_atom_forge_atom(forge, 0, 0); // blank
288 						//TODO do other types
289 					}
290 					lv2_atom_forge_pop(forge, &scale_point_frame);
291 				}
292 				lv2_atom_forge_pop(forge, &tuple_frame);
293 			}
294 		}
295 		lv2_atom_forge_pop(forge, &add_frame);
296 	}
297 	lv2_atom_forge_pop(forge, &obj_frame);
298 
299 	handle->ref = ref;
300 }
301 
302 static void
_set(plughandle_t * handle,int64_t frame_time,LV2_URID property,const LV2_Atom * atom)303 _set(plughandle_t *handle, int64_t frame_time, LV2_URID property, const LV2_Atom *atom)
304 {
305 	LV2_Atom_Forge *forge = &handle->forge;
306 	LV2_Atom_Forge_Frame obj_frame;
307 	LV2_Atom_Forge_Ref ref = handle->ref;
308 
309 	lv2_atom_forge_frame_time(forge, frame_time);
310 	lv2_atom_forge_object(forge, &obj_frame, 0, handle->urid.patch_set);
311 	{
312 		lv2_atom_forge_key(forge, handle->urid.patch_subject);
313 		lv2_atom_forge_urid(forge, handle->urid.subject);
314 
315 		lv2_atom_forge_key(forge, handle->urid.patch_property);
316 		lv2_atom_forge_urid(forge, property);
317 
318 		lv2_atom_forge_key(forge, handle->urid.patch_value);
319 		lv2_atom_forge_write(forge, atom, lv2_atom_total_size(atom));
320 	}
321 	lv2_atom_forge_pop(forge, &obj_frame);
322 
323 	handle->ref = ref;
324 }
325 
326 static void
_clear(plughandle_t * handle,int64_t frame_time)327 _clear(plughandle_t *handle, int64_t frame_time)
328 {
329 	LV2_Atom_Forge *forge = &handle->forge;
330 	LV2_Atom_Forge_Frame obj_frame;
331 	LV2_Atom_Forge_Ref ref = handle->ref;
332 
333 	lv2_atom_forge_frame_time(forge, frame_time);
334 	lv2_atom_forge_object(forge, &obj_frame, 0, handle->urid.patch_patch);
335 	{
336 		lv2_atom_forge_key(forge, handle->urid.patch_subject);
337 		lv2_atom_forge_urid(forge, handle->urid.subject);
338 
339 		lv2_atom_forge_key(forge, handle->urid.patch_remove);
340 		LV2_Atom_Forge_Frame remove_frame;
341 		lv2_atom_forge_object(forge, &remove_frame, 0, 0);
342 		{
343 			lv2_atom_forge_key(forge, handle->urid.patch_writable);
344 			lv2_atom_forge_urid(forge, handle->urid.patch_wildcard);
345 
346 			lv2_atom_forge_key(forge, handle->urid.patch_readable);
347 			lv2_atom_forge_urid(forge, handle->urid.patch_wildcard);
348 		}
349 		lv2_atom_forge_pop(forge, &remove_frame);
350 
351 		lv2_atom_forge_key(forge, handle->urid.patch_add);
352 		LV2_Atom_Forge_Frame add_frame;
353 		lv2_atom_forge_object(forge, &add_frame, 0, 0);
354 		{
355 			// empty
356 		}
357 		lv2_atom_forge_pop(forge, &add_frame);
358 	}
359 	lv2_atom_forge_pop(forge, &obj_frame);
360 
361 	handle->ref = ref;
362 }
363 
364 static void
_refresh(plughandle_t * handle,int64_t frame_time)365 _refresh(plughandle_t *handle, int64_t frame_time)
366 {
367 	_clear(handle, frame_time);
368 
369 	const char *destination = "/!";
370 
371 	// schedule on ring buffer
372 	size_t len2 = strlen(destination) + 1;
373 	char *ptr;
374 	if((ptr = varchunk_write_request(handle->rb, len2)))
375 	{
376 		strncpy(ptr, destination, len2);
377 		varchunk_write_advance(handle->rb, len2);
378 	}
379 	else if(handle->log)
380 		lv2_log_trace(&handle->logger, "eteroj#query: ringbuffer full");
381 }
382 
383 static void
_intercept_refresh(void * data,int64_t frames,props_impl_t * impl)384 _intercept_refresh(void *data, int64_t frames, props_impl_t *impl)
385 {
386 	plughandle_t *handle = data;
387 
388 	_refresh(handle, frames);
389 
390 	handle->state.query_refresh = false;
391 	props_set(&handle->props, &handle->forge, frames, handle->urid.query_refresh, &handle->ref);
392 }
393 
394 static const props_def_t defs [MAX_NPROPS] = {
395 	{
396 		.property = ETEROJ_QUERY_REFRESH_URI,
397 		.offset = offsetof(plugstate_t, query_refresh),
398 		.type = LV2_ATOM__Bool,
399 		.event_cb = _intercept_refresh
400 	}
401 };
402 
403 static LV2_Handle
instantiate(const LV2_Descriptor * descriptor,double rate,const char * bundle_path,const LV2_Feature * const * features)404 instantiate(const LV2_Descriptor* descriptor, double rate,
405 	const char *bundle_path, const LV2_Feature *const *features)
406 {
407 	plughandle_t *handle = calloc(1, sizeof(plughandle_t));
408 	if(!handle)
409 		return NULL;
410 	mlock(handle, sizeof(plughandle_t));
411 
412 	const LV2_State_Make_Path *make_path = NULL;
413 
414 	for(int i=0; features[i]; i++)
415 	{
416 		if(!strcmp(features[i]->URI, LV2_URID__map))
417 			handle->map = features[i]->data;
418 		else if(!strcmp(features[i]->URI, LV2_URID__unmap))
419 			handle->unmap = features[i]->data;
420 		else if(!strcmp(features[i]->URI, LV2_LOG__log))
421 			handle->log = features[i]->data;
422 	}
423 
424 	if(!handle->map)
425 	{
426 		fprintf(stderr,
427 			"%s: Host does not support urid:map\n", descriptor->URI);
428 		free(handle);
429 		return NULL;
430 	}
431 	if(!handle->unmap)
432 	{
433 		fprintf(stderr,
434 			"%s: Host does not support urid:unmap\n", descriptor->URI);
435 		free(handle);
436 		return NULL;
437 	}
438 
439 	if(handle->log)
440 		lv2_log_logger_init(&handle->logger, handle->map, handle->log);
441 	lv2_osc_urid_init(&handle->osc_urid, handle->map);
442 	lv2_atom_forge_init(&handle->forge, handle->map);
443 
444 	handle->urid.subject = handle->map->map(handle->map->handle,
445 		descriptor->URI);
446 
447 	handle->urid.patch_message = handle->map->map(handle->map->handle,
448 		LV2_PATCH__Message);
449 	handle->urid.patch_set = handle->map->map(handle->map->handle,
450 		LV2_PATCH__Set);
451 	handle->urid.patch_get = handle->map->map(handle->map->handle,
452 		LV2_PATCH__Get);
453 	handle->urid.patch_subject = handle->map->map(handle->map->handle,
454 		LV2_PATCH__subject);
455 	handle->urid.patch_property = handle->map->map(handle->map->handle,
456 		LV2_PATCH__property);
457 	handle->urid.patch_value = handle->map->map(handle->map->handle,
458 		LV2_PATCH__value);
459 	handle->urid.patch_wildcard = handle->map->map(handle->map->handle,
460 		LV2_PATCH__wildcard);
461 	handle->urid.patch_patch = handle->map->map(handle->map->handle,
462 		LV2_PATCH__Patch);
463 	handle->urid.patch_add = handle->map->map(handle->map->handle,
464 		LV2_PATCH__add);
465 	handle->urid.patch_remove = handle->map->map(handle->map->handle,
466 		LV2_PATCH__remove);
467 	handle->urid.patch_writable = handle->map->map(handle->map->handle,
468 		LV2_PATCH__writable);
469 	handle->urid.patch_readable = handle->map->map(handle->map->handle,
470 		LV2_PATCH__readable);
471 
472 	handle->urid.rdfs_label = handle->map->map(handle->map->handle,
473 		"http://www.w3.org/2000/01/rdf-schema#label");
474 	handle->urid.rdfs_comment = handle->map->map(handle->map->handle,
475 		"http://www.w3.org/2000/01/rdf-schema#comment");
476 	handle->urid.rdfs_range = handle->map->map(handle->map->handle,
477 		"http://www.w3.org/2000/01/rdf-schema#range");
478 
479 	handle->urid.rdf_value = handle->map->map(handle->map->handle,
480 		"http://www.w3.org/1999/02/22-rdf-syntax-ns#value");
481 
482 	handle->urid.lv2_minimum = handle->map->map(handle->map->handle,
483 		LV2_CORE__minimum);
484 	handle->urid.lv2_maximum = handle->map->map(handle->map->handle,
485 		LV2_CORE__maximum);
486 	handle->urid.lv2_scale_point = handle->map->map(handle->map->handle,
487 		LV2_CORE__scalePoint);
488 
489 	handle->cnt = 0;
490 
491 	handle->rb = varchunk_new(65536, false);
492 
493 	if(!props_init(&handle->props, descriptor->URI,
494 		defs, MAX_NPROPS, &handle->state, &handle->stash,
495 		handle->map, handle))
496 	{
497 		free(handle);
498 		return NULL;
499 	}
500 
501 	handle->urid.query_refresh = props_map(&handle->props, ETEROJ_QUERY_REFRESH_URI);
502 
503 	return handle;
504 }
505 
506 static void
connect_port(LV2_Handle instance,uint32_t port,void * data)507 connect_port(LV2_Handle instance, uint32_t port, void *data)
508 {
509 	plughandle_t *handle = (plughandle_t *)instance;
510 
511 	switch(port)
512 	{
513 		case 0:
514 			handle->osc_in = (const LV2_Atom_Sequence *)data;
515 			break;
516 		case 1:
517 			handle->osc_out = (LV2_Atom_Sequence *)data;
518 			break;
519 		default:
520 			break;
521 	}
522 }
523 
524 static inline int
json_eq(const char * json,jsmntok_t * tok,const char * s)525 json_eq(const char *json, jsmntok_t *tok, const char *s)
526 {
527 	if(  (tok->type == JSMN_STRING)
528 		&& ((int)strlen(s) == tok->end - tok->start)
529 		&& !strncmp(json + tok->start, s, tok->end - tok->start) )
530 	{
531 		return 0;
532 	}
533 
534 	return -1;
535 }
536 
537 static inline const char *
json_string(const char * json,jsmntok_t * tok,size_t * len)538 json_string(const char *json, jsmntok_t *tok, size_t *len)
539 {
540 	if(tok->type != JSMN_STRING)
541 		return NULL;
542 
543 	*len = tok->end - tok->start;
544 	return json + tok->start;
545 }
546 
547 static inline int32_t
json_int(const char * json,jsmntok_t * tok)548 json_int(const char *json, jsmntok_t *tok)
549 {
550 	if(tok->type != JSMN_PRIMITIVE)
551 		return -1;
552 
553 	return strtol(json + tok->start, NULL, 10);
554 }
555 
556 static inline float
json_float(const char * json,jsmntok_t * tok)557 json_float(const char *json, jsmntok_t *tok)
558 {
559 	if(tok->type != JSMN_PRIMITIVE)
560 		return -1;
561 
562 	return strtod(json + tok->start, NULL);
563 }
564 
565 static inline bool
json_bool(const char * json,jsmntok_t * tok)566 json_bool(const char *json, jsmntok_t *tok)
567 {
568 	if(tok->type != JSMN_PRIMITIVE)
569 		return false;
570 
571 	if(json[tok->start] == 't')
572 		return true;
573 	else if(json[tok->start] == 'f')
574 		return false;
575 
576 	return false;
577 }
578 
579 // rt
580 static void
_message_cb(const char * path,const LV2_Atom_Tuple * body,void * data)581 _message_cb(const char *path, const LV2_Atom_Tuple *body, void *data)
582 {
583 	plughandle_t *handle = data;
584 	LV2_OSC_URID *osc_urid = &handle->osc_urid;
585 	LV2_Atom_Forge *forge = &handle->forge;
586 	jsmntok_t *t = handle->tokens;
587 
588 	const LV2_Atom *atom = lv2_atom_tuple_begin(body);
589 
590 	if(!strcmp(path, "/success"))
591 	{
592 		int32_t id;
593 		const char *destination;
594 
595 		atom = lv2_osc_int32_get(osc_urid, atom, &id);
596 		atom = lv2_osc_string_get(osc_urid, atom, &destination);
597 		//fprintf(stderr, "success: %s\n", destination);
598 
599 		if(strrchr(destination, '!'))
600 		{
601 			const char *json;
602 			atom = lv2_osc_string_get(osc_urid, atom, &json);
603 			jsmn_init(&handle->parser);
604 			int n_tokens = jsmn_parse(&handle->parser, json, strlen(json),
605 				handle->tokens, MAX_TOKENS);
606 			if( (n_tokens < 1) && handle->log)
607 				lv2_log_trace(&handle->logger, "eror parsing JSON: '%s'", json);
608 
609 			size_t target_len = 0;
610 			const char *target = NULL;
611 			size_t type_len = 0;
612 			const char *type = NULL;
613 			size_t desc_len = 0;
614 			const char *desc = NULL;
615 
616 			int arg_n = 0;
617 			char arg_type = 'i';
618 			bool arg_read = true;
619 			bool arg_write = false;
620 			int arg_range_cnt = 0;
621 			jsmntok_t *arg_range = NULL;
622 			int arg_values_cnt = 0;
623 			jsmntok_t *arg_values = NULL;
624 
625 			for(int i = 1; i < n_tokens; )
626 			{
627 				jsmntok_t *key = &t[i++];
628 				jsmntok_t *value = &t[i++];
629 
630 				if(!json_eq(json, key, "path"))
631 				{
632 					target = json_string(json, value, &target_len);
633 				}
634 				else if(!json_eq(json, key, "type"))
635 				{
636 					type = json_string(json, value, &type_len);
637 				}
638 				else if(!json_eq(json, key, "description"))
639 				{
640 					desc = json_string(json, value, &desc_len);
641 				}
642 				else if(!json_eq(json, key, "items"))
643 				{
644 					for(int j = 0; j < value->size; j++)
645 					{
646 						jsmntok_t *item = &t[i++];
647 						size_t len = 0;
648 						const char *s = json_string(json, item, &len);
649 
650 						// add request to ring buffer
651 						size_t len2 = target_len + len + 2;
652 						char *ptr;
653 						if((ptr = varchunk_write_request(handle->rb, len2)))
654 						{
655 							strncpy(ptr, target, target_len);
656 							strncpy(ptr + target_len, s, len);
657 							ptr[target_len + len] = '!';
658 							ptr[target_len + len + 1] = 0;
659 
660 							varchunk_write_advance(handle->rb, len2);
661 						}
662 						else if(handle->log)
663 							lv2_log_trace(&handle->logger, "eteroj#query: ringbuffer full");
664 					}
665 				}
666 				else if(!json_eq(json, key, "arguments"))
667 				{
668 					arg_n = value->size;
669 
670 					for(int j = 0; j < value->size; j++)
671 					{
672 						jsmntok_t *item = &t[i++];
673 
674 						for(int m = 0; m < item->size; m++)
675 						{
676 							jsmntok_t *item_key = &t[i++];
677 							jsmntok_t *item_val = &t[i++];
678 
679 							if(!json_eq(json, item_key, "type"))
680 							{
681 								size_t len;
682 								const char *s = json_string(json, item_val, &len);
683 
684 								if(j == 0)
685 									arg_type = s[0];
686 							}
687 							else if(!json_eq(json, item_key, "description"))
688 							{
689 								size_t len = 0;
690 								const char *s = json_string(json, item_val, &len);
691 
692 								char dest [1024];
693 								strncpy(dest, s, len);
694 								dest[len] = 0;
695 							}
696 							else if(!json_eq(json, item_key, "read"))
697 							{
698 								const bool boolean = json_bool(json, item_val);
699 
700 								if(j == 0)
701 									arg_read = boolean;
702 							}
703 							else if(!json_eq(json, item_key, "write"))
704 							{
705 								const bool boolean = json_bool(json, item_val);
706 
707 								if(j == 0)
708 									arg_write = boolean;
709 							}
710 							else if(!json_eq(json, item_key, "range"))
711 							{
712 								arg_range_cnt = item_val->size;
713 								arg_range = item_val + 1;
714 
715 								for(int n = 0; n < item_val->size; n++)
716 								{
717 									jsmntok_t *range = &t[i++];
718 								}
719 							}
720 							else if(!json_eq(json, item_key, "values"))
721 							{
722 								arg_values_cnt = item_val->size;
723 								arg_values = item_val + 1;
724 
725 								for(int n = 0; n < item_val->size; n++)
726 								{
727 									jsmntok_t *val = &t[i++];
728 								}
729 							}
730 						}
731 					}
732 				}
733 			}
734 
735 			// register methods in UI
736 			if(!strncmp(type, "method", type_len) && (arg_n == 1) ) //FIXME handle all arg_n
737 			{
738 				char dest[1024];
739 				strncpy(dest, target, target_len);
740 				dest[target_len] = 0;
741 				LV2_URID property = handle->map->map(handle->map->handle, dest);
742 
743 				_add(handle, 0, arg_type, arg_read, arg_write, json, arg_range_cnt, arg_range,
744 					arg_values_cnt, arg_values, property, target, target_len, desc, desc_len);
745 			}
746 		}
747 		else
748 		{
749 			// is this a reply with arguments?
750 			if(!lv2_atom_tuple_is_end(LV2_ATOM_BODY_CONST(body), body->atom.size, atom))
751 			{
752 				LV2_URID property = handle->map->map(handle->map->handle, destination);
753 				_set(handle, handle->frames, property, atom);
754 			}
755 		}
756 	}
757 	else if(!strcmp(path, "/error"))
758 	{
759 		int32_t id;
760 		const char *destination;
761 		const char *msg;
762 
763 		atom = lv2_osc_int32_get(osc_urid, atom, &id);
764 		atom = lv2_osc_string_get(osc_urid, atom, &destination);
765 		atom = lv2_osc_string_get(osc_urid, atom, &msg);
766 		if(handle->log)
767 			lv2_log_trace(&handle->logger, "error: %s (%s)", destination, msg);
768 	}
769 }
770 
771 static void
run(LV2_Handle instance,uint32_t nsamples)772 run(LV2_Handle instance, uint32_t nsamples)
773 {
774 	plughandle_t *handle = instance;
775 
776 	LV2_Atom_Forge *forge = &handle->forge;
777 	LV2_Atom_Forge_Frame frame;
778 
779 	// prepare sequence forges
780 	const uint32_t capacity = handle->osc_out->atom.size;
781 	lv2_atom_forge_set_buffer(forge, (uint8_t *)handle->osc_out, capacity);
782 	handle->ref = lv2_atom_forge_sequence_head(forge, &frame, 0);
783 
784 	props_idle(&handle->props, &handle->forge, 0, &handle->ref);
785 
786 	LV2_ATOM_SEQUENCE_FOREACH(handle->osc_in, ev)
787 	{
788 		const LV2_Atom_Object *obj = (const LV2_Atom_Object *)&ev->body;
789 		const int64_t frames = ev->time.frames;
790 
791 		if(lv2_osc_is_message_or_bundle_type(&handle->osc_urid, obj->body.otype))
792 		{
793 			handle->frames = frames;
794 			lv2_osc_unroll(&handle->osc_urid, obj, _message_cb, handle);
795 		}
796 		else if(obj->atom.type == forge->Object)
797 		{
798 			props_advance(&handle->props, forge, frames, obj, &handle->ref);
799 
800 			if(obj->body.otype == handle->urid.patch_set)
801 			{
802 				const LV2_Atom_URID *subject = NULL;
803 				const LV2_Atom_URID *property = NULL;
804 				const LV2_Atom *value = NULL;
805 
806 				lv2_atom_object_get(obj,
807 					handle->urid.patch_subject, &subject,
808 					handle->urid.patch_property, &property,
809 					handle->urid.patch_value, &value,
810 					0);
811 
812 				if(!property || !value)
813 					continue;
814 
815 				if(subject && (subject->body != handle->urid.subject))
816 					continue; // subject not matching
817 
818 				const char *uri = handle->unmap->unmap(handle->unmap->handle, property->body);
819 
820 				if( (value->type == forge->Int) || (value->type == forge->Bool) )
821 				{
822 					if(handle->ref)
823 						handle->ref = lv2_atom_forge_frame_time(forge, frames);
824 					if(handle->ref)
825 						handle->ref = lv2_osc_forge_message_vararg(forge, &handle->osc_urid, uri, "ii",
826 							handle->cnt++, ((const LV2_Atom_Int *)value)->body);
827 				}
828 				else if(value->type == forge->Long)
829 				{
830 					if(handle->ref)
831 						handle->ref = lv2_atom_forge_frame_time(forge, frames);
832 					if(handle->ref)
833 						handle->ref = lv2_osc_forge_message_vararg(forge, &handle->osc_urid, uri, "ih",
834 							handle->cnt++, ((const LV2_Atom_Long *)value)->body);
835 				}
836 				else if(value->type == forge->Float)
837 				{
838 					if(handle->ref)
839 						handle->ref = lv2_atom_forge_frame_time(forge, frames);
840 					if(handle->ref)
841 						handle->ref = lv2_osc_forge_message_vararg(forge, &handle->osc_urid, uri, "if",
842 							handle->cnt++, ((const LV2_Atom_Float *)value)->body);
843 				}
844 				else if(value->type == forge->Double)
845 				{
846 					if(handle->ref)
847 						handle->ref = lv2_atom_forge_frame_time(forge, frames);
848 					if(handle->ref)
849 						handle->ref = lv2_osc_forge_message_vararg(forge, &handle->osc_urid, uri, "id",
850 							handle->cnt++, ((const LV2_Atom_Double *)value)->body);
851 				}
852 				else if(value->type == forge->String)
853 				{
854 					if(handle->ref)
855 						handle->ref = lv2_atom_forge_frame_time(forge, frames);
856 					if(handle->ref)
857 						handle->ref = lv2_osc_forge_message_vararg(forge, &handle->osc_urid, uri, "is",
858 							handle->cnt++, LV2_ATOM_BODY_CONST(value));
859 				}
860 			}
861 			else if(obj->body.otype == handle->urid.patch_get)
862 			{
863 				const LV2_Atom_URID *subject = NULL;
864 				const LV2_Atom_URID *property = NULL;
865 
866 				lv2_atom_object_get(obj,
867 					handle->urid.patch_subject, &subject,
868 					handle->urid.patch_property, &property,
869 					0);
870 
871 				if(subject && (subject->body != handle->urid.subject))
872 					continue; // subject not matching
873 
874 				if(!property)
875 				{
876 					_refresh(handle, frames);
877 				}
878 				else
879 				{
880 					const char *uri = handle->unmap->unmap(handle->unmap->handle, property->body);
881 
882 					// schedule on ring buffer
883 					size_t len2 = strlen(uri) + 1;
884 					char *ptr;
885 					if((ptr = varchunk_write_request(handle->rb, len2)))
886 					{
887 						strncpy(ptr, uri, len2);
888 						varchunk_write_advance(handle->rb, len2);
889 					}
890 					else if(handle->log)
891 						lv2_log_trace(&handle->logger, "eteroj#query: ringbuffer full");
892 				}
893 			}
894 		}
895 	}
896 
897 	{
898 		// send requests in ring buffer
899 		size_t len2;
900 		const char *ptr;
901 		int cnt = 0;
902 		if( (ptr = varchunk_read_request(handle->rb, &len2)) && (cnt++ < 10) ) //TODO how many?
903 		{
904 			if(handle->ref)
905 				handle->ref = lv2_atom_forge_frame_time(forge, nsamples-1);
906 			if(handle->ref)
907 				handle->ref = lv2_osc_forge_message_vararg(forge, &handle->osc_urid, ptr, "i", handle->cnt++);
908 
909 			varchunk_read_advance(handle->rb);
910 		}
911 	}
912 
913 	if(handle->ref)
914 		lv2_atom_forge_pop(forge, &frame);
915 	else
916 		lv2_atom_sequence_clear(handle->osc_out);
917 }
918 
919 static void
cleanup(LV2_Handle instance)920 cleanup(LV2_Handle instance)
921 {
922 	plughandle_t *handle = instance;
923 
924 	if(handle->rb)
925 		varchunk_free(handle->rb);
926 	munlock(handle, sizeof(plughandle_t));
927 	free(handle);
928 }
929 
930 static LV2_State_Status
_state_save(LV2_Handle instance,LV2_State_Store_Function store,LV2_State_Handle state,uint32_t flags,const LV2_Feature * const * features)931 _state_save(LV2_Handle instance, LV2_State_Store_Function store,
932 	LV2_State_Handle state, uint32_t flags,
933 	const LV2_Feature *const *features)
934 {
935 	plughandle_t *handle = (plughandle_t *)instance;
936 
937 	return props_save(&handle->props, store, state, flags, features);
938 }
939 
940 static LV2_State_Status
_state_restore(LV2_Handle instance,LV2_State_Retrieve_Function retrieve,LV2_State_Handle state,uint32_t flags,const LV2_Feature * const * features)941 _state_restore(LV2_Handle instance, LV2_State_Retrieve_Function retrieve,
942 	LV2_State_Handle state, uint32_t flags,
943 	const LV2_Feature *const *features)
944 {
945 	plughandle_t *handle = (plughandle_t *)instance;
946 
947 	return props_restore(&handle->props, retrieve, state, flags, features);
948 }
949 
950 static const LV2_State_Interface state_iface = {
951 	.save = _state_save,
952 	.restore = _state_restore
953 };
954 
955 static const void *
extension_data(const char * uri)956 extension_data(const char *uri)
957 {
958 	if(!strcmp(uri, LV2_STATE__interface))
959 		return &state_iface;
960 
961 	return NULL;
962 }
963 
964 const LV2_Descriptor eteroj_query = {
965 	.URI						= ETEROJ_QUERY_URI,
966 	.instantiate		= instantiate,
967 	.connect_port		= connect_port,
968 	.activate				= NULL,
969 	.run						= run,
970 	.deactivate			= NULL,
971 	.cleanup				= cleanup,
972 	.extension_data	= extension_data
973 };
974