From bfee18f05fae23fa8107de86761c79d07955e0ca Mon Sep 17 00:00:00 2001 From: David Robillard Date: Sat, 18 Feb 2012 06:54:24 +0000 Subject: Add -d option and implement proper communication dumping. git-svn-id: http://svn.drobilla.net/lad/trunk/jalv@3986 a436a847-0d15-0410-975c-d299462d15a1 --- doc/jalv.1 | 6 ++- src/atom_rdf.c | 138 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/jalv.c | 36 +++++++------- src/jalv_console.c | 5 +- src/jalv_gtk2.c | 4 +- src/jalv_internal.h | 8 +++ src/symap.c | 6 ++- wscript | 2 +- 8 files changed, 181 insertions(+), 24 deletions(-) create mode 100644 src/atom_rdf.c diff --git a/doc/jalv.1 b/doc/jalv.1 index 116a1ce..bc44007 100644 --- a/doc/jalv.1 +++ b/doc/jalv.1 @@ -1,4 +1,4 @@ -.TH JALV "17 Jan 2012" +.TH JALV "18 Feb 2012" .SH NAME .B jalv \- Run an LV2 plugin as a JACK application. @@ -20,6 +20,10 @@ UUID for Jack session restoration. \fB\-l DIR\fR Load state from state directory. +.TP +\fB\-d DIR\fR +Dump plugin <=> UI communication. + .SH SEE ALSO .BR lv2ls(1), .BR jackd(1) diff --git a/src/atom_rdf.c b/src/atom_rdf.c new file mode 100644 index 0000000..2ee97f2 --- /dev/null +++ b/src/atom_rdf.c @@ -0,0 +1,138 @@ +/* + Copyright 2012 David Robillard + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#include +#include + +#include "lv2/lv2plug.in/ns/ext/atom/atom.h" +#include "lv2/lv2plug.in/ns/ext/atom/atom-helpers.h" +#include "lv2/lv2plug.in/ns/ext/urid/urid.h" + +#include "serd/serd.h" + +#define NS_ATOM "http://lv2plug.in/ns/ext/atom#" +#define NS_XSD "http://www.w3.org/2001/XMLSchema#" + +#define USTR(str) ((const uint8_t*)str) + +typedef struct { + char* buf; + size_t len; +} String; + +static size_t +string_sink(const void* buf, size_t len, void* stream) +{ + String* str = (String*)stream; + str->buf = realloc(str->buf, str->len + len); + memcpy(str->buf + str->len, buf, len); + str->len += len; + return len; +} + +void +atom_to_rdf(SerdWriter* writer, + LV2_URID_Unmap* unmap, + const SerdNode* subject, + const SerdNode* predicate, + const LV2_Atom* atom, + uint32_t flags) +{ + const char* const type = unmap->unmap(unmap->handle, atom->type); + SerdNode object = SERD_NODE_NULL; + SerdNode datatype = SERD_NODE_NULL; + bool new_node = false; + if (atom->type == 0 && atom->size == 0) { + object = serd_node_from_string(SERD_BLANK, USTR("null")); + } else if (!strcmp(type, NS_ATOM "String")) { + const uint8_t* str = USTR(LV2_ATOM_BODY(atom)); + object = serd_node_from_string(SERD_LITERAL, str); + } else if (!strcmp(type, NS_ATOM "URID")) { + const uint32_t id = *(const uint32_t*)LV2_ATOM_BODY(atom); + const uint8_t* str = USTR(unmap->unmap(unmap->handle, id)); + object = serd_node_from_string(SERD_URI, str); + } else if (!strcmp(type, NS_ATOM "URI")) { + const uint8_t* str = USTR(LV2_ATOM_BODY(atom)); + object = serd_node_from_string(SERD_URI, str); + } else if (!strcmp(type, NS_ATOM "Int32")) { + new_node = true; + object = serd_node_new_integer(*(int32_t*)LV2_ATOM_BODY(atom)); + datatype = serd_node_from_string(SERD_URI, USTR(NS_XSD "integer")); + } else if (!strcmp(type, NS_ATOM "Float")) { + new_node = true; + object = serd_node_new_decimal(*(float*)LV2_ATOM_BODY(atom), 8); + datatype = serd_node_from_string(SERD_URI, USTR(NS_XSD "decimal")); + } else if (!strcmp(type, NS_ATOM "Double")) { + new_node = true; + object = serd_node_new_decimal(*(float*)LV2_ATOM_BODY(atom), 16); + datatype = serd_node_from_string(SERD_URI, USTR(NS_XSD "decimal")); + } else if (!strcmp(type, NS_ATOM "Bool")) { + new_node = true; + datatype = serd_node_from_string(SERD_URI, USTR(NS_XSD "boolean")); + if (*(int32_t*)LV2_ATOM_BODY(atom)) { + object = serd_node_from_string(SERD_LITERAL, USTR("true")); + } else { + object = serd_node_from_string(SERD_LITERAL, USTR("false")); + } + } else if (!strcmp(type, NS_ATOM "Blank")) { + const LV2_Atom_Object* obj = (const LV2_Atom_Object*)atom; + SerdNode idnum = serd_node_new_integer(obj->id); + SerdNode id = serd_node_from_string(SERD_BLANK, idnum.buf); + serd_writer_write_statement( + writer, flags|SERD_ANON_O_BEGIN, NULL, + subject, predicate, &id, NULL, NULL); + LV2_OBJECT_FOREACH(obj, i) { + const LV2_Atom_Property_Body* prop = lv2_object_iter_get(i); + const char* const key = unmap->unmap(unmap->handle, prop->key); + SerdNode pred = serd_node_from_string(SERD_URI, USTR(key)); + atom_to_rdf(writer, unmap, &id, &pred, &prop->value, SERD_ANON_CONT); + } + serd_writer_end_anon(writer, &id); + serd_node_free(&idnum); + } + + if (object.buf) { + serd_writer_write_statement( + writer, flags, NULL, subject, predicate, &object, &datatype, NULL); + } + + if (new_node) { + serd_node_free(&object); + } +} + +char* +atom_to_turtle(LV2_URID_Unmap* unmap, + const SerdNode* subject, + const SerdNode* predicate, + const LV2_Atom* atom) +{ + SerdURI base_uri = SERD_URI_NULL; + SerdEnv* env = serd_env_new(NULL); + String str = { NULL, 0 }; + SerdWriter* writer = serd_writer_new( + SERD_TURTLE, + SERD_STYLE_ABBREVIATED|SERD_STYLE_RESOLVED|SERD_STYLE_CURIED, + env, &base_uri, string_sink, &str); + + atom_to_rdf(writer, unmap, subject, predicate, atom, 0); + serd_writer_finish(writer); + string_sink("", 1, &str); + + serd_writer_free(writer); + serd_env_free(env); + return str.buf; +} diff --git a/src/jalv.c b/src/jalv.c index ab81162..f1b01d0 100644 --- a/src/jalv.c +++ b/src/jalv.c @@ -1,5 +1,5 @@ /* - Copyright 2007-2011 David Robillard + Copyright 2007-2012 David Robillard Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -52,7 +52,10 @@ #define NS_ATOM "http://lv2plug.in/ns/ext/atom#" #define NS_MIDI "http://lv2plug.in/ns/ext/midi#" #define NS_PSET "http://lv2plug.in/ns/ext/presets#" +#define NS_RDF "http://www.w3.org/1999/02/22-rdf-syntax-ns#" +#define USTR(str) ((const uint8_t*)str) + ZixSem exit_sem; /**< Exit semaphore */ LV2_URID @@ -386,11 +389,6 @@ jack_process_cb(jack_nframes_t nframes, void* data) assert(ev.size == sizeof(float)); port->control = *(float*)body; } else if (ev.protocol == host->atom_prot_id) { - printf("ATOM UI READ\n"); - for (uint32_t i = 0; i < ev.size; ++i) { - printf("%c", body[i]); - } - printf("\n"); LV2_Evbuf_Iterator i = lv2_evbuf_end(port->evbuf); const LV2_Atom* const atom = (const LV2_Atom*)body; lv2_evbuf_write(&i, nframes, 0, @@ -511,11 +509,11 @@ jalv_ui_write(SuilController controller, } if (protocol == host->atom_prot_id) { - printf("ATOM UI WRITE: %d\n", protocol); - for (uint32_t i = 0; i < buffer_size; ++i) { - printf("%c", ((uint8_t*)buffer)[i]); - } - printf("\n"); + SerdNode s = serd_node_from_string(SERD_BLANK, USTR("msg")); + SerdNode p = serd_node_from_string(SERD_URI, USTR(NS_RDF "value")); + char* str = atom_to_turtle(&host->unmap, &s, &p, (LV2_Atom*)buffer); + printf("\n## UI => Plugin ##\n%s\n", str); + free(str); } char buf[sizeof(ControlChange) + buffer_size]; @@ -524,13 +522,6 @@ jalv_ui_write(SuilController controller, ev->protocol = protocol; ev->size = buffer_size; memcpy(ev->body, buffer, buffer_size); - #if 0 - printf("WRITE: "); - for (uint32_t i = 0; i < sizeof(buf); ++i) { - printf("%c", buf[i]); - } - printf("\n"); - #endif jack_ringbuffer_write(host->ui_events, buf, sizeof(buf)); } @@ -543,6 +534,15 @@ jalv_emit_ui_events(Jalv* host) jack_ringbuffer_read(host->plugin_events, (char*)&ev, sizeof(ev)); char buf[ev.size]; jack_ringbuffer_read(host->plugin_events, buf, ev.size); + + if (ev.protocol == host->atom_prot_id) { + SerdNode s = serd_node_from_string(SERD_BLANK, USTR("msg")); + SerdNode p = serd_node_from_string(SERD_URI, USTR(NS_RDF "value")); + char* str = atom_to_turtle(&host->unmap, &s, &p, (LV2_Atom*)buf); + printf("\n## Plugin => UI ##\n%s\n", str); + free(str); + } + suil_instance_port_event(host->ui_instance, ev.index, ev.size, ev.protocol, buf); } diff --git a/src/jalv_console.c b/src/jalv_console.c index 80be5cd..ae5c30f 100644 --- a/src/jalv_console.c +++ b/src/jalv_console.c @@ -1,5 +1,5 @@ /* - Copyright 2007-2011 David Robillard + Copyright 2007-2012 David Robillard Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -30,6 +30,7 @@ print_usage(const char* name, bool error) fprintf(os, " -h Display this help and exit\n"); fprintf(os, " -u UUID UUID for Jack session restoration\n"); fprintf(os, " -l DIR Load state from save directory\n"); + fprintf(os, " -d DIR Dump plugin <=> UI communication\n"); return error ? 1 : 0; } @@ -58,6 +59,8 @@ jalv_init(int* argc, char*** argv, JalvOptions* opts) return 1; } opts->load = jalv_strdup((*argv)[a]); + } else if ((*argv)[a][1] == 'd') { + opts->dump = true; } else { fprintf(stderr, "Unknown option %s\n", (*argv)[a]); return print_usage((*argv)[0], true); diff --git a/src/jalv_gtk2.c b/src/jalv_gtk2.c index fad7609..3e20398 100644 --- a/src/jalv_gtk2.c +++ b/src/jalv_gtk2.c @@ -1,5 +1,5 @@ /* - Copyright 2007-2011 David Robillard + Copyright 2007-2012 David Robillard Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -36,6 +36,8 @@ jalv_init(int* argc, char*** argv, JalvOptions* opts) "UUID for Jack session restoration", "UUID" }, { "load", 'l', 0, G_OPTION_ARG_STRING, &opts->load, "Load state from save directory", "DIR" }, + { "dump", 'd', 0, G_OPTION_ARG_NONE, &opts->dump, + "Dump plugin <=> UI communication", NULL }, { 0, 0, 0, 0, 0, 0, 0 } }; GError* error = NULL; const int err = gtk_init_with_args( diff --git a/src/jalv_internal.h b/src/jalv_internal.h index 25da829..1dc225f 100644 --- a/src/jalv_internal.h +++ b/src/jalv_internal.h @@ -27,6 +27,7 @@ #include "serd/serd.h" #include "suil/suil.h" +#include "lv2/lv2plug.in/ns/ext/atom/atom.h" #include "lv2/lv2plug.in/ns/ext/urid/urid.h" #include "lv2/lv2plug.in/ns/ext/state/state.h" @@ -78,6 +79,7 @@ typedef struct { typedef struct { char* uuid; char* load; + bool dump; } JalvOptions; typedef enum { @@ -189,6 +191,12 @@ jalv_make_path(LV2_State_Make_Path_Handle handle, void jalv_apply_state(Jalv* jalv, LilvState* state); +char* +atom_to_turtle(LV2_URID_Unmap* unmap, + const SerdNode* subject, + const SerdNode* predicate, + const LV2_Atom* atom); + static inline char* jalv_strdup(const char* str) { diff --git a/src/symap.c b/src/symap.c index ee9320d..f7cc653 100644 --- a/src/symap.c +++ b/src/symap.c @@ -1,5 +1,5 @@ /* - Copyright 2011 David Robillard + Copyright 2011-2012 David Robillard Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -172,7 +172,9 @@ symap_map(Symap* map, const char* sym) const char* symap_unmap(Symap* map, uint32_t id) { - if (id <= map->size) { + if (id == 0) { + return NULL; + } else if (id <= map->size) { return map->symbols[id - 1]; } return NULL; diff --git a/wscript b/wscript index f04a9e0..4c5933b 100644 --- a/wscript +++ b/wscript @@ -83,7 +83,7 @@ def configure(conf): def build(bld): libs = 'LILV SUIL JACK SERD LV2CORE LV2_EVENT LV2_ATOM LV2_URI_MAP LV2_STATE' - source = 'src/jalv.c src/symap.c src/state.c src/lv2_evbuf.c' + source = 'src/jalv.c src/symap.c src/state.c src/lv2_evbuf.c src/atom_rdf.c' # Non-GUI version obj = bld(features = 'c cprogram', -- cgit v1.2.1