diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/presets.c | 348 | ||||
-rw-r--r-- | src/state.c | 354 |
2 files changed, 334 insertions, 368 deletions
diff --git a/src/presets.c b/src/presets.c deleted file mode 100644 index 2e145cd..0000000 --- a/src/presets.c +++ /dev/null @@ -1,348 +0,0 @@ -/* - Copyright 2007-2011 David Robillard <http://drobilla.net> - - 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. -*/ - -#define _POSIX_C_SOURCE 200112L /* for fileno */ -#define _BSD_SOURCE 1 /* for lockf */ - -#include <errno.h> -#include <sys/stat.h> -#include <sys/types.h> - -#include "lilv/lilv.h" - -#include "jalv-config.h" -#include "jalv_internal.h" - -#ifdef HAVE_LOCKF -#include <unistd.h> -#endif - -#define NS_LV2 "http://lv2plug.in/ns/lv2core#" -#define NS_PSET "http://lv2plug.in/ns/ext/presets#" -#define NS_RDF "http://www.w3.org/1999/02/22-rdf-syntax-ns#" -#define NS_RDFS "http://www.w3.org/2000/01/rdf-schema#" -#define NS_XSD "http://www.w3.org/2001/XMLSchema#" - -#define USTR(s) ((const uint8_t*)s) - -int -jalv_load_presets(Jalv* jalv, PresetSink sink, void* data) -{ - LilvNodes* presets = lilv_plugin_get_related(jalv->plugin, - jalv->preset_class); - LILV_FOREACH(nodes, i, presets) { - const LilvNode* preset = lilv_nodes_get(presets, i); - lilv_world_load_resource(jalv->world, preset); - LilvNodes* labels = lilv_world_find_nodes( - jalv->world, preset, jalv->label_pred, NULL); - if (labels) { - const LilvNode* label = lilv_nodes_get_first(labels); - sink(jalv, preset, label, data); - lilv_nodes_free(labels); - } else { - fprintf(stderr, "Preset <%s> has no rdfs:label\n", - lilv_node_as_string(lilv_nodes_get(presets, i))); - } - } - lilv_nodes_free(presets); - - return 0; -} - -static inline const LilvNode* -get_value(LilvWorld* world, const LilvNode* subject, const LilvNode* predicate) -{ - LilvNodes* vs = lilv_world_find_nodes(world, subject, predicate, NULL); - return vs ? lilv_nodes_get_first(vs) : NULL; -} - -int -jalv_apply_preset(Jalv* jalv, const LilvNode* preset) -{ - LilvNode* lv2_port = lilv_new_uri(jalv->world, NS_LV2 "port"); - LilvNode* lv2_symbol = lilv_new_uri(jalv->world, NS_LV2 "symbol"); - LilvNode* pset_value = lilv_new_uri(jalv->world, NS_PSET "value"); - - LilvNodes* ports = lilv_world_find_nodes( - jalv->world, preset, lv2_port, NULL); - LILV_FOREACH(nodes, i, ports) { - const LilvNode* port = lilv_nodes_get(ports, i); - const LilvNode* symbol = get_value(jalv->world, port, lv2_symbol); - const LilvNode* value = get_value(jalv->world, port, pset_value); - if (!symbol) { - fprintf(stderr, "error: Preset port missing symbol.\n"); - } else if (!value) { - fprintf(stderr, "error: Preset port missing value.\n"); - } else if (!lilv_node_is_float(value) && !lilv_node_is_int(value)) { - fprintf(stderr, "error: Preset port value is not a number.\n"); - } else { - const char* sym = lilv_node_as_string(symbol); - struct Port* p = jalv_port_by_symbol(jalv, sym); - if (p) { - const float fvalue = lilv_node_as_float(value); - // Send value to plugin - jalv_ui_write(jalv, p->index, sizeof(float), 0, &fvalue); - - // Update UI - char buf[sizeof(ControlChange) + sizeof(float)]; - ControlChange* ev = (ControlChange*)buf; - ev->index = p->index; - ev->protocol = 0; - ev->size = sizeof(float); - *(float*)ev->body = fvalue; - jack_ringbuffer_write(jalv->plugin_events, buf, sizeof(buf)); - } else { - fprintf(stderr, "error: Preset port `%s' is missing\n", sym); - } - } - } - lilv_nodes_free(ports); - - lilv_node_free(pset_value); - lilv_node_free(lv2_symbol); - lilv_node_free(lv2_port); - - return 0; -} - -static size_t -file_sink(const void* buf, size_t len, void* stream) -{ - FILE* file = (FILE*)stream; - return fwrite(buf, 1, len, file); -} - -static char* -pathify(const char* in, const char* ext) -{ - const size_t in_len = strlen(in); - const size_t ext_len = ext ? strlen(ext) : 0; - - char* out = malloc(in_len + ext_len + 1); - for (size_t i = 0; i < in_len; ++i) { - char c = in[i]; - if (!((c >= 'a' && c <= 'z') - || (c >= 'A' && c <= 'Z') - || (c >= '0' && c <= '9'))) { - c = '-'; - } - out[i] = c; - } - if (ext) { - memcpy(out + in_len, ext, ext_len); - } - return out; -} - -static char* -strjoin(const char* a, const char* b) -{ - const size_t a_len = strlen(a); - const size_t b_len = strlen(a); - char* const out = malloc(a_len + b_len + 1); - - memcpy(out, a, a_len); - memcpy(out + a_len, b, b_len); - out[a_len + b_len] = '\0'; - - return out; -} - -void -jalv_save_port_values(Jalv* jalv, - SerdWriter* writer, - const SerdNode* subject) -{ - for (uint32_t i = 0; i < jalv->num_ports; ++i) { - struct Port* const port = &jalv->ports[i]; - if (port->type != TYPE_CONTROL || port->flow != FLOW_INPUT) { - continue; - } - - const LilvNode* sym = lilv_port_get_symbol(jalv->plugin, port->lilv_port); - LilvNode* val = lilv_new_float(jalv->world, port->control); - - const SerdNode port_node = serd_node_from_string( - SERD_BLANK, USTR(lilv_node_as_string(sym))); - - // <> lv2:port _:symbol - SerdNode p = serd_node_from_string(SERD_URI, - USTR(NS_LV2 "port")); - serd_writer_write_statement(writer, SERD_ANON_O_BEGIN, - NULL, subject, &p, &port_node, NULL, NULL); - - // _:symbol lv2:symbol "symbol" - p = serd_node_from_string(SERD_URI, USTR(NS_LV2 "symbol")); - SerdNode o = serd_node_from_string(SERD_LITERAL, - USTR(lilv_node_as_string(sym))); - serd_writer_write_statement(writer, SERD_ANON_CONT, - NULL, &port_node, &p, &o, NULL, NULL); - - // _:symbol pset:value value - p = serd_node_from_string(SERD_URI, USTR(NS_PSET "value")); - o = serd_node_from_string(SERD_LITERAL, - USTR(lilv_node_as_string(val))); - SerdNode t = serd_node_from_string(SERD_URI, USTR(NS_XSD "decimal")); - serd_writer_write_statement(writer, SERD_ANON_CONT, - NULL, &port_node, &p, &o, &t, NULL); - - lilv_node_free(val); - serd_writer_end_anon(writer, &port_node); - } -} - -int -jalv_save_preset(Jalv* jalv, const char* label) -{ - const char* const home = getenv("HOME"); - if (!home) { - fprintf(stderr, "error: $HOME is undefined\n"); - return 1; - } - - const char* const bundle_name = "presets.lv2/"; - - // Create ~/.lv2/ and ~/.lv2/presets.lv2/ if necessary - char* const lv2dir = strjoin(home, "/.lv2/"); - char* const bundle = strjoin(lv2dir, bundle_name); - char* const filename = pathify(label, ".ttl"); - char* const path = strjoin(bundle, filename); - char* const uri = strjoin("file://", path); - char* const manifest_path = strjoin(bundle, "manifest.ttl"); - char* const manifest_uri = strjoin("file: //", manifest_path); - - int ret = 0; - if ((mkdir(lv2dir, 0755) && errno != EEXIST) - || (mkdir(bundle, 0755) && errno != EEXIST)) { - fprintf(stderr, "error: Unable to create %s (%s)\n", - lv2dir, strerror(errno)); - ret = 2; - goto done; - } - - // Open preset file - FILE* fd = fopen((char*)path, "w"); - if (!fd) { - fprintf(stderr, "error: Failed to open %s (%s)\n", - path, strerror(errno)); - ret = 3; - goto done; - } - - SerdURI base_uri; - SerdNode base = serd_node_new_uri_from_string((const uint8_t*)uri, - NULL, &base_uri); - - SerdEnv* env = serd_env_new(&base); - serd_env_set_prefix_from_strings(env, USTR("lv2"), USTR(NS_LV2)); - serd_env_set_prefix_from_strings(env, USTR("pset"), USTR(NS_PSET)); - serd_env_set_prefix_from_strings(env, USTR("rdfs"), USTR(NS_RDFS)); - - // Write preset file - - SerdWriter* writer = serd_writer_new( - SERD_TURTLE, SERD_STYLE_ABBREVIATED|SERD_STYLE_CURIED, - env, &base_uri, - file_sink, - fd); - - serd_env_foreach(env, (SerdPrefixSink)serd_writer_set_prefix, writer); - - // <> a pset:Preset - SerdNode s = serd_node_from_string(SERD_URI, USTR("")); - SerdNode p = serd_node_from_string(SERD_URI, USTR(NS_RDF "type")); - SerdNode o = serd_node_from_string(SERD_CURIE, USTR("pset:Preset")); - serd_writer_write_statement(writer, 0, NULL, &s, &p, &o, NULL, NULL); - - // <> rdfs:label label - p = serd_node_from_string(SERD_URI, USTR(NS_RDFS "label")); - o = serd_node_from_string(SERD_LITERAL, USTR(label)); - serd_writer_write_statement(writer, 0, - NULL, &s, &p, &o, NULL, NULL); - - jalv_save_port_values(jalv, writer, &s); - - serd_writer_free(writer); - serd_node_free(&base); - - // Append record to manifest - - fclose(fd); - fd = fopen((char*)manifest_path, "a"); - if (!fd) { - fprintf(stderr, "error: Failed to open %s (%s)\n", - path, strerror(errno)); - serd_env_free(env); - ret = 4; - goto done; - } - -#ifdef HAVE_LOCKF - lockf(fileno(fd), F_LOCK, 0); -#endif - - base = serd_node_new_uri_from_string((const uint8_t*)manifest_uri, - NULL, &base_uri); - - writer = serd_writer_new( - SERD_TURTLE, SERD_STYLE_ABBREVIATED|SERD_STYLE_CURIED, - env, &base_uri, - file_sink, - fd); - - fseek(fd, 0, SEEK_END); - if (ftell(fd) == 0) { - serd_env_foreach(env, (SerdPrefixSink)serd_writer_set_prefix, writer); - } - - s = serd_node_from_string(SERD_URI, USTR(filename)); - - // <preset> a pset:Preset - p = serd_node_from_string(SERD_URI, USTR(NS_RDF "type")); - o = serd_node_from_string(SERD_CURIE, USTR("pset:Preset")); - serd_writer_write_statement(writer, 0, NULL, &s, &p, &o, NULL, NULL); - - // <preset> rdfs:seeAlso <preset> - p = serd_node_from_string(SERD_URI, USTR(NS_RDFS "seeAlso")); - serd_writer_write_statement(writer, 0, NULL, &s, &p, &s, NULL, NULL); - - // <preset> lv2:appliesTo <plugin> - p = serd_node_from_string(SERD_URI, USTR(NS_LV2 "appliesTo")); - o = serd_node_from_string( - SERD_URI, USTR(lilv_node_as_string(lilv_plugin_get_uri(jalv->plugin)))); - serd_writer_write_statement(writer, 0, NULL, &s, &p, &o, NULL, NULL); - - serd_writer_free(writer); - serd_env_free(env); - serd_node_free(&base); - -#ifdef HAVE_LOCKF - lockf(fileno(fd), F_ULOCK, 0); -#endif - - fclose(fd); - -done: - free(manifest_uri); - free(manifest_path); - free(uri); - free(path); - free(filename); - free(bundle); - free(lv2dir); - - return ret; -} diff --git a/src/state.c b/src/state.c index 5eb50a1..1f36dc1 100644 --- a/src/state.c +++ b/src/state.c @@ -14,25 +14,38 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#define _POSIX_C_SOURCE 200112L /* for fileno */ +#define _BSD_SOURCE 1 /* for lockf */ + #include <assert.h> #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/types.h> #ifdef HAVE_LV2_STATE # include "lv2/lv2plug.in/ns/ext/state/state.h" #endif +#include "lilv/lilv.h" + #include "jalv-config.h" #include "jalv_internal.h" -#define NS_ATOM (const uint8_t*)"http://lv2plug.in/ns/ext/atom#" -#define NS_JALV (const uint8_t*)"http://drobilla.net/ns/jalv#" -#define NS_LV2 (const uint8_t*)"http://lv2plug.in/ns/lv2core#" -#define NS_PSET (const uint8_t*)"http://lv2plug.in/ns/ext/presets#" -#define NS_STATE (const uint8_t*)"http://lv2plug.in/ns/ext/state#" -#define NS_XSD (const uint8_t*)"http://www.w3.org/2001/XMLSchema#" -#define NS_RDFS (const uint8_t*)"http://www.w3.org/2000/01/rdf-schema#" +#ifdef HAVE_LOCKF +#include <unistd.h> +#endif + +#define NS_ATOM "http://lv2plug.in/ns/ext/atom#" +#define NS_JALV "http://drobilla.net/ns/jalv#" +#define NS_LV2 "http://lv2plug.in/ns/lv2core#" +#define NS_PSET "http://lv2plug.in/ns/ext/presets#" +#define NS_RDF "http://www.w3.org/1999/02/22-rdf-syntax-ns#" +#define NS_RDFS "http://www.w3.org/2000/01/rdf-schema#" +#define NS_STATE "http://lv2plug.in/ns/ext/state#" +#define NS_XSD "http://www.w3.org/2001/XMLSchema#" #define USTR(s) ((const uint8_t*)s) @@ -78,6 +91,20 @@ value_cmp(const void* a, const void* b) return strcmp((const char*)pa->symbol.buf, (const char*)pb->symbol.buf); } +static char* +strjoin(const char* a, const char* b) +{ + const size_t a_len = strlen(a); + const size_t b_len = strlen(b); + char* const out = malloc(a_len + b_len + 1); + + memcpy(out, a, a_len); + memcpy(out + a_len, b, b_len); + out[a_len + b_len] = '\0'; + + return out; +} + #ifdef HAVE_LV2_STATE typedef struct { LV2_URID_Unmap* unmap; @@ -158,13 +185,8 @@ file_sink(const void* buf, size_t len, void* stream) void jalv_save(Jalv* jalv, const char* dir) { - const size_t dir_len = strlen(dir); - const char* const filename = "state.ttl"; - const size_t path_len = dir_len + strlen(filename); - char* const path = (char*)malloc(path_len + 1); - - snprintf(path, path_len + 1, "%s%s", dir, filename); - FILE* out_fd = fopen(path, "w"); + char* const path = strjoin(dir, "/state.ttl"); + FILE* out_fd = fopen(path, "w"); SerdEnv* env = serd_env_new(NULL); serd_env_set_prefix_from_strings(env, USTR("atom"), USTR(NS_ATOM)); @@ -174,7 +196,8 @@ jalv_save(Jalv* jalv, const char* dir) serd_env_set_prefix_from_strings(env, USTR("rdfs"), USTR(NS_RDFS)); serd_env_set_prefix_from_strings(env, USTR("state"), USTR(NS_STATE)); - SerdNode lv2_appliesTo = serd_node_from_string(SERD_URI, NS_LV2 "appliesTo"); + SerdNode lv2_appliesTo = serd_node_from_string(SERD_URI, + USTR(NS_LV2 "appliesTo")); SerdNode plugin_uri = serd_node_from_string(SERD_URI, USTR(lilv_node_as_uri( lilv_plugin_get_uri(jalv->plugin)))); @@ -206,7 +229,7 @@ jalv_save(Jalv* jalv, const char* dir) if (state) { SerdNode state_instanceState = serd_node_from_string( - SERD_URI, (NS_STATE "instanceState")); + SERD_URI, USTR(NS_STATE "instanceState")); // [] state:instanceState [ SerdNode state_node = serd_node_from_string(SERD_BLANK, USTR("state")); @@ -295,15 +318,18 @@ load_state_from_file(LilvWorld* world, PluginState* jalv_load_state(Jalv* jalv, const char* dir) { - const size_t dir_len = strlen(dir); - const size_t state_uri_len = strlen("file:///state.ttl") + dir_len + 1; - char* state_uri = (char*)malloc(state_uri_len); - snprintf(state_uri, state_uri_len, "file://%s/state.ttl", dir); + char* base_uri = strjoin("file://", dir); + char* state_uri = strjoin(base_uri, "/state.ttl"); + fprintf(stderr, "DIR: %s\n", base_uri); + fprintf(stderr, "BASE: %s\n", base_uri); + fprintf(stderr, "LOAD: %s\n", state_uri); + PluginState* state = load_state_from_file( jalv->world, &jalv->map, state_uri); free(state_uri); + free(base_uri); return state; } @@ -378,3 +404,291 @@ jalv_apply_state(Jalv* jalv, PluginState* state) } #endif // HAVE_LV2_STATE } + +int +jalv_load_presets(Jalv* jalv, PresetSink sink, void* data) +{ + LilvNodes* presets = lilv_plugin_get_related(jalv->plugin, + jalv->preset_class); + LILV_FOREACH(nodes, i, presets) { + const LilvNode* preset = lilv_nodes_get(presets, i); + lilv_world_load_resource(jalv->world, preset); + LilvNodes* labels = lilv_world_find_nodes( + jalv->world, preset, jalv->label_pred, NULL); + if (labels) { + const LilvNode* label = lilv_nodes_get_first(labels); + sink(jalv, preset, label, data); + lilv_nodes_free(labels); + } else { + fprintf(stderr, "Preset <%s> has no rdfs:label\n", + lilv_node_as_string(lilv_nodes_get(presets, i))); + } + } + lilv_nodes_free(presets); + + return 0; +} + +static inline const LilvNode* +get_value(LilvWorld* world, const LilvNode* subject, const LilvNode* predicate) +{ + LilvNodes* vs = lilv_world_find_nodes(world, subject, predicate, NULL); + return vs ? lilv_nodes_get_first(vs) : NULL; +} + +int +jalv_apply_preset(Jalv* jalv, const LilvNode* preset) +{ + LilvNode* lv2_port = lilv_new_uri(jalv->world, NS_LV2 "port"); + LilvNode* lv2_symbol = lilv_new_uri(jalv->world, NS_LV2 "symbol"); + LilvNode* pset_value = lilv_new_uri(jalv->world, NS_PSET "value"); + + LilvNodes* ports = lilv_world_find_nodes( + jalv->world, preset, lv2_port, NULL); + LILV_FOREACH(nodes, i, ports) { + const LilvNode* port = lilv_nodes_get(ports, i); + const LilvNode* symbol = get_value(jalv->world, port, lv2_symbol); + const LilvNode* value = get_value(jalv->world, port, pset_value); + if (!symbol) { + fprintf(stderr, "error: Preset port missing symbol.\n"); + } else if (!value) { + fprintf(stderr, "error: Preset port missing value.\n"); + } else if (!lilv_node_is_float(value) && !lilv_node_is_int(value)) { + fprintf(stderr, "error: Preset port value is not a number.\n"); + } else { + const char* sym = lilv_node_as_string(symbol); + struct Port* p = jalv_port_by_symbol(jalv, sym); + if (p) { + const float fvalue = lilv_node_as_float(value); + // Send value to plugin + jalv_ui_write(jalv, p->index, sizeof(float), 0, &fvalue); + + // Update UI + char buf[sizeof(ControlChange) + sizeof(float)]; + ControlChange* ev = (ControlChange*)buf; + ev->index = p->index; + ev->protocol = 0; + ev->size = sizeof(float); + *(float*)ev->body = fvalue; + jack_ringbuffer_write(jalv->plugin_events, buf, sizeof(buf)); + } else { + fprintf(stderr, "error: Preset port `%s' is missing\n", sym); + } + } + } + lilv_nodes_free(ports); + + lilv_node_free(pset_value); + lilv_node_free(lv2_symbol); + lilv_node_free(lv2_port); + + return 0; +} + +static char* +pathify(const char* in, const char* ext) +{ + const size_t in_len = strlen(in); + const size_t ext_len = ext ? strlen(ext) : 0; + + char* out = malloc(in_len + ext_len + 1); + for (size_t i = 0; i < in_len; ++i) { + char c = in[i]; + if (!((c >= 'a' && c <= 'z') + || (c >= 'A' && c <= 'Z') + || (c >= '0' && c <= '9'))) { + c = '-'; + } + out[i] = c; + } + if (ext) { + memcpy(out + in_len, ext, ext_len); + } + return out; +} + +void +jalv_save_port_values(Jalv* jalv, + SerdWriter* writer, + const SerdNode* subject) +{ + for (uint32_t i = 0; i < jalv->num_ports; ++i) { + struct Port* const port = &jalv->ports[i]; + if (port->type != TYPE_CONTROL || port->flow != FLOW_INPUT) { + continue; + } + + const LilvNode* sym = lilv_port_get_symbol(jalv->plugin, port->lilv_port); + LilvNode* val = lilv_new_float(jalv->world, port->control); + + const SerdNode port_node = serd_node_from_string( + SERD_BLANK, USTR(lilv_node_as_string(sym))); + + // <> lv2:port _:symbol + SerdNode p = serd_node_from_string(SERD_URI, + USTR(NS_LV2 "port")); + serd_writer_write_statement(writer, SERD_ANON_O_BEGIN, + NULL, subject, &p, &port_node, NULL, NULL); + + // _:symbol lv2:symbol "symbol" + p = serd_node_from_string(SERD_URI, USTR(NS_LV2 "symbol")); + SerdNode o = serd_node_from_string(SERD_LITERAL, + USTR(lilv_node_as_string(sym))); + serd_writer_write_statement(writer, SERD_ANON_CONT, + NULL, &port_node, &p, &o, NULL, NULL); + + // _:symbol pset:value value + p = serd_node_from_string(SERD_URI, USTR(NS_PSET "value")); + o = serd_node_from_string(SERD_LITERAL, + USTR(lilv_node_as_string(val))); + SerdNode t = serd_node_from_string(SERD_URI, USTR(NS_XSD "decimal")); + serd_writer_write_statement(writer, SERD_ANON_CONT, + NULL, &port_node, &p, &o, &t, NULL); + + lilv_node_free(val); + serd_writer_end_anon(writer, &port_node); + } +} + +int +jalv_save_preset(Jalv* jalv, const char* label) +{ + const char* const home = getenv("HOME"); + if (!home) { + fprintf(stderr, "error: $HOME is undefined\n"); + return 1; + } + + const char* const bundle_name = "presets.lv2/"; + + // Create ~/.lv2/ and ~/.lv2/presets.lv2/ if necessary + char* const lv2dir = strjoin(home, "/.lv2/"); + char* const bundle = strjoin(lv2dir, bundle_name); + char* const filename = pathify(label, ".ttl"); + char* const path = strjoin(bundle, filename); + char* const uri = strjoin("file://", path); + char* const manifest_path = strjoin(bundle, "manifest.ttl"); + char* const manifest_uri = strjoin("file: //", manifest_path); + + int ret = 0; + if ((mkdir(lv2dir, 0755) && errno != EEXIST) + || (mkdir(bundle, 0755) && errno != EEXIST)) { + fprintf(stderr, "error: Unable to create %s (%s)\n", + lv2dir, strerror(errno)); + ret = 2; + goto done; + } + + // Open preset file + FILE* fd = fopen((char*)path, "w"); + if (!fd) { + fprintf(stderr, "error: Failed to open %s (%s)\n", + path, strerror(errno)); + ret = 3; + goto done; + } + + SerdURI base_uri; + SerdNode base = serd_node_new_uri_from_string((const uint8_t*)uri, + NULL, &base_uri); + + SerdEnv* env = serd_env_new(&base); + serd_env_set_prefix_from_strings(env, USTR("lv2"), USTR(NS_LV2)); + serd_env_set_prefix_from_strings(env, USTR("pset"), USTR(NS_PSET)); + serd_env_set_prefix_from_strings(env, USTR("rdfs"), USTR(NS_RDFS)); + + // Write preset file + + SerdWriter* writer = serd_writer_new( + SERD_TURTLE, SERD_STYLE_ABBREVIATED|SERD_STYLE_CURIED, + env, &base_uri, + file_sink, + fd); + + serd_env_foreach(env, (SerdPrefixSink)serd_writer_set_prefix, writer); + + // <> a pset:Preset + SerdNode s = serd_node_from_string(SERD_URI, USTR("")); + SerdNode p = serd_node_from_string(SERD_URI, USTR(NS_RDF "type")); + SerdNode o = serd_node_from_string(SERD_CURIE, USTR("pset:Preset")); + serd_writer_write_statement(writer, 0, NULL, &s, &p, &o, NULL, NULL); + + // <> rdfs:label label + p = serd_node_from_string(SERD_URI, USTR(NS_RDFS "label")); + o = serd_node_from_string(SERD_LITERAL, USTR(label)); + serd_writer_write_statement(writer, 0, + NULL, &s, &p, &o, NULL, NULL); + + jalv_save_port_values(jalv, writer, &s); + + serd_writer_free(writer); + serd_node_free(&base); + + // Append record to manifest + + fclose(fd); + fd = fopen((char*)manifest_path, "a"); + if (!fd) { + fprintf(stderr, "error: Failed to open %s (%s)\n", + path, strerror(errno)); + serd_env_free(env); + ret = 4; + goto done; + } + +#ifdef HAVE_LOCKF + lockf(fileno(fd), F_LOCK, 0); +#endif + + base = serd_node_new_uri_from_string((const uint8_t*)manifest_uri, + NULL, &base_uri); + + writer = serd_writer_new( + SERD_TURTLE, SERD_STYLE_ABBREVIATED|SERD_STYLE_CURIED, + env, &base_uri, + file_sink, + fd); + + fseek(fd, 0, SEEK_END); + if (ftell(fd) == 0) { + serd_env_foreach(env, (SerdPrefixSink)serd_writer_set_prefix, writer); + } + + s = serd_node_from_string(SERD_URI, USTR(filename)); + + // <preset> a pset:Preset + p = serd_node_from_string(SERD_URI, USTR(NS_RDF "type")); + o = serd_node_from_string(SERD_CURIE, USTR("pset:Preset")); + serd_writer_write_statement(writer, 0, NULL, &s, &p, &o, NULL, NULL); + + // <preset> rdfs:seeAlso <preset> + p = serd_node_from_string(SERD_URI, USTR(NS_RDFS "seeAlso")); + serd_writer_write_statement(writer, 0, NULL, &s, &p, &s, NULL, NULL); + + // <preset> lv2:appliesTo <plugin> + p = serd_node_from_string(SERD_URI, USTR(NS_LV2 "appliesTo")); + o = serd_node_from_string( + SERD_URI, USTR(lilv_node_as_string(lilv_plugin_get_uri(jalv->plugin)))); + serd_writer_write_statement(writer, 0, NULL, &s, &p, &o, NULL, NULL); + + serd_writer_free(writer); + serd_env_free(env); + serd_node_free(&base); + +#ifdef HAVE_LOCKF + lockf(fileno(fd), F_ULOCK, 0); +#endif + + fclose(fd); + +done: + free(manifest_uri); + free(manifest_path); + free(uri); + free(path); + free(filename); + free(bundle); + free(lv2dir); + + return ret; +} |