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