From 17ec1c5594772a89a5284449754b56ccb705ebe4 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Wed, 7 Feb 2007 01:45:53 +0000 Subject: Added lv2.ttl installation, lv2.ttl added as source by default to queries. Changed port API to work by referring to either index or symbol. Plugged some leaks. Added access to plugin/port hints/properties. Updated lv2.ttl. git-svn-id: http://svn.drobilla.net/lad/slv2@285 a436a847-0d15-0410-975c-d299462d15a1 --- configure.ac | 14 +++- data/Makefile.am | 3 +- data/lv2.ttl | 28 +++++--- hosts/lv2_jack_host.c | 15 ++-- hosts/lv2_simple_jack_host.c | 30 ++++---- slv2/Makefile.am | 1 + slv2/library.h | 53 ++++++++++++++ slv2/plugin.h | 61 +++++++++------- slv2/port.h | 72 ++++++++++++++----- slv2/query.h | 22 ++++-- slv2/slv2.h | 6 +- slv2/types.h | 27 +++++-- src/Makefile.am | 5 +- src/library.c | 44 ++++++++++++ src/plugin.c | 106 +++++++++++++-------------- src/pluginlist.c | 4 +- src/port.c | 167 +++++++++++++++++++++++++++++++------------ src/query.c | 91 ++++++++++++++--------- utils/Makefile.am | 6 +- utils/lv2_inspect.c | 106 +++++++++++++++++++++++++++ utils/lv2_list.c | 4 ++ 21 files changed, 644 insertions(+), 221 deletions(-) create mode 100644 slv2/library.h create mode 100644 src/library.c create mode 100644 utils/lv2_inspect.c diff --git a/configure.ac b/configure.ac index 2485744..bbc7590 100644 --- a/configure.ac +++ b/configure.ac @@ -81,6 +81,17 @@ if test "$build_ladspa2lv2" = "yes"; then fi AM_CONDITIONAL(BUILD_LADSPA2SLV2, [test "$build_ladspa2lv2" = "yes"]) + +# Check ontology install directory +AC_MSG_CHECKING([where to install lv2.ttl]) +AC_ARG_WITH(lv2-ttl-dir, + AS_HELP_STRING([--with-lv2-ttl-dir=DIR], + [directory where lv2.ttl should be installed ($datadir/lv2)]), + [lv2ttldir=$withval], [lv2ttldir=$datadir/lv2]) +AC_MSG_RESULT($lv2ttldir) +lv2ttlpath="$lv2ttldir/lv2.ttl" +AC_SUBST(lv2ttlpath) + # Write output files AC_CONFIG_FILES([Makefile]) AC_CONFIG_FILES([src/Makefile]) @@ -98,7 +109,8 @@ AC_MSG_RESULT([]) AC_MSG_RESULT([**********************************************************************]) AC_MSG_RESULT([SLV2 build configuration:]) AC_MSG_RESULT([]) -AC_MSG_RESULT([Building JACK clients: $build_jack]) +AC_MSG_RESULT([Building JACK clients: $build_jack]) +AC_MSG_RESULT([Ontology install location: $lv2ttlpath]) AC_MSG_RESULT([**********************************************************************]) AC_MSG_RESULT([]) diff --git a/data/Makefile.am b/data/Makefile.am index 1ebf317..65c8a66 100644 --- a/data/Makefile.am +++ b/data/Makefile.am @@ -1 +1,2 @@ -EXTRA_DIST = lv2.ttl +ontologydir = $(datadir)/lv2 +ontology_DATA = lv2.ttl diff --git a/data/lv2.ttl b/data/lv2.ttl index 9ba6974..6f02475 100644 --- a/data/lv2.ttl +++ b/data/lv2.ttl @@ -1,7 +1,7 @@ # RDF Schema for LV2 plugins # *** PROVISIONAL *** # -# Revision 2007-01-03 +# Revision 2007-02-06 # # This document describes the classes and properties that are defined by the # core LV2 specification. See for more information. @@ -153,6 +153,17 @@ Plugins will write values to this array during their run method. +################################## +# Optional Plugin RDF:Properties # +################################## + +:documentation a rdf:Property ; + rdfs:domain :Plugin ; + rdfs:label "documentation" ; + rdfs:comment "Relates a Plugin to some text/audio/video documentation either online or included with the plugin package" . + + + ################################# # Mandatory Port RDF:Properties # ################################# @@ -228,7 +239,7 @@ minimum, and maximum), though future extensions may define more. :ScalePoint a rdfs:Class ; rdfs:subClassOf :Point ; - rdfs:comment "A single :Float Point (for control inputs)" . + rdfs:comment "A single :float Point (for control inputs)" . :scalePoint a rdf:Property ; rdfs:domain :Port ; @@ -250,7 +261,7 @@ information available. rdfs:comment """ A hint to the host for the minimum useful value that the port will use. This is a "soft" limit - the plugin is required to gracefully accept all -values in the range of :Float. +values in the range of :float. """ . :maximum a rdf:Property ; @@ -259,7 +270,7 @@ values in the range of :Float. rdfs:comment """ A hint to the host for the maximum useful value that the port will use. This is a "soft" limit - the plugin is required to gracefully accept all -values in the range of :Float. +values in the range of :float. """ . @@ -268,8 +279,8 @@ values in the range of :Float. # Data Type # ############# -:Float a rdfs:DataType ; - rdfs:label "32-bit Floating Point" ; +:float a :DataType ; + rdfs:label "32-bit floating point" ; rdfs:comment """ Value conforming to the 32bit IEEE-754 floating point specification.""". @@ -340,11 +351,6 @@ plugin can still function correctly, it is NOT a Property, it is a Hint. rdfs:label "hint" ; rdfs:comment "Relates Ports to PortProperties." . -:documentation a rdf:Property ; - rdfs:domain :Plugin ; - rdfs:label "documentation" ; - rdfs:comment "Relates a Plugin to some text/audio/video documentation either online or included with the plugin package" . - ############### diff --git a/hosts/lv2_jack_host.c b/hosts/lv2_jack_host.c index e5e51a3..03d57d9 100644 --- a/hosts/lv2_jack_host.c +++ b/hosts/lv2_jack_host.c @@ -35,6 +35,7 @@ struct Port { enum Direction { INPUT, OUTPUT} direction; enum Type { UNKNOWN, FLOAT, MIDI } type; + SLV2PortID id; jack_port_t* jack_port; /**< For audio and MIDI ports, otherwise NULL */ float control; /**< For control ports, otherwise 0.0f */ LV2_MIDI* midi_buffer; /**< For midi ports, otherwise NULL */ @@ -65,6 +66,8 @@ main(int argc, char** argv) host.num_ports = 0; host.ports = NULL; + slv2_init(); + /* Find all installed plugins */ SLV2List plugins = slv2_list_new(); slv2_list_load_all(plugins); @@ -143,6 +146,8 @@ main(int argc, char** argv) } jack_client_close(host.jack_client); + slv2_finish(); + return 0; } @@ -170,6 +175,7 @@ create_port(struct JackHost* host, //struct Port* port = (Port*)malloc(sizeof(Port)); struct Port* const port = &host->ports[port_index]; + port->id = slv2_port_by_index(port_index); port->type = UNKNOWN; port->jack_port = NULL; port->control = 0.0f; @@ -177,17 +183,18 @@ create_port(struct JackHost* host, slv2_instance_connect_port(host->instance, port_index, NULL); - char* type_str = slv2_port_get_data_type(host->plugin, port_index); + char* type_str = slv2_port_get_data_type(host->plugin, port->id); + if (!strcmp(type_str, SLV2_DATA_TYPE_FLOAT)) port->type = FLOAT; else if (!strcmp(type_str, SLV2_DATA_TYPE_MIDI)) port->type = MIDI; /* Get the port symbol (label) for console printing */ - char* symbol = slv2_port_get_symbol(host->plugin, port_index); + char* symbol = slv2_port_get_symbol(host->plugin, port->id); /* Get the 'class' (not data type) of the port (control input, audio output, etc) */ - enum SLV2PortClass class = slv2_port_get_class(host->plugin, port_index); + enum SLV2PortClass class = slv2_port_get_class(host->plugin, port->id); if (port->type == FLOAT) { @@ -195,7 +202,7 @@ create_port(struct JackHost* host, switch (class) { case SLV2_CONTROL_RATE_INPUT: port->direction = INPUT; - port->control = slv2_port_get_default_value(host->plugin, port_index); + port->control = slv2_port_get_default_value(host->plugin, port->id); slv2_instance_connect_port(host->instance, port_index, &port->control); printf("Set %s to %f\n", symbol, host->ports[port_index].control); break; diff --git a/hosts/lv2_simple_jack_host.c b/hosts/lv2_simple_jack_host.c index 4b7493f..ef386b7 100644 --- a/hosts/lv2_simple_jack_host.c +++ b/hosts/lv2_simple_jack_host.c @@ -49,6 +49,8 @@ main(int argc, char** argv) host.jack_ports = NULL; host.controls = NULL; + slv2_init(); + /* Find all installed plugins */ SLV2List plugins = slv2_list_new(); slv2_list_load_all(plugins); @@ -125,6 +127,8 @@ main(int argc, char** argv) } jack_client_close(host.jack_client); + slv2_finish(); + return 0; } @@ -147,40 +151,42 @@ die(const char* msg) */ void create_port(struct JackHost* host, - uint32_t port_index) + uint32_t index) { + SLV2PortID id = slv2_port_by_index(index); + /* Make sure this is a float port */ - char* type = slv2_port_get_data_type(host->plugin, port_index); + char* type = slv2_port_get_data_type(host->plugin, id); if (strcmp(type, SLV2_DATA_TYPE_FLOAT)) die("Unrecognized data type, aborting."); free(type); /* Get the port symbol (label) for console printing */ - char* symbol = slv2_port_get_symbol(host->plugin, port_index); + char* symbol = slv2_port_get_symbol(host->plugin, id); /* Initialize the port array elements */ - host->jack_ports[port_index] = NULL; - host->controls[port_index] = 0.0f; + host->jack_ports[index] = NULL; + host->controls[index] = 0.0f; /* Get the 'class' of the port (control input, audio output, etc) */ - enum SLV2PortClass class = slv2_port_get_class(host->plugin, port_index); + enum SLV2PortClass class = slv2_port_get_class(host->plugin, id); /* Connect the port based on it's 'class' */ switch (class) { case SLV2_CONTROL_RATE_INPUT: - host->controls[port_index] = slv2_port_get_default_value(host->plugin, port_index); - slv2_instance_connect_port(host->instance, port_index, &host->controls[port_index]); - printf("Set %s to %f\n", symbol, host->controls[port_index]); + host->controls[index] = slv2_port_get_default_value(host->plugin, id); + slv2_instance_connect_port(host->instance, index, &host->controls[index]); + printf("Set %s to %f\n", symbol, host->controls[index]); break; case SLV2_CONTROL_RATE_OUTPUT: - slv2_instance_connect_port(host->instance, port_index, &host->controls[port_index]); + slv2_instance_connect_port(host->instance, index, &host->controls[index]); break; case SLV2_AUDIO_RATE_INPUT: - host->jack_ports[port_index] = jack_port_register(host->jack_client, + host->jack_ports[index] = jack_port_register(host->jack_client, symbol, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); break; case SLV2_AUDIO_RATE_OUTPUT: - host->jack_ports[port_index] = jack_port_register(host->jack_client, + host->jack_ports[index] = jack_port_register(host->jack_client, symbol, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); break; default: diff --git a/slv2/Makefile.am b/slv2/Makefile.am index 2fcb5b7..5fba079 100644 --- a/slv2/Makefile.am +++ b/slv2/Makefile.am @@ -5,6 +5,7 @@ slv2include_HEADERS = \ types.h \ private_types.h \ slv2.h \ + library.h \ plugin.h \ query.h \ port.h \ diff --git a/slv2/library.h b/slv2/library.h new file mode 100644 index 0000000..9c94139 --- /dev/null +++ b/slv2/library.h @@ -0,0 +1,53 @@ +/* SLV2 + * Copyright (C) 2007 Dave Robillard + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef __SLV2_LIBRARY_H +#define __SLV2_LIBRARY_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/** Initialize SLV2. + * + * This MUST be called before calling any other SLV2 functions, or fatal + * errors will likely occur. + */ +void +slv2_init(); + + +/** Finialize SLV2. + * + * Frees any resources allocated by slv2_init(). + */ +void +slv2_finish(); + + +/** The URI of the lv2.ttl file. + */ +extern raptor_uri* slv2_ontology_uri; + + +#ifdef __cplusplus +} +#endif + +#endif /* __SLV2_LIBRARY_H */ diff --git a/slv2/plugin.h b/slv2/plugin.h index 839137f..d646504 100644 --- a/slv2/plugin.h +++ b/slv2/plugin.h @@ -136,21 +136,45 @@ char* slv2_plugin_get_name(const SLV2Plugin* plugin); -/** Request some property of the plugin. +/** Request some arbitrary RDF object of the plugin. * * May return NULL if the property was not found (ie is not defined in the - * data file). + * data file), or if object is not sensibly represented as an SLV2Value + * (e.g. blank nodes). * - * Return value must be free()'d by caller. + * Return value must be freed by caller with slv2_value_free. * - * Note that some properties may have multiple values. If the property is a + * Note that this may return multiple values. If the property is a * string with multiple languages defined, the translation according to * $LANG will be returned if it is set. Otherwise all values will be * returned. */ -SLV2Property -slv2_plugin_get_property(const SLV2Plugin* p, - const char* property); +SLV2Value +slv2_plugin_get_value(const SLV2Plugin* p, + const char* predicate); + + +/** Get the LV2 Properties of a plugin. + * + * LV2 Properties are mandatory. Hosts MUST NOT use a plugin if they do not + * understand all the LV2 Properties associated with that plugin (if this is + * not what you want, see slv2_plugin_get_hints). + * + * Return value must be freed by caller with slv2_value_free. + */ +SLV2Value +slv2_plugin_get_properties(const SLV2Plugin* p); + + +/** Get the LV2 Hints of a plugin. + * + * LV2 Hints are suggestions that may be useful for a host. LV2 Hints may be + * ignored and the plugin will still function correctly. + * + * Return value must be freed by caller with slv2_value_free. + */ +SLV2Value +slv2_plugin_get_hints(const SLV2Plugin* p); /** Get the number of ports on this plugin. @@ -179,29 +203,12 @@ slv2_plugin_has_latency(const SLV2Plugin* p); uint32_t slv2_plugin_get_latency_port(const SLV2Plugin* p); -#if 0 -/** Return whether or not a plugin supports the given host feature / extension. - * - * This will return true for both supported and required host features. - */ -bool -slv2_plugin_supports_feature(const SLV2Plugin* p, const char* feature_uri); - - -/** Return whether or not a plugin requires the given host feature / extension. - * - * If a plugin requires a feature, that feature MUST be passed to the plugin's - * instantiate method or the plugin will fail to instantiate. - */ -bool -slv2_plugin_requires_features(const SLV2Plugin* p, const char* feature_uri); -#endif /** Get a plugin's supported host features / extensions. * * This returns a list of all supported features (both required and optional). */ -SLV2Property +SLV2Value slv2_plugin_get_supported_features(const SLV2Plugin* p); @@ -210,7 +217,7 @@ slv2_plugin_get_supported_features(const SLV2Plugin* p); * All feature URI's returned by this call MUST be passed to the plugin's * instantiate method for the plugin to instantiate successfully. */ -SLV2Property +SLV2Value slv2_plugin_get_required_features(const SLV2Plugin* p); @@ -220,7 +227,7 @@ slv2_plugin_get_required_features(const SLV2Plugin* p); * instantiate method, those features will be used by the function, otherwise * the plugin will act as it would if it did not support that feature at all. */ -SLV2Property +SLV2Value slv2_plugin_get_optional_features(const SLV2Plugin* p); diff --git a/slv2/port.h b/slv2/port.h index 4e352a8..8e5b006 100644 --- a/slv2/port.h +++ b/slv2/port.h @@ -31,14 +31,38 @@ extern "C" { */ -/** Get a property of a port, by port index. - * - * Return value must be freed by caller with slv2_property_free. +/** Create an ID to reference a port by index. */ -SLV2Property -slv2_port_get_property(SLV2Plugin* plugin, - uint32_t index, - const char* property); +SLV2PortID +slv2_port_by_index(uint32_t index); + + +/** Create an ID to reference a port by symbol. + */ +SLV2PortID +slv2_port_by_symbol(const char* symbol); + + +/** Port equivalent to slv2_plugin_get_value. + */ +SLV2Value +slv2_port_get_value(SLV2Plugin* plugin, + SLV2PortID id, + const char* property); + + +/** Port equivalent to slv2_plugin_get_properties. + */ +SLV2Value +slv2_port_get_properties(const SLV2Plugin* p, + SLV2PortID id); + + +/** Port equivalent to slv2_plugin_get_hints. + */ +SLV2Value +slv2_port_get_hints(const SLV2Plugin* p, + SLV2PortID id); /** Get the symbol of a port given the index. @@ -49,15 +73,25 @@ slv2_port_get_property(SLV2Plugin* plugin, * \return NULL when index is out of range */ char* -slv2_port_get_symbol(SLV2Plugin* plugin, - uint32_t index); +slv2_port_get_symbol(SLV2Plugin* plugin, + SLV2PortID id); + +/** Get the name of a port. + * + * This is guaranteed to return the untranslated name (the doap:name in the + * data file without a language tag). Returned value must be free()'d by + * the caller. + */ +char* +slv2_port_get_name(SLV2Plugin* plugin, + SLV2PortID id); /** Get the class (direction and rate) of a port. */ enum SLV2PortClass -slv2_port_get_class(SLV2Plugin* plugin, - uint32_t index); +slv2_port_get_class(SLV2Plugin* plugin, + SLV2PortID id); /** Get the data type of a port (as a URI). @@ -68,8 +102,8 @@ slv2_port_get_class(SLV2Plugin* plugin, * Returned string must be free()'d by caller. */ char* -slv2_port_get_data_type(SLV2Plugin* plugin, - uint32_t index); +slv2_port_get_data_type(SLV2Plugin* plugin, + SLV2PortID id); /** Get the default value of a port. @@ -77,8 +111,8 @@ slv2_port_get_data_type(SLV2Plugin* plugin, * Only valid for ports with a data type of lv2:float. */ float -slv2_port_get_default_value(SLV2Plugin* plugin, - uint32_t index); +slv2_port_get_default_value(SLV2Plugin* plugin, + SLV2PortID id); /** Get the minimum value of a port. @@ -86,8 +120,8 @@ slv2_port_get_default_value(SLV2Plugin* plugin, * Only valid for ports with a data type of lv2:float. */ float -slv2_port_get_minimum_value(SLV2Plugin* plugin, - uint32_t index); +slv2_port_get_minimum_value(SLV2Plugin* plugin, + SLV2PortID id); /** Get the maximum value of a port. @@ -95,8 +129,8 @@ slv2_port_get_minimum_value(SLV2Plugin* plugin, * Only valid for ports with a data type of lv2:float. */ float -slv2_port_get_maximum_value(SLV2Plugin* plugin, - uint32_t index); +slv2_port_get_maximum_value(SLV2Plugin* plugin, + SLV2PortID id); /** @} */ diff --git a/slv2/query.h b/slv2/query.h index 28df4a6..3faba15 100644 --- a/slv2/query.h +++ b/slv2/query.h @@ -27,6 +27,10 @@ extern "C" { #include "plugin.h" #include "types.h" + +// FIXME: much of this should not be exposed + + /** \defgroup query SPARQL query helpers * * This part is in progress, incomplete, a random mishmash of crap that @@ -74,6 +78,16 @@ char* slv2_query_lang_filter(const char* variable); +rasqal_query_results* +slv2_plugin_query(SLV2Plugin* plugin, + const char* sparql_str); + +SLV2Value +slv2_plugin_simple_query(SLV2Plugin* plugin, + const char* sparql_str, + const char* variable); + +#if 0 /** Run a SPARQL query on a plugin's data file and return variable matches. * * Header from slv2query_header will be prepended to passed query string (so @@ -82,12 +96,11 @@ slv2_query_lang_filter(const char* variable); * * Returned is a list of all matches for the query variable \a var_name. */ -SLV2Property +SLV2Value slv2_query_get_results(const SLV2Plugin* p, const char* query_string, const char* var_name); - /** Run a SPARQL query on a plugin's data file and just count the matches. * * Header from slv2query_header will be prepended to passed query string (so @@ -99,12 +112,9 @@ slv2_query_get_results(const SLV2Plugin* p, size_t slv2_query_count_results(const SLV2Plugin* p, const char* query_string); +#endif -/** Free an SLV2Property. */ -void -slv2_property_free(SLV2Property); - /** @} */ diff --git a/slv2/slv2.h b/slv2/slv2.h index b3c9f63..44744c9 100644 --- a/slv2/slv2.h +++ b/slv2/slv2.h @@ -22,13 +22,17 @@ #ifdef __cplusplus extern "C" { #endif - + +#include + +#include #include #include #include #include #include + #ifdef __cplusplus } #endif diff --git a/slv2/types.h b/slv2/types.h index ca695b4..19f1f2b 100644 --- a/slv2/types.h +++ b/slv2/types.h @@ -19,23 +19,42 @@ #ifndef __SLV2_TYPES_H__ #define __SLV2_TYPES_H__ +#include +#include +#include + #ifdef __cplusplus extern "C" { #endif -#include - /* A property, resulting from a query. * * Note that properties may have many values. */ -struct _Property { +struct _Value { size_t num_values; char** values; }; -typedef struct _Property* SLV2Property; +typedef struct _Value* SLV2Value; + + +/** Free an SLV2Value. */ +void +slv2_value_free(SLV2Value); + + +/** Port ID type, to allow passing either symbol or index + * to port related functions. + */ +struct _PortID { + bool is_index; /**< Otherwise, symbol */ + uint32_t index; + const char* symbol; +}; + +typedef struct _PortID SLV2PortID; /** Class (direction and rate) of a port */ diff --git a/src/Makefile.am b/src/Makefile.am index 5f6cea2..4f81d9a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,4 +1,4 @@ -AM_CFLAGS = -std=c99 -I$(top_srcdir)/include -I$(top_srcdir) @RASQAL_CFLAGS@ -DLIBSLV2_SOURCE +AM_CFLAGS = -std=c99 -I$(top_srcdir)/include -I$(top_srcdir) @RASQAL_CFLAGS@ -DLIBSLV2_SOURCE -DLV2_TTL_PATH=\"@lv2ttlpath@\" AM_LDFLAGS = `pkg-config --libs rasqal` lib_LTLIBRARIES = libslv2.la @@ -11,4 +11,5 @@ libslv2_la_SOURCES = \ port.c \ pluginlist.c \ util.c \ - plugininstance.c + plugininstance.c \ + library.c diff --git a/src/library.c b/src/library.c new file mode 100644 index 0000000..591218d --- /dev/null +++ b/src/library.c @@ -0,0 +1,44 @@ +/* SLV2 + * Copyright (C) 2007 Dave Robillard + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" +#include + + +raptor_uri* slv2_ontology_uri = NULL; + + +void +slv2_init() +{ + rasqal_init(); + + slv2_ontology_uri = raptor_new_uri((const unsigned char*) + "file://" LV2_TTL_PATH); +} + + +void +slv2_finish() +{ + rasqal_finish(); + + raptor_free_uri(slv2_ontology_uri); + slv2_ontology_uri = NULL; +} + diff --git a/src/plugin.c b/src/plugin.c index 0d9b26b..970b82f 100644 --- a/src/plugin.c +++ b/src/plugin.c @@ -93,7 +93,7 @@ slv2_plugin_verify(const SLV2Plugin* plugin) size_t num_values = 0; - struct _Property* prop = slv2_plugin_get_property(plugin, "doap:name"); + struct _Value* prop = slv2_plugin_get_value(plugin, "doap:name"); if (prop) { num_values = prop->num_values; free(prop); @@ -101,7 +101,7 @@ slv2_plugin_verify(const SLV2Plugin* plugin) if (num_values < 1) return false; /* - prop = slv2_plugin_get_property(plugin, "doap:license"); + prop = slv2_plugin_get_value(plugin, "doap:license"); num_values = prop->num_values; free(prop); if (num_values < 1) @@ -116,7 +116,7 @@ slv2_plugin_get_name(const SLV2Plugin* plugin) { // FIXME: leak char* result = NULL; - struct _Property* prop = slv2_plugin_get_property(plugin, "doap:name"); + struct _Value* prop = slv2_plugin_get_value(plugin, "doap:name"); // FIXME: guaranteed to be the untagged one? if (prop && prop->num_values >= 1) @@ -126,11 +126,11 @@ slv2_plugin_get_name(const SLV2Plugin* plugin) } -SLV2Property -slv2_plugin_get_property(const SLV2Plugin* p, - const char* property) +SLV2Value +slv2_plugin_get_value(const SLV2Plugin* p, + const char* predicate) { - assert(property); + assert(predicate); /* char* header = slv2_query_header(p); @@ -147,11 +147,11 @@ slv2_plugin_get_property(const SLV2Plugin* p, free(lang_filter);*/ char* query = strjoin( - "SELECT DISTINCT ?value FROM data: WHERE { \n" - "plugin: ", property, " ?value . \n" - "} \n", NULL); + "SELECT DISTINCT ?value FROM data: WHERE {\n" + "plugin: ", predicate, " ?value .\n" + "}\n", NULL); - SLV2Property result = slv2_query_get_results(p, query, "value"); + SLV2Value result = slv2_plugin_simple_query(p, query, "value"); free(query); @@ -159,19 +159,33 @@ slv2_plugin_get_property(const SLV2Plugin* p, } +SLV2Value +slv2_plugin_get_properties(const SLV2Plugin* p) +{ + return slv2_plugin_get_value(p, "lv2:pluginProperty"); +} + + +SLV2Value +slv2_plugin_get_hints(const SLV2Plugin* p) +{ + return slv2_plugin_get_value(p, "lv2:pluginHint"); +} + + uint32_t slv2_plugin_get_num_ports(const SLV2Plugin* p) { const char* const query = - "SELECT DISTINCT ?value FROM data: WHERE { \n" - "plugin: lv2:port ?value . \n" - "} \n"; + "SELECT DISTINCT ?value FROM data: WHERE {\n" + "plugin: lv2:port ?value .\n" + "}\n"; - SLV2Property results = slv2_query_get_results(p, query, "value"); + SLV2Value results = slv2_plugin_simple_query(p, query, "value"); size_t count = results->num_values; - slv2_property_free(results); + slv2_value_free(results); return count; } @@ -181,16 +195,16 @@ bool slv2_plugin_has_latency(const SLV2Plugin* p) { const char* const query = - "SELECT DISTINCT ?value FROM data: WHERE { \n" - " plugin: lv2:port ?port . \n" - " ?port lv2:portHint lv2:reportsLatency . \n" + "SELECT DISTINCT ?port FROM data: WHERE {\n" + " plugin: lv2:port ?port .\n" + " ?port lv2:portHint lv2:reportsLatency .\n" "}\n"; - SLV2Property results = slv2_query_get_results(p, query, "port"); + SLV2Value results = slv2_plugin_simple_query(p, query, "port"); bool exists = (results->num_values > 0); - slv2_property_free(results); + slv2_value_free(results); return exists; } @@ -200,13 +214,13 @@ uint32_t slv2_plugin_get_latency_port(const SLV2Plugin* p) { const char* const query = - "SELECT DISTINCT ?value FROM data: WHERE { \n" - " plugin: lv2:port ?port . \n" - " ?port lv2:portHint lv2:reportsLatency ; \n" - " lv2:index ?index . \n" + "SELECT DISTINCT ?value FROM data: WHERE {\n" + " plugin: lv2:port ?port .\n" + " ?port lv2:portHint lv2:reportsLatency ;\n" + " lv2:index ?index .\n" "}\n"; - SLV2Property result = slv2_query_get_results(p, query, "index"); + SLV2Value result = slv2_plugin_simple_query(p, query, "index"); // FIXME: need a sane error handling strategy assert(result->num_values == 1); @@ -217,58 +231,46 @@ slv2_plugin_get_latency_port(const SLV2Plugin* p) return index; } -/* -bool -slv2_plugin_supports_feature(const SLV2Plugin* p, const char* feature_uri) -{ -} - - -bool -slv2_plugin_requires_feature(const SLV2Plugin* p, const char* feature_uri) -{ -} -*/ -SLV2Property +SLV2Value slv2_plugin_get_supported_features(const SLV2Plugin* p) { const char* const query = - "SELECT DISTINCT ?feature FROM data: WHERE { \n" - " { plugin: lv2:optionalHostFeature ?feature } \n" - " UNION \n" - " { plugin: lv2:requiredHostFeature ?feature } \n" + "SELECT DISTINCT ?feature FROM data: WHERE {\n" + " { plugin: lv2:optionalHostFeature ?feature }\n" + " UNION\n" + " { plugin: lv2:requiredHostFeature ?feature }\n" "}\n"; - SLV2Property result = slv2_query_get_results(p, query, "feature"); + SLV2Value result = slv2_plugin_simple_query(p, query, "feature"); return result; } -SLV2Property +SLV2Value slv2_plugin_get_optional_features(const SLV2Plugin* p) { const char* const query = - "SELECT DISTINCT ?feature FROM data: WHERE { \n" - " plugin: lv2:optionalHostFeature ?feature . \n" + "SELECT DISTINCT ?feature FROM data: WHERE {\n" + " plugin: lv2:optionalHostFeature ?feature .\n" "}\n"; - SLV2Property result = slv2_query_get_results(p, query, "feature"); + SLV2Value result = slv2_plugin_simple_query(p, query, "feature"); return result; } -SLV2Property +SLV2Value slv2_plugin_get_required_features(const SLV2Plugin* p) { const char* const query = - "SELECT DISTINCT ?feature FROM data: WHERE { \n" - " plugin: lv2:requiredHostFeature ?feature . \n" + "SELECT DISTINCT ?feature FROM data: WHERE {\n" + " plugin: lv2:requiredHostFeature ?feature .\n" "}\n"; - SLV2Property result = slv2_query_get_results(p, query, "feature"); + SLV2Value result = slv2_plugin_simple_query(p, query, "feature"); return result; } diff --git a/src/pluginlist.c b/src/pluginlist.c index 75b506a..3c8e409 100644 --- a/src/pluginlist.c +++ b/src/pluginlist.c @@ -85,10 +85,9 @@ slv2_list_load_bundle(SLV2List list, else strcat((char*)manifest_url, "/manifest.ttl"); - rasqal_init(); rasqal_query_results *results; raptor_uri *base_url = raptor_new_uri(manifest_url); - rasqal_query *rq = rasqal_new_query("sparql", (unsigned char*)base_url); + rasqal_query *rq = rasqal_new_query("sparql", NULL); char* query_string = "PREFIX rdfs: \n" @@ -146,7 +145,6 @@ slv2_list_load_bundle(SLV2List list, //rasqal_free_query(rq); // FIXME: crashes? leak? raptor_free_uri(base_url); } - rasqal_finish(); free(manifest_url); } diff --git a/src/port.c b/src/port.c index d014f60..eb4ba48 100644 --- a/src/port.c +++ b/src/port.c @@ -20,42 +20,70 @@ #include #include #include +#include #include #include #include #include "util.h" + +SLV2PortID +slv2_port_by_index(uint32_t index) +{ + SLV2PortID ret; + ret.is_index = true; + ret.index = index; + ret.symbol = NULL; + return ret; +} + + +SLV2PortID +slv2_port_by_symbol(const char* symbol) +{ + SLV2PortID ret; + ret.is_index = false; + ret.index = UINT_MAX; + ret.symbol = symbol; + return ret; +} + + enum SLV2PortClass slv2_port_get_class(SLV2Plugin* p, - uint32_t index) + SLV2PortID id) { - struct _Property* class = slv2_port_get_property(p, index, "rdf:type"); + struct _Value* class = slv2_port_get_value(p, id, "rdf:type"); assert(class); - assert(class->num_values == 1); + assert(class->num_values > 0); assert(class->values); - - // FIXME FIXME FIXME: leak + + enum SLV2PortClass ret; if (!strcmp((char*)class->values[0], "http://lv2plug.in/ontology#ControlRateInputPort")) - return SLV2_CONTROL_RATE_INPUT; + ret = SLV2_CONTROL_RATE_INPUT; else if (!strcmp((char*)class->values[0], "http://lv2plug.in/ontology#ControlRateOutputPort")) - return SLV2_CONTROL_RATE_OUTPUT; + ret = SLV2_CONTROL_RATE_OUTPUT; else if (!strcmp((char*)class->values[0], "http://lv2plug.in/ontology#AudioRateInputPort")) - return SLV2_AUDIO_RATE_INPUT; + ret = SLV2_AUDIO_RATE_INPUT; else if (!strcmp((char*)class->values[0], "http://lv2plug.in/ontology#AudioRateOutputPort")) - return SLV2_AUDIO_RATE_OUTPUT; + ret = SLV2_AUDIO_RATE_OUTPUT; else { fprintf(stderr, "Unknown port class: %s\n", class->values[0]); - return SLV2_UNKNOWN_PORT_CLASS; + ret = SLV2_UNKNOWN_PORT_CLASS; } + + slv2_value_free(class); + + return ret; } char* slv2_port_get_data_type(SLV2Plugin* p, - uint32_t index) + SLV2PortID id) { - SLV2Property type = slv2_port_get_property(p, index, "lv2:datatype"); + SLV2Value type = slv2_port_get_value(p, id, "lv2:datatype"); assert(type); assert(type->num_values == 1); assert(type->values); @@ -63,30 +91,45 @@ slv2_port_get_data_type(SLV2Plugin* p, char* ret = type->values[0]; type->values[0] = NULL; // prevent deletion - slv2_property_free(type); + slv2_value_free(type); return ret; } -SLV2Property -slv2_port_get_property(SLV2Plugin* p, - uint32_t index, - const char* property) +SLV2Value +slv2_port_get_value(SLV2Plugin* p, + SLV2PortID id, + const char* property) { assert(property); - char index_str[16]; - snprintf(index_str, (size_t)16, "%u", index); - - char* query = strjoin( - "SELECT DISTINCT ?value FROM data: WHERE { \n" - "plugin: lv2:port ?port . \n" - "?port lv2:index ", index_str, " . \n" - "?port ", property, " ?value . \n}\n", NULL); + SLV2Value result = NULL; - SLV2Property result = slv2_query_get_results(p, query, "value"); - - free(query); + if (id.is_index) { + char index_str[16]; + snprintf(index_str, (size_t)16, "%u", id.index); + + char* query = strjoin( + "SELECT DISTINCT ?value FROM data: WHERE { \n" + "plugin: lv2:port ?port . \n" + "?port lv2:index ", index_str, " ;\n\t", + property, " ?value . \n}\n", NULL); + + result = slv2_plugin_simple_query(p, query, "value"); + + free(query); + } else { + + char* query = strjoin( + "SELECT DISTINCT ?value FROM data: WHERE { \n" + "plugin: lv2:port ?port . \n" + "?port lv2:symbol ", id.symbol, " ;\n\t", + property, " ?value . \n}\n", NULL); + + result = slv2_plugin_simple_query(p, query, "value"); + + free(query); + } return result; } @@ -94,19 +137,39 @@ slv2_port_get_property(SLV2Plugin* p, char* slv2_port_get_symbol(SLV2Plugin* p, - uint32_t index) + SLV2PortID id) { char* result = NULL; - SLV2Property prop - = slv2_port_get_property(p, index, "lv2:symbol"); + SLV2Value prop + = slv2_port_get_value(p, id, "lv2:symbol"); if (prop && prop->num_values == 1) { result = prop->values[0]; prop->values[0] = NULL; // prevent deletion } - slv2_property_free(prop); + slv2_value_free(prop); + + return result; +} + + +char* +slv2_port_get_name(SLV2Plugin* p, + SLV2PortID id) +{ + char* result = NULL; + + SLV2Value prop + = slv2_port_get_value(p, id, "lv2:name"); + + if (prop && prop->num_values == 1) { + result = prop->values[0]; + prop->values[0] = NULL; // prevent deletion + } + + slv2_value_free(prop); return result; } @@ -114,19 +177,19 @@ slv2_port_get_symbol(SLV2Plugin* p, float slv2_port_get_default_value(SLV2Plugin* p, - uint32_t index) + SLV2PortID id) { // FIXME: do casting properly in the SPARQL query float result = 0.0f; - SLV2Property prop - = slv2_port_get_property(p, index, "lv2:default"); + SLV2Value prop + = slv2_port_get_value(p, id, "lv2:default"); if (prop && prop->num_values == 1) result = atof((char*)prop->values[0]); - slv2_property_free(prop); + slv2_value_free(prop); return result; } @@ -134,19 +197,19 @@ slv2_port_get_default_value(SLV2Plugin* p, float slv2_port_get_minimum_value(SLV2Plugin* p, - uint32_t index) + SLV2PortID id) { // FIXME: do casting properly in the SPARQL query float result = 0.0f; - SLV2Property prop - = slv2_port_get_property(p, index, "lv2:minimum"); + SLV2Value prop + = slv2_port_get_value(p, id, "lv2:minimum"); if (prop && prop->num_values == 1) result = atof((char*)prop->values[0]); - slv2_property_free(prop); + slv2_value_free(prop); return result; } @@ -154,20 +217,36 @@ slv2_port_get_minimum_value(SLV2Plugin* p, float slv2_port_get_maximum_value(SLV2Plugin* p, - uint32_t index) + SLV2PortID id) { // FIXME: do casting properly in the SPARQL query float result = 0.0f; - SLV2Property prop - = slv2_port_get_property(p, index, "lv2:maximum"); + SLV2Value prop + = slv2_port_get_value(p, id, "lv2:maximum"); if (prop && prop->num_values == 1) result = atof((char*)prop->values[0]); - slv2_property_free(prop); + slv2_value_free(prop); return result; } + +SLV2Value +slv2_port_get_properties(const SLV2Plugin* p, + SLV2PortID id) +{ + return slv2_port_get_value(p, id, "lv2:portProperty"); +} + + +SLV2Value +slv2_port_get_hints(const SLV2Plugin* p, + SLV2PortID id) +{ + return slv2_port_get_value(p, id, "lv2:portHint"); +} + diff --git a/src/query.c b/src/query.c index a6eda89..6149531 100644 --- a/src/query.c +++ b/src/query.c @@ -21,6 +21,7 @@ #include #include #include +#include char* @@ -30,12 +31,12 @@ slv2_query_header(const SLV2Plugin* p) const char* const data_file_url = slv2_plugin_get_data_url(p); char* query_string = strjoin( - "PREFIX rdf: \n" - "PREFIX rdfs: \n" - "PREFIX doap: \n" - "PREFIX lv2: \n" - "PREFIX plugin: <", plugin_uri, "> \n", - "PREFIX data: <", data_file_url, "> \n\n", NULL); + "PREFIX rdf: \n" + "PREFIX rdfs: \n" + "PREFIX doap: \n" + "PREFIX lv2: \n" + "PREFIX plugin: <", plugin_uri, ">\n", + "PREFIX data: <", data_file_url, ">\n\n", NULL); return query_string; } @@ -58,13 +59,14 @@ slv2_query_lang_filter(const char* variable) } -SLV2Property -slv2_query_get_variable_bindings(rasqal_query_results* results, const char* var_name) +SLV2Value +slv2_query_get_variable_bindings(rasqal_query_results* results, + const char* variable) { - struct _Property* result = NULL; + struct _Value* result = NULL; if (rasqal_query_results_get_bindings_count(results) > 0) { - result = malloc(sizeof(struct _Property)); + result = malloc(sizeof(struct _Value)); result->num_values = 0; result->values = NULL; } @@ -72,7 +74,7 @@ slv2_query_get_variable_bindings(rasqal_query_results* results, const char* var_ while (!rasqal_query_results_finished(results)) { rasqal_literal* literal = - rasqal_query_results_get_binding_value_by_name(results, (const unsigned char*)var_name); + rasqal_query_results_get_binding_value_by_name(results, (const unsigned char*)variable); assert(literal != NULL); // Add value on to the array, reallocing all the way. @@ -102,41 +104,60 @@ slv2_query_count_variable_bindings(rasqal_query_results* results) return count; } - -SLV2Property -slv2_query_get_results(const SLV2Plugin* p, - const char* query, - const char* var_name) + +rasqal_query_results* +slv2_plugin_query(SLV2Plugin* plugin, + const char* sparql_str) { - char* header = slv2_query_header(p); - char* query_str = strjoin(header, query, NULL); - - assert(p); - assert(query_str); - - rasqal_init(); + raptor_uri* base_uri = raptor_new_uri((unsigned char*)slv2_plugin_get_uri(plugin)); rasqal_query *rq = rasqal_new_query("sparql", NULL); + + char* header = slv2_query_header(plugin); + char* query_str = strjoin(header, sparql_str, NULL); //printf("Query: \n%s\n\n", query_str); - rasqal_query_prepare(rq, (unsigned char*)query_str, NULL); + rasqal_query_prepare(rq, (unsigned char*)query_str, base_uri); + + // Add LV2 ontology to query sources + rasqal_query_add_data_graph(rq, slv2_ontology_uri, + NULL, RASQAL_DATA_GRAPH_BACKGROUND); + rasqal_query_results* results = rasqal_query_execute(rq); assert(results); - SLV2Property ret = slv2_query_get_variable_bindings(results, var_name); - rasqal_free_query_results(results); rasqal_free_query(rq); + raptor_free_uri(base_uri); + + // FIXME: results leaked? + return results; + + /* + SLV2Value ret = slv2_query_get_variable_bindings(results, var_name); - rasqal_finish(); - - free(query_str); - free(header); + rasqal_free_query_results(results); + rasqal_free_query(rq); + + return ret;*/ +} + + +/** Query a single variable */ +SLV2Value +slv2_plugin_simple_query(SLV2Plugin* plugin, + const char* sparql_str, + const char* variable) +{ + rasqal_query_results* results = slv2_plugin_query(plugin, sparql_str); + SLV2Value ret = slv2_query_get_variable_bindings(results, variable); + rasqal_free_query_results(results); return ret; } +// FIXME: stupid interface size_t slv2_query_count_results(const SLV2Plugin* p, const char* query) @@ -147,13 +168,16 @@ slv2_query_count_results(const SLV2Plugin* p, assert(p); assert(query_str); - rasqal_init(); - rasqal_query *rq = rasqal_new_query("sparql", NULL); //printf("Query: \n%s\n\n", query_str); rasqal_query_prepare(rq, (unsigned char*)query_str, NULL); + + // Add LV2 ontology to query sources + rasqal_query_add_data_graph(rq, slv2_ontology_uri, + NULL, RASQAL_DATA_GRAPH_BACKGROUND); + rasqal_query_results* results = rasqal_query_execute(rq); assert(results); @@ -170,6 +194,7 @@ slv2_query_count_results(const SLV2Plugin* p, return count; } + /* size_t slv2_query_get_num_results(rasqal_query_results* results, const char* var_name) @@ -188,7 +213,7 @@ slv2_query_get_num_results(rasqal_query_results* results, const char* var_name) */ void -slv2_property_free(struct _Property* prop) +slv2_value_free(struct _Value* prop) { for (size_t i=0; i < prop->num_values; ++i) free(prop->values[i]); diff --git a/utils/Makefile.am b/utils/Makefile.am index 4dff275..09935fc 100644 --- a/utils/Makefile.am +++ b/utils/Makefile.am @@ -1,11 +1,15 @@ AM_CFLAGS = -I$(top_srcdir) @RASQAL_CFLAGS@ -bin_PROGRAMS = lv2_list +bin_PROGRAMS = lv2_list lv2_inspect lv2_list_CFLAGS = "-std=c99" lv2_list_SOURCES = lv2_list.c lv2_list_LDADD = ../src/libslv2.la +lv2_inspect_CFLAGS = "-std=c99" +lv2_inspect_SOURCES = lv2_inspect.c +lv2_inspect_LDADD = ../src/libslv2.la + if BUILD_LADSPA2SLV2 bin_PROGRAMS += ladspa2lv2 diff --git a/utils/lv2_inspect.c b/utils/lv2_inspect.c new file mode 100644 index 0000000..c8ffd55 --- /dev/null +++ b/utils/lv2_inspect.c @@ -0,0 +1,106 @@ +/* lv2_inspect - Display information about an LV2 plugin. + * Copyright (C) 2007 Dave Robillard + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include + + +void +print_port(SLV2Plugin* p, uint32_t index) +{ + SLV2PortID id = slv2_port_by_index(index); + + char* str = NULL; + + printf("\n\tPort %d:\n", index); + + str = slv2_port_get_symbol(p, id); + printf("\t\tSymbol: %s\n", str); + free(str); + + str = slv2_port_get_name(p, id); + printf("\t\tName: %s\n", str); + free(str); +} + + +void +print_plugin(SLV2Plugin* p) +{ + char* str = NULL; + + printf("<%s>\n", slv2_plugin_get_uri(p)); + + printf("\tData URL: %s\n", slv2_plugin_get_data_url(p)); + printf("\tLibrary URL: %s\n\n", slv2_plugin_get_library_url(p)); + + str = slv2_plugin_get_name(p); + printf("\tName: %s\n", str); + free(str); + + if (slv2_plugin_has_latency(p)) + printf("\tHas latency: yes\n"); + else + printf("\tHas latency: no\n"); + + printf("\tProperties:\n"); + SLV2Value v = slv2_plugin_get_properties(p); + for (size_t i=0; i < v->num_values; ++i) + printf("\t\t%s\n", v->values[i]); + slv2_value_free(v); + + printf("\tHints:\n"); + v = slv2_plugin_get_hints(p); + for (size_t i=0; i < v->num_values; ++i) + printf("\t\t%s\n", v->values[i]); + slv2_value_free(v); + + uint32_t num_ports = slv2_plugin_get_num_ports(p); + for (uint32_t i=0; i < num_ports; ++i) + print_port(p, i); +} + + + +int +main(int argc, char** argv) +{ + slv2_init(); + + if (argc != 2) { + fprintf(stderr, "Usage: %s PLUGIN_URI\n", argv[0]); + return -1; + } + + SLV2List plugins = slv2_list_new(); + slv2_list_load_all(plugins); + + SLV2Plugin* p = slv2_list_get_plugin_by_uri(plugins, argv[1]); + + if (!p) { + fprintf(stderr, "Plugin not found.\n"); + return -1; + } + + print_plugin(p); + + slv2_finish(); + + return 0; +} diff --git a/utils/lv2_list.c b/utils/lv2_list.c index e1cba6d..923cba9 100644 --- a/utils/lv2_list.c +++ b/utils/lv2_list.c @@ -33,11 +33,15 @@ list_plugins(SLV2List list) int main()//int argc, char** argv) { + slv2_init(); + SLV2List plugins = slv2_list_new(); slv2_list_load_all(plugins); list_plugins(plugins); + slv2_finish(); + return 0; } -- cgit v1.2.1