summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2007-02-07 01:45:53 +0000
committerDavid Robillard <d@drobilla.net>2007-02-07 01:45:53 +0000
commit17ec1c5594772a89a5284449754b56ccb705ebe4 (patch)
treed3ee843acc698345b3760818b1a09f55a18517bb
parent87e016baff11bd74d905b68e48577461b36b992c (diff)
downloadlilv-17ec1c5594772a89a5284449754b56ccb705ebe4.tar.gz
lilv-17ec1c5594772a89a5284449754b56ccb705ebe4.tar.bz2
lilv-17ec1c5594772a89a5284449754b56ccb705ebe4.zip
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
-rw-r--r--configure.ac14
-rw-r--r--data/Makefile.am3
-rw-r--r--data/lv2.ttl28
-rw-r--r--hosts/lv2_jack_host.c15
-rw-r--r--hosts/lv2_simple_jack_host.c30
-rw-r--r--slv2/Makefile.am1
-rw-r--r--slv2/library.h53
-rw-r--r--slv2/plugin.h61
-rw-r--r--slv2/port.h72
-rw-r--r--slv2/query.h22
-rw-r--r--slv2/slv2.h6
-rw-r--r--slv2/types.h27
-rw-r--r--src/Makefile.am5
-rw-r--r--src/library.c44
-rw-r--r--src/plugin.c106
-rw-r--r--src/pluginlist.c4
-rw-r--r--src/port.c167
-rw-r--r--src/query.c91
-rw-r--r--utils/Makefile.am6
-rw-r--r--utils/lv2_inspect.c106
-rw-r--r--utils/lv2_list.c4
21 files changed, 644 insertions, 221 deletions
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 <http://lv2plug.in> 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 <http://drobilla.net>
+ *
+ * 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 <rasqal.h>
+
+#include <slv2/library.h>
#include <slv2/types.h>
#include <slv2/plugin.h>
#include <slv2/plugininstance.h>
#include <slv2/pluginlist.h>
#include <slv2/port.h>
+
#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 <stddef.h>
+#include <stdbool.h>
+#include <stdint.h>
+
#ifdef __cplusplus
extern "C" {
#endif
-#include <stddef.h>
-
/* 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 <http://drobilla.net>
+ *
+ * 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 <slv2/slv2.h>
+
+
+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: <http://www.w3.org/2000/01/rdf-schema#> \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 <assert.h>
#include <stdlib.h>
#include <string.h>
+#include <limits.h>
#include <slv2/port.h>
#include <slv2/types.h>
#include <slv2/query.h>
#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 <assert.h>
#include <slv2/plugin.h>
#include <slv2/query.h>
+#include <slv2/library.h>
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: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> \n"
- "PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> \n"
- "PREFIX doap: <http://usefulinc.com/ns/doap#> \n"
- "PREFIX lv2: <http://lv2plug.in/ontology#> \n"
- "PREFIX plugin: <", plugin_uri, "> \n",
- "PREFIX data: <", data_file_url, "> \n\n", NULL);
+ "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>\n"
+ "PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>\n"
+ "PREFIX doap: <http://usefulinc.com/ns/doap#>\n"
+ "PREFIX lv2: <http://lv2plug.in/ontology#>\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 <drobilla.net>
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <slv2/slv2.h>
+
+
+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;
}