diff --git a/libslv2/examples/plugins/Amp-slv2.lv2/Makefile b/libslv2/examples/plugins/Amp-slv2.lv2/Makefile index 55180c2b..eb7dfe1a 100644 --- a/libslv2/examples/plugins/Amp-slv2.lv2/Makefile +++ b/libslv2/examples/plugins/Amp-slv2.lv2/Makefile @@ -1,4 +1,4 @@ -CFLAGS = -Wall -I../../../include -fPIC +CFLAGS = -Wall -I../../../include -fPIC -g -O0 all: amp.so diff --git a/libslv2/include/lv2.ttl b/libslv2/include/lv2.ttl index c7d1ac98..75b2aa3b 100644 --- a/libslv2/include/lv2.ttl +++ b/libslv2/include/lv2.ttl @@ -55,7 +55,7 @@ To be used by a host a Plugin must have at least the following properties: rdf:type (with object :Plugin) doap:name (one without language tag) doap:licence - lv2:port + :port """ . @@ -147,7 +147,7 @@ Plugins will write values to this array during their run method. :dataType a rdf:Property ; rdfs:domain :Port ; - rdfs:range lv2:DataType ; + rdfs:range :DataType ; rdfs:label "Port Data type" ; rdfs:comment """ Relates a Port to the data type(s) it can accept. Hosts that do not support diff --git a/libslv2/slv2/plugin.h b/libslv2/slv2/plugin.h index 01dfc606..2b2a2958 100644 --- a/libslv2/slv2/plugin.h +++ b/libslv2/slv2/plugin.h @@ -158,6 +158,27 @@ slv2_plugin_get_property(const SLV2Plugin* p, uint32_t slv2_plugin_get_num_ports(const SLV2Plugin* p); +/** Return whether or not the plugin introduces (and reports) latency. + * + * The index of the latency port can be found with slv2_plugin_get_latency_port + * ONLY if this function returns true. + */ +bool +slv2_plugin_has_latency(const SLV2Plugin* p); + +/** Return the index of the plugin's latency port, or the empty string if the + * plugin has no latency. + * + * It is a fatal error to call this on a plugin without checking if the port + * exists by first calling slv2_plugin_has_latency. + * + * Any plugin that introduces unwanted latency that should be compensated for + * (by hosts with the ability/need) MUST provide this port, which is a control + * rate output port that reports the latency for each cycle in frames. + */ +uint32_t +slv2_plugin_get_latency_port(const SLV2Plugin* p); + /** @} */ diff --git a/libslv2/slv2/private_types.h b/libslv2/slv2/private_types.h index a9c60bf0..fdfba655 100644 --- a/libslv2/slv2/private_types.h +++ b/libslv2/slv2/private_types.h @@ -23,6 +23,7 @@ extern "C" { #endif +#include #include #include @@ -30,7 +31,7 @@ extern "C" { /* If you're a user of SLV2, stop reading this file RIGHT NOW. * Unfortunately it needs to be exposed to allow inlining of some things that * really need to be inlined, but these are opaque types. Don't even think - * about writing code that depends on any information here.... + * about writing code that depends on any information here :) */ diff --git a/libslv2/slv2/query.h b/libslv2/slv2/query.h index 9bba6195..9f1c93d8 100644 --- a/libslv2/slv2/query.h +++ b/libslv2/slv2/query.h @@ -86,8 +86,11 @@ rasqal_query_results* slv2_plugin_run_query(const SLV2Plugin* p, const char* query_string); +size_t +slv2_query_get_num_results(rasqal_query_results* results, const char* var_name); + SLV2Property -slv2_query_get_results(rasqal_query_results* results); +slv2_query_get_results(rasqal_query_results* results, const char* var_name); /** Free an SLV2Property. */ void diff --git a/libslv2/src/plugin.c b/libslv2/src/plugin.c index a6b23445..a0240773 100644 --- a/libslv2/src/plugin.c +++ b/libslv2/src/plugin.c @@ -156,7 +156,7 @@ slv2_plugin_get_property(const SLV2Plugin* p, rasqal_query_results* results = slv2_plugin_run_query(p, query); - struct _Property* result = slv2_query_get_results(results); + SLV2Property result = slv2_query_get_results(results, "value"); rasqal_free_query_results(results); rasqal_finish(); @@ -169,8 +169,6 @@ slv2_plugin_get_property(const SLV2Plugin* p, uint32_t slv2_plugin_get_num_ports(const SLV2Plugin* p) { - uint32_t result = 0; - rasqal_init(); char* query = strjoin( @@ -179,12 +177,32 @@ slv2_plugin_get_num_ports(const SLV2Plugin* p) "} \n", NULL); rasqal_query_results* results = slv2_plugin_run_query(p, query); + const size_t result = slv2_query_get_num_results(results, "value"); - while (!rasqal_query_results_finished(results)) { - ++result; - rasqal_query_results_next(results); - } + rasqal_free_query_results(results); + rasqal_finish(); + free(query); + return result; +} + + +bool +slv2_plugin_has_latency(const SLV2Plugin* p) +{ + assert(p); + + rasqal_init(); + + char* query = + "SELECT DISTINCT ?value FROM data: WHERE { \n" + " plugin: lv2:port ?port . \n" + " ?port lv2:portHint lv2:reportsLatency . \n" + "}\n"; + + rasqal_query_results* results = slv2_plugin_run_query(p, query); + bool result = ( rasqal_query_results_get_bindings_count(results) > 0 ); + rasqal_free_query_results(results); rasqal_finish(); free(query); @@ -192,3 +210,34 @@ slv2_plugin_get_num_ports(const SLV2Plugin* p) return result; } +uint32_t +slv2_plugin_get_latency_port(const SLV2Plugin* p) +{ + assert(p); + + rasqal_init(); + + char* query = + "SELECT DISTINCT ?value FROM data: WHERE { \n" + " plugin: lv2:port ?port . \n" + " ?port lv2:portHint lv2:reportsLatency ; \n" + " lv2:index ?index . \n" + "}\n"; + + rasqal_query_results* results = slv2_plugin_run_query(p, query); + + struct _Property* result = slv2_query_get_results(results, "index"); + + // FIXME: need a sane error handling strategy + assert(result->num_values == 1); + char* endptr = 0; + uint32_t index = strtol(result->values[0], &endptr, 10); + // FIXME: check.. stuff.. + + rasqal_free_query_results(results); + rasqal_finish(); + free(query); + + return index; +} + diff --git a/libslv2/src/plugininstance.c b/libslv2/src/plugininstance.c index 6665fd72..f70866ac 100644 --- a/libslv2/src/plugininstance.c +++ b/libslv2/src/plugininstance.c @@ -85,7 +85,7 @@ slv2_plugin_instantiate(const SLV2Plugin* plugin, assert(result); assert(slv2_plugin_get_num_ports(plugin) > 0); - // Connect all ports to NULL (catches bugs) + // "Connect" all ports to NULL (catches bugs) for (uint32_t i=0; i < slv2_plugin_get_num_ports(plugin); ++i) result->descriptor->connect_port(result->lv2_handle, i, NULL); diff --git a/libslv2/src/port.c b/libslv2/src/port.c index db18ab89..111517d8 100644 --- a/libslv2/src/port.c +++ b/libslv2/src/port.c @@ -61,6 +61,8 @@ slv2_port_get_data_type(SLV2Plugin* p, assert(type->values); char* ret = type->values[0]; + type->values[0] = NULL; // prevent deletion + slv2_property_free(type); return ret; } @@ -87,7 +89,7 @@ slv2_port_get_property(SLV2Plugin* p, rasqal_query_results* results = slv2_plugin_run_query(p, query); - SLV2Property result = slv2_query_get_results(results); + SLV2Property result = slv2_query_get_results(results, "value"); rasqal_free_query_results(results); rasqal_finish(); @@ -107,8 +109,11 @@ slv2_port_get_symbol(SLV2Plugin* p, SLV2Property prop = slv2_port_get_property(p, index, "lv2:symbol"); - if (prop && prop->num_values == 1) - result = strdup(prop->values[0]); + if (prop && prop->num_values == 1) { + result = prop->values[0]; + prop->values[0] = NULL; // prevent deletion + } + slv2_property_free(prop); return result; diff --git a/libslv2/src/query.c b/libslv2/src/query.c index 05173311..8f3ef407 100644 --- a/libslv2/src/query.c +++ b/libslv2/src/query.c @@ -83,40 +83,57 @@ slv2_plugin_run_query(const SLV2Plugin* p, return results; } - -SLV2Property -slv2_query_get_results(rasqal_query_results* results) +size_t +slv2_query_get_num_results(rasqal_query_results* results, const char* var_name) { - struct _Property* result = NULL; - - if (rasqal_query_results_get_count(results) > 0) { - result = malloc(sizeof(struct _Property)); - result->num_values = 0; - result->values = NULL; - } - - while (!rasqal_query_results_finished(results)) { - - rasqal_literal* literal = - rasqal_query_results_get_binding_value_by_name(results, "value"); - assert(literal != NULL); - - // Add value on to the array. Yes, this is disgusting. - result->num_values++; - // FIXME LEAK: - result->values = realloc(result->values, result->num_values * sizeof(char*)); - result->values[result->num_values-1] = strdup(rasqal_literal_as_string(literal)); - - rasqal_query_results_next(results); + size_t result = 0; + + while (!rasqal_query_results_finished(results)) { + if (!strcmp(rasqal_query_results_get_binding_name(results, 0), var_name)) { + ++result; + } + rasqal_query_results_next(results); } return result; } +SLV2Property +slv2_query_get_results(rasqal_query_results* results, const char* var_name) +{ + struct _Property* result = NULL; + + if (rasqal_query_results_get_bindings_count(results) > 0) { + result = malloc(sizeof(struct _Property)); + result->num_values = 0; + result->values = NULL; + } + + while (!rasqal_query_results_finished(results)) { + + rasqal_literal* literal = + rasqal_query_results_get_binding_value_by_name(results, var_name); + assert(literal != NULL); + + // Add value on to the array, reallocing all the way. + // Yes, this is disgusting. Roughly as disgusting as the rasqal query + // results API. coincidentally. + result->num_values++; + result->values = realloc(result->values, result->num_values * sizeof(char*)); + result->values[result->num_values-1] = strdup(rasqal_literal_as_string(literal)); + + rasqal_query_results_next(results); + } + + return result; +} + void slv2_property_free(struct _Property* prop) { - //struct _Property* prop = (struct _Property*)property; + for (size_t i=0; i < prop->num_values; ++i) + free(prop->values[i]); + free(prop->values); free(prop); }