summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--data/lv2.ttl3
-rw-r--r--doc/reference.doxygen.in2
-rw-r--r--hosts/lv2_jack_host.c7
-rw-r--r--hosts/lv2_simple_jack_host.c203
-rw-r--r--slv2/lv2.h2
-rw-r--r--slv2/plugin.h60
-rw-r--r--slv2/pluginlist.h36
-rw-r--r--slv2/port.h18
-rw-r--r--slv2/stringlist.h11
-rw-r--r--slv2/types.h7
-rw-r--r--slv2/world.h75
-rw-r--r--src/plugin.c12
-rw-r--r--src/plugininstance.c9
-rw-r--r--src/pluginlist.c8
-rw-r--r--src/private_types.h27
-rw-r--r--src/world.c57
-rw-r--r--utils/lv2_inspect.c50
-rw-r--r--utils/lv2_list.c2
18 files changed, 421 insertions, 168 deletions
diff --git a/data/lv2.ttl b/data/lv2.ttl
index d3ed0b3..d0d9f94 100644
--- a/data/lv2.ttl
+++ b/data/lv2.ttl
@@ -167,10 +167,9 @@ The plugin author MUST change the plugin URI if a port index is changed.
""" .
:symbol a rdf:Property ;
- rdfs:domain :Port ;
rdfs:label "symbol" ;
rdfs:comment """
-A short name used to identify the port in an easily machine and human readable way.
+A short name used as a machine and human readable identifier.
The first character must be one of _, a-z or A-Z and subsequenct characters can
be from _, a-z, A-Z and 0-9.
diff --git a/doc/reference.doxygen.in b/doc/reference.doxygen.in
index ce9cd2d..ac744a9 100644
--- a/doc/reference.doxygen.in
+++ b/doc/reference.doxygen.in
@@ -421,7 +421,7 @@ WARN_LOGFILE =
INPUT = @top_srcdir@/doc/mainpage.dox \
@top_srcdir@/slv2/types.h \
- @top_srcdir@/slv2/model.h \
+ @top_srcdir@/slv2/world.h \
@top_srcdir@/slv2/pluginlist.h \
@top_srcdir@/slv2/stringlist.h \
@top_srcdir@/slv2/plugin.h \
diff --git a/hosts/lv2_jack_host.c b/hosts/lv2_jack_host.c
index a0bca74..4a9995f 100644
--- a/hosts/lv2_jack_host.c
+++ b/hosts/lv2_jack_host.c
@@ -74,6 +74,7 @@ main(int argc, char** argv)
fprintf(stderr, "\nYou must specify a plugin URI to load.\n");
fprintf(stderr, "\nKnown plugins:\n\n");
list_plugins(plugins);
+ slv2_world_free(world);
return EXIT_FAILURE;
}
@@ -82,7 +83,7 @@ main(int argc, char** argv)
if (!host.plugin) {
fprintf(stderr, "Failed to find plugin %s.\n", plugin_uri);
- slv2_plugins_free(plugins);
+ slv2_world_free(world);
return EXIT_FAILURE;
}
@@ -126,7 +127,7 @@ main(int argc, char** argv)
/* Deactivate plugin and JACK */
slv2_instance_free(host.instance);
- slv2_plugins_free(plugins);
+ slv2_plugins_free(world, plugins);
printf("Shutting down JACK.\n");
for (unsigned long i=0; i < host.num_ports; ++i) {
@@ -140,6 +141,7 @@ main(int argc, char** argv)
}
jack_client_close(host.jack_client);
+ slv2_plugins_free(world, plugins);
slv2_world_free(world);
return 0;
@@ -166,7 +168,6 @@ void
create_port(struct JackHost* host,
uint32_t port_index)
{
- //struct Port* port = (Port*)malloc(sizeof(Port));
struct Port* const port = &host->ports[port_index];
port->class = SLV2_UNKNOWN_PORT_CLASS;
diff --git a/hosts/lv2_simple_jack_host.c b/hosts/lv2_simple_jack_host.c
index 0b938e3..d0fabc1 100644
--- a/hosts/lv2_simple_jack_host.c
+++ b/hosts/lv2_simple_jack_host.c
@@ -20,49 +20,200 @@
#include <stdlib.h>
#include <string.h>
#include <slv2/slv2.h>
+#include <jack/jack.h>
+
+
+/** This program's data */
+struct JackHost {
+ jack_client_t* jack_client; /**< Jack client */
+ SLV2Plugin plugin; /**< Plugin "class" (actually just a few strings) */
+ SLV2Instance instance; /**< Plugin "instance" (loaded shared lib) */
+ uint32_t num_ports; /**< Size of the two following arrays: */
+ jack_port_t** jack_ports; /**< For audio ports, otherwise NULL */
+ float* controls; /**< For control ports, otherwise 0.0f */
+};
+
+
+void die(const char* msg);
+void create_port(struct JackHost* host, uint32_t port_index);
+int jack_process_cb(jack_nframes_t nframes, void* data);
+void list_plugins(SLV2Plugins list);
+
int
-main(/*int argc, char** argv*/)
+main(int argc, char** argv)
{
+ struct JackHost host;
+ host.jack_client = NULL;
+ host.num_ports = 0;
+ host.jack_ports = NULL;
+ host.controls = NULL;
+
+ /* Find all installed plugins */
SLV2World world = slv2_world_new();
slv2_world_load_all(world);
+ SLV2Plugins plugins = slv2_world_get_all_plugins(world);
+
+ /* Find the plugin to run */
+ const char* plugin_uri = (argc == 2) ? argv[1] : NULL;
+ if (!plugin_uri) {
+ fprintf(stderr, "\nYou must specify a plugin URI to load.\n");
+ fprintf(stderr, "\nKnown plugins:\n\n");
+ list_plugins(plugins);
+ slv2_world_free(world);
+ return EXIT_FAILURE;
+ }
- /*printf("********** All plugins **********\n");
+ printf("URI:\t%s\n", plugin_uri);
+ host.plugin = slv2_plugins_get_by_uri(plugins, plugin_uri);
+
+ if (!host.plugin) {
+ fprintf(stderr, "Failed to find plugin %s.\n", plugin_uri);
+ slv2_world_free(world);
+ return EXIT_FAILURE;
+ }
- SLV2Plugins plugins = slv2_model_get_all_plugins(model);
+ /* Get the plugin's name */
+ char* name = slv2_plugin_get_name(host.plugin);
+ printf("Name:\t%s\n", name);
+
+ /* Connect to JACK (with plugin name as client name) */
+ host.jack_client = jack_client_open(name, JackNullOption, NULL);
+ free(name);
+ if (!host.jack_client)
+ die("Failed to connect to JACK.");
+ else
+ printf("Connected to JACK.\n");
+
+ /* Instantiate the plugin */
+ host.instance = slv2_plugin_instantiate(
+ host.plugin, jack_get_sample_rate(host.jack_client), NULL);
+ if (!host.instance)
+ die("Failed to instantiate plugin.\n");
+ else
+ printf("Succesfully instantiated plugin.\n");
- for (unsigned i=0; i < slv2_plugins_size(plugins); ++i) {
- SLV2Plugin p = slv2_plugins_get_at(plugins, i);
- printf("Plugin: %s\n", slv2_plugin_get_uri(p));
+ jack_set_process_callback(host.jack_client, &jack_process_cb, (void*)(&host));
+
+ /* Create ports */
+ host.num_ports = slv2_plugin_get_num_ports(host.plugin);
+ host.jack_ports = calloc((size_t)host.num_ports, sizeof(jack_port_t*));
+ host.controls = calloc((size_t)host.num_ports, sizeof(float*));
+
+ for (uint32_t i=0; i < host.num_ports; ++i)
+ create_port(&host, i);
+
+ /* Activate plugin and JACK */
+ slv2_instance_activate(host.instance);
+ jack_activate(host.jack_client);
+
+ /* Run */
+ printf("Press enter to quit: ");
+ getc(stdin);
+ printf("\n");
+
+ /* Deactivate plugin and JACK */
+ slv2_instance_free(host.instance);
+
+ printf("Shutting down JACK.\n");
+ for (unsigned long i=0; i < host.num_ports; ++i) {
+ if (host.jack_ports[i] != NULL) {
+ jack_port_unregister(host.jack_client, host.jack_ports[i]);
+ host.jack_ports[i] = NULL;
+ }
}
+ jack_client_close(host.jack_client);
+
+ slv2_world_free(world);
+
+ return 0;
+}
+
- slv2_plugins_free(plugins);*/
+/** Abort and exit on error */
+void
+die(const char* msg)
+{
+ fprintf(stderr, "%s\n", msg);
+ exit(EXIT_FAILURE);
+}
+
+
+/** Creates a port and connects the plugin instance to it's data location.
+ *
+ * For audio ports, creates a jack port and connects plugin port to buffer.
+ *
+ * For control ports, sets controls array to default value and connects plugin
+ * port to that element.
+ */
+void
+create_port(struct JackHost* host,
+ uint32_t index)
+{
+ SLV2Port port = slv2_plugin_get_port_by_index(host->plugin, index);
+
+ /* Get the port symbol (label) for console printing */
+ char* symbol = slv2_port_get_symbol(host->plugin, port);
+ /* Initialize the port array elements */
+ host->jack_ports[index] = NULL;
+ host->controls[index] = 0.0f;
- printf("********** Plugins with MIDI input **********\n");
+ /* Get the 'class' of the port (control input, audio output, etc) */
+ SLV2PortClass class = slv2_port_get_class(host->plugin, port);
- /*const char* query =
- "PREFIX : <http://lv2plug.in/ontology#>\n"
- //"PREFIX llext: <http://ll-plugins.nongnu.org/lv2/ext/>\n"
- "SELECT DISTINCT ?plugin WHERE {\n"
- " ?plugin a :Plugin ;\n"
- " :port ?port .\n"
- " ?port :symbol \"in\". \n"
- //" :port [ a llext:MidiPort; a :InputPort ] .\n"
- "}\n";
+ /* Connect the port based on it's 'class' */
+ switch (class) {
+ case SLV2_CONTROL_INPUT:
+ host->controls[index] = slv2_port_get_default_value(host->plugin, port);
+ slv2_instance_connect_port(host->instance, index, &host->controls[index]);
+ printf("Set %s to %f\n", symbol, host->controls[index]);
+ break;
+ case SLV2_CONTROL_OUTPUT:
+ slv2_instance_connect_port(host->instance, index, &host->controls[index]);
+ break;
+ case SLV2_AUDIO_INPUT:
+ host->jack_ports[index] = jack_port_register(host->jack_client,
+ symbol, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
+ break;
+ case SLV2_AUDIO_OUTPUT:
+ host->jack_ports[index] = jack_port_register(host->jack_client,
+ symbol, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
+ break;
+ default:
+ // Simple examples don't have to be robust :)
+ die("ERROR: Unknown port type, aborting messily!");
+ }
- SLV2Plugins plugins = slv2_model_get_plugins_by_query(model, query);
+ free(symbol);
+}
- for (unsigned i=0; i < slv2_plugins_size(plugins); ++i) {
- SLV2Plugin p = slv2_plugins_get_at(plugins, i);
- printf("Plugin: %s\n", slv2_plugin_get_uri(p));
- }
-
- slv2_plugins_free(plugins);
- */
- slv2_world_free(world);
+/** Jack process callback. */
+int
+jack_process_cb(jack_nframes_t nframes, void* data)
+{
+ struct JackHost* host = (struct JackHost*)data;
+
+ /* Connect plugin ports directly to JACK buffers */
+ for (uint32_t i=0; i < host->num_ports; ++i)
+ if (host->jack_ports[i] != NULL)
+ slv2_instance_connect_port(host->instance, i,
+ jack_port_get_buffer(host->jack_ports[i], nframes));
+ /* Run plugin for this cycle */
+ slv2_instance_run(host->instance, nframes);
+
return 0;
}
+
+
+void
+list_plugins(SLV2Plugins list)
+{
+ for (unsigned i=0; i < slv2_plugins_size(list); ++i) {
+ SLV2Plugin p = slv2_plugins_get_at(list, i);
+ printf("%s\n", slv2_plugin_get_uri(p));
+ }
+}
diff --git a/slv2/lv2.h b/slv2/lv2.h
index 10ea542..3e7b641 100644
--- a/slv2/lv2.h
+++ b/slv2/lv2.h
@@ -113,7 +113,7 @@ extern "C" {
*
* This plugin handle indicates a particular instance of the plugin
* concerned. It is valid to compare this to NULL (0 for C++) but
- * otherwise the host MUST not attempt to interpret it. The plugin
+ * otherwise the host MUST NOT attempt to interpret it. The plugin
* may use it to reference internal instance data. */
typedef void * LV2_Handle;
diff --git a/slv2/plugin.h b/slv2/plugin.h
index 47cb9ee..30394d3 100644
--- a/slv2/plugin.h
+++ b/slv2/plugin.h
@@ -53,11 +53,14 @@ extern "C" {
* testing utilities, etc.
*
* \return true if \a plugin is valid.
+ *
+ * Time = Query
*/
bool
slv2_plugin_verify(SLV2Plugin plugin);
+#if 0
/** Duplicate a plugin.
*
* Use this if you want to keep an SLV2Plugin around but free the list it came
@@ -68,15 +71,7 @@ slv2_plugin_verify(SLV2Plugin plugin);
*/
SLV2Plugin
slv2_plugin_duplicate(SLV2Plugin plugin);
-
-
-/** Free an SLV2Plugin.
- *
- * This should NEVER be used on a plugin contained in a Plugins. Use this
- * only with plugins created with slv2_plugin_duplicate.
- */
-void
-slv2_plugin_free(SLV2Plugin plugin);
+#endif
/** Get the URI of \a plugin.
@@ -92,6 +87,8 @@ slv2_plugin_free(SLV2Plugin plugin);
* MUST have a different URI than it's predecessor.
*
* \return a shared string which must not be modified or free()'d.
+ *
+ * Time = O(1)
*/
const char*
slv2_plugin_get_uri(SLV2Plugin plugin);
@@ -102,8 +99,10 @@ slv2_plugin_get_uri(SLV2Plugin plugin);
* Note this always returns fully qualified URIs. If you want local
* filesystem paths, use slv2_uri_to_path.
*
- * \return a complete URL eg. "file:///usr/foo/SomeBundle.lv2/someplug.ttl",
- * which is shared and must not be modified or free()'d.
+ * \return a list of complete URLs eg. "file:///foo/ABundle.lv2/aplug.ttl",
+ * which is shared and must not be modified or freed.
+ *
+ * Time = O(1)
*/
SLV2Strings
slv2_plugin_get_data_uris(SLV2Plugin plugin);
@@ -113,8 +112,10 @@ slv2_plugin_get_data_uris(SLV2Plugin plugin);
*
* Note this always returns a fully qualified URI. If you want a local
* filesystem path, use slv2_uri_to_path.
+ *
+ * \return a shared string which must not be modified or freed.
*
- * \return a shared string which must not be modified or free()'d.
+ * Time = O(1)
*/
const char*
slv2_plugin_get_library_uri(SLV2Plugin plugin);
@@ -124,8 +125,10 @@ slv2_plugin_get_library_uri(SLV2Plugin plugin);
/** Get the name of \a plugin.
*
* 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
+ * data file without a language tag). Returned value must be freed by
* the caller.
+ *
+ * Time = Query
*/
char*
slv2_plugin_get_name(SLV2Plugin plugin);
@@ -141,6 +144,8 @@ slv2_plugin_get_name(SLV2Plugin plugin);
* sensibly represented as an SLV2Strings (e.g. blank nodes).
*
* Return value must be freed by caller with slv2_strings_free.
+ *
+ * Time = Query
*/
SLV2Strings
slv2_plugin_get_value(SLV2Plugin p,
@@ -160,6 +165,8 @@ slv2_plugin_get_value(SLV2Plugin p,
* sensibly represented as an SLV2Strings (e.g. blank nodes).
*
* Return value must be freed by caller with slv2_strings_free.
+ *
+ * Time = Query
*/
SLV2Strings
slv2_plugin_get_value_for_subject(SLV2Plugin p,
@@ -174,6 +181,8 @@ slv2_plugin_get_value_for_subject(SLV2Plugin p,
* not what you want, see slv2_plugin_get_hints).
*
* Return value must be freed by caller with slv2_value_free.
+ *
+ * Time = Query
*/
SLV2Strings
slv2_plugin_get_properties(SLV2Plugin p);
@@ -185,12 +194,16 @@ slv2_plugin_get_properties(SLV2Plugin p);
* ignored and the plugin will still function correctly.
*
* Return value must be freed by caller with slv2_value_free.
+ *
+ * Time = Query
*/
SLV2Strings
slv2_plugin_get_hints(SLV2Plugin p);
/** Get the number of ports on this plugin.
+ *
+ * Time = O(1)
*/
uint32_t
slv2_plugin_get_num_ports(SLV2Plugin p);
@@ -200,6 +213,8 @@ slv2_plugin_get_num_ports(SLV2Plugin p);
*
* The index of the latency port can be found with slv2_plugin_get_latency_port
* ONLY if this function returns true.
+ *
+ * Time = Query
*/
bool
slv2_plugin_has_latency(SLV2Plugin p);
@@ -214,6 +229,8 @@ slv2_plugin_has_latency(SLV2Plugin p);
* 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.
+ *
+ * Time = Query
*/
uint32_t
slv2_plugin_get_latency_port(SLV2Plugin p);
@@ -222,6 +239,8 @@ slv2_plugin_get_latency_port(SLV2Plugin p);
/** Get a plugin's supported host features / extensions.
*
* This returns a list of all supported features (both required and optional).
+ *
+ * Time = Query
*/
SLV2Strings
slv2_plugin_get_supported_features(SLV2Plugin p);
@@ -231,6 +250,8 @@ slv2_plugin_get_supported_features(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.
+ *
+ * Time = Query
*/
SLV2Strings
slv2_plugin_get_required_features(SLV2Plugin p);
@@ -241,6 +262,8 @@ slv2_plugin_get_required_features(SLV2Plugin p);
* If the feature URI's returned by this method are passed to the plugin's
* 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.
+ *
+ * Time = Query
*/
SLV2Strings
slv2_plugin_get_optional_features(SLV2Plugin p);
@@ -248,9 +271,12 @@ slv2_plugin_get_optional_features(SLV2Plugin p);
/** Query a plugin for a single variable.
*
+ * \param plugin The plugin to query.
* \param sparql_str A SPARQL SELECT query.
* \param variable The variable to return results for.
* \return All matches for \a variable.
+ *
+ * Time = Query
*/
SLV2Strings
slv2_plugin_simple_query(SLV2Plugin plugin,
@@ -260,7 +286,10 @@ slv2_plugin_simple_query(SLV2Plugin plugin,
/** Query a plugin and return the number of results found.
*
+ * \param plugin The plugin to query.
* \param sparql_str A SPARQL SELECT query.
+ *
+ * Time = Query
*/
unsigned
slv2_plugin_query_count(SLV2Plugin plugin,
@@ -272,7 +301,7 @@ slv2_plugin_query_count(SLV2Plugin plugin,
* To perform multiple calls on a port, the returned value should
* be cached and used repeatedly.
*
- * O(1)
+ * Time = O(1)
*/
SLV2Port
slv2_plugin_get_port_by_index(SLV2Plugin plugin,
@@ -284,14 +313,13 @@ slv2_plugin_get_port_by_index(SLV2Plugin plugin,
* To perform multiple calls on a port, the returned value should
* be cached and used repeatedly.
*
- * O(num_ports)
+ * Time = O(n)
*/
SLV2Port
slv2_plugin_get_port_by_symbol(SLV2Plugin plugin,
const char* symbol);
-
/** @} */
#ifdef __cplusplus
diff --git a/slv2/pluginlist.h b/slv2/pluginlist.h
index cd1bbf8..a2978e1 100644
--- a/slv2/pluginlist.h
+++ b/slv2/pluginlist.h
@@ -39,27 +39,14 @@ typedef void* SLV2Plugins;
*/
-/** Create a new, empty plugin list.
- *
- * Returned object must be freed with slv2_plugins_free.
- */
-SLV2Plugins
-slv2_plugins_new();
-
-
/** Free a plugin list.
*
- * Note that all plugins in the list (eg those returned by the get_plugin
- * functions) will be deleted as well. It is expected that hosts will
- * keep the plugin list allocated until they are done with their plugins.
- * If you want to keep a plugin around, but free the list it came from, you
- * will have to copy it with slv2_plugin_duplicate().
- *
- * \a list is invalid after this call (though it may be used again after a
- * "list = slv2_plugins_new()")
+ * Freeing a plugin list does not destroy the plugins it contains (plugins
+ * are owned by the world). \a list is invalid after this call.
*/
void
-slv2_plugins_free(SLV2Plugins list);
+slv2_plugins_free(SLV2World world,
+ SLV2Plugins list);
/** Get the number of plugins in the list.
@@ -73,7 +60,7 @@ slv2_plugins_size(SLV2Plugins list);
* Return value is shared (stored in \a list) and must not be freed or
* modified by the caller in any way.
*
- * O(log2(n))
+ * Time = O(log2(n))
*
* \return NULL if plugin with \a url not found in \a list.
*/
@@ -84,15 +71,12 @@ slv2_plugins_get_by_uri(SLV2Plugins list,
/** Get a plugin from the list by index.
*
- * \a index has no significance. Any \a index not less than
- * slv2list_get_length(list) will return NULL. All plugins in a list can
- * thus be easily enumerated by repeated calls to this function starting
- * with \a index 0.
- *
- * Return value is shared (stored in \a list) and must not be freed or
- * modified by the caller in any way.
+ * \a index has no significance other than as an index into this list.
+ * Any \a index not less than slv2_list_get_length(list) will return NULL,
+ * so all plugins in a list can be enumerated by repeated calls
+ * to this function starting with \a index = 0.
*
- * O(1)
+ * Time = O(1)
*
* \return NULL if \a index out of range.
*/
diff --git a/slv2/port.h b/slv2/port.h
index 13ac5c1..d415f84 100644
--- a/slv2/port.h
+++ b/slv2/port.h
@@ -34,6 +34,8 @@ extern "C" {
/** Port equivalent to slv2_plugin_get_value.
+ *
+ * Time = Query
*/
SLV2Strings
slv2_port_get_value(SLV2Plugin plugin,
@@ -42,6 +44,8 @@ slv2_port_get_value(SLV2Plugin plugin,
/** Port equivalent to slv2_plugin_get_properties.
+ *
+ * Time = Query
*/
SLV2Strings
slv2_port_get_properties(SLV2Plugin plugin,
@@ -49,6 +53,8 @@ slv2_port_get_properties(SLV2Plugin plugin,
/** Port equivalent to slv2_plugin_get_hints.
+ *
+ * Time = Query
*/
SLV2Strings
slv2_port_get_hints(SLV2Plugin plugin,
@@ -61,6 +67,8 @@ slv2_port_get_hints(SLV2Plugin plugin,
* Returned string must be free()'d by caller.
*
* \return NULL when index is out of range
+ *
+ * Time = Query
*/
char*
slv2_port_get_symbol(SLV2Plugin plugin,
@@ -71,6 +79,8 @@ slv2_port_get_symbol(SLV2Plugin plugin,
* 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.
+ *
+ * Time = Query
*/
char*
slv2_port_get_name(SLV2Plugin plugin,
@@ -78,6 +88,8 @@ slv2_port_get_name(SLV2Plugin plugin,
/** Get the class (input/output, data type, rate...) of a port.
+ *
+ * Time = Query
*/
SLV2PortClass
slv2_port_get_class(SLV2Plugin plugin,
@@ -87,6 +99,8 @@ slv2_port_get_class(SLV2Plugin plugin,
/** Get the default value of a port.
*
* Only valid for ports with a data type of lv2:float.
+ *
+ * Time = Query
*/
float
slv2_port_get_default_value(SLV2Plugin plugin,
@@ -96,6 +110,8 @@ slv2_port_get_default_value(SLV2Plugin plugin,
/** Get the minimum value of a port.
*
* Only valid for ports with a data type of lv2:float.
+ *
+ * Time = Query
*/
float
slv2_port_get_minimum_value(SLV2Plugin plugin,
@@ -105,6 +121,8 @@ slv2_port_get_minimum_value(SLV2Plugin plugin,
/** Get the maximum value of a port.
*
* Only valid for ports with a data type of lv2:float.
+ *
+ * Time = Query
*/
float
slv2_port_get_maximum_value(SLV2Plugin plugin,
diff --git a/slv2/stringlist.h b/slv2/stringlist.h
index 0c42318..eb613d6 100644
--- a/slv2/stringlist.h
+++ b/slv2/stringlist.h
@@ -53,18 +53,23 @@ slv2_strings_size(SLV2Strings list);
/** Get a string from a string list at the given index.
*
* @return the element at \a index, or NULL if index is out of range.
+ *
+ * Time = O(1)
*/
const char*
slv2_strings_get_at(SLV2Strings list, unsigned index);
-/** Return whether \a list contains \a uri.
+/** Return whether \a list contains \a string.
+ *
+ * Time = O(n)
*/
bool
-slv2_strings_contains(SLV2Strings list, const char* uri);
+slv2_strings_contains(SLV2Strings list, const char* string);
-/** Free a string list. */
+/** Free a string list.
+ */
void
slv2_strings_free(SLV2Strings);
diff --git a/slv2/types.h b/slv2/types.h
index f0f9b7f..c22b2be 100644
--- a/slv2/types.h
+++ b/slv2/types.h
@@ -43,12 +43,19 @@ typedef enum _PortClass {
SLV2_MIDI_OUTPUT /**< MIDI output (LL extension) */
} SLV2PortClass;
+
+/** A port on a plugin. Opaque, but valid to compare to NULL. */
typedef struct _Port* SLV2Port;
+
+/** A plugin. Opaque, but valid to compare to NULL. */
typedef struct _Plugin* SLV2Plugin;
+
+/** The world. Opaque, but valid to compare to NULL. */
typedef struct _World* SLV2World;
+
#ifdef __cplusplus
}
#endif
diff --git a/slv2/world.h b/slv2/world.h
index 4f5b252..64f0fc2 100644
--- a/slv2/world.h
+++ b/slv2/world.h
@@ -28,17 +28,19 @@ extern "C" {
/** \defgroup world Library context, data loading, etc.
*
- * These functions deal with the data model which other SLV2 methods
- * operate with. The world contains an in-memory cache of all bundles
- * manifest.ttl files, from which you can quickly query plugins, etc.
+ * The "world" represents all library state, and the data found in bundles'
+ * manifest.ttl (ie it is an in-memory index of all things LV2 found).
+ * Plugins (and plugin extensions) and the LV2 specification (and LV2
+ * extensions) itself can be queried from the world for use.
*
* Normal hosts which just want to easily load plugins by URI are strongly
- * recommended to simply find all installed data in the recommended way with
- * \ref slv2_world_load_all rather than find and load bundles manually.
- *
- * Functions are provided for hosts that wish to access bundles explicitly and
- * individually for some reason, this is intended for hosts which are tied to
- * a specific bundle (shipped with the application).
+ * recommended to simply call \ref slv2_world_load_all to find all installed
+ * data in the recommended way.
+ *
+ * Normal hosts should NOT have to refer to bundles directly under normal
+ * circumstances. However, functions are provided to load individual bundles
+ * explicitly, intended for hosts which depend on a specific bundle
+ * (which is shipped with the application).
*
* @{
*/
@@ -60,7 +62,7 @@ void
slv2_world_free(SLV2World world);
-/** Load all installed LV2 bundles on the system
+/** Load all installed LV2 bundles on the system.
*
* This is the recommended way for hosts to load LV2 data. It does the most
* reasonable thing to find all installed plugins, extensions, etc. on the
@@ -70,60 +72,63 @@ slv2_world_free(SLV2World world);
*
* Use of other functions for loading bundles is \em highly discouraged
* without a special reason to do so - use this one.
- */
-void
-slv2_world_load_all(SLV2World world);
-
-
-/** Load all bundles found in \a search_path.
*
- * \param search_path A colon-delimited list of directories. These directories
- * should contain LV2 bundle directories (ie the search path is a list of
- * parent directories of bundles, not a list of bundle directories).
- *
- * If \a search_path is NULL, \a world will be unmodified.
- * Use of this function is \b not recommended. Use \ref slv2_world_load_all.
+ * Time = Query
*/
void
-slv2_world_load_path(SLV2World world,
- const char* search_path);
+slv2_world_load_all(SLV2World world);
-/** Load a specific bundle into \a world.
+/** Load a specific bundle.
*
- * \arg bundle_base_uri is a fully qualified URI to the bundle directory,
+ * \arg bundle_uri A fully qualified URI to the bundle directory,
* with the trailing slash, eg. file:///usr/lib/lv2/someBundle/
*
* Normal hosts should not use this function.
*
- * Hosts should not attach \em any long-term significance to bundle paths
+ * Hosts should \b never attach any long-term significance to bundle paths
* as there are no guarantees they will remain consistent whatsoever.
+ * Plugins (and other things) are identified by URIs, \b not bundle or
+ * file names.
+ *
* This function should only be used by apps which ship with a special
- * bundle (which it knows exists at some path because they are part of
- * the same package).
+ * bundle (which it knows exists at some path because the bundle is
+ * shipped with the application).
+ *
+ * Time = Query
*/
void
slv2_world_load_bundle(SLV2World world,
- const char* bundle_base_uri);
+ const char* bundle_uri);
-/** Add all plugins present in \a world to \a list.
+/** Return a list of all found plugins.
+ *
+ * The returned list contains just enough references to query
+ * or instantiate plugins. The data for a particular plugin will not be
+ * loaded into memory until a call to an slv2_plugin_* function results in
+ * a query (at which time the data is cached with the SLV2Plugin so future
+ * queries are very fast).
*
* Returned plugins contain a reference to this world, world must not be
* destroyed until plugins are finished with.
+ *
+ * Time = O(1)
*/
SLV2Plugins
slv2_world_get_all_plugins(SLV2World world);
-/** Get plugins filtered by a user-defined filter function.
+/** Return a list of found plugins filtered by a user-defined filter function.
*
- * All plugins in \a world that return true when passed to \a include
- * (a pointer to a function that takes an SLV2Plugin and returns a bool)
- * will be added to \a list.
+ * All plugins currently found in \a world that return true when passed to
+ * \a include (a pointer to a function which takes an SLV2Plugin and returns
+ * a bool) will be in the returned list.
*
* Returned plugins contain a reference to this world, world must not be
* destroyed until plugins are finished with.
+ *
+ * Time = O(n * Time(include))
*/
SLV2Plugins
slv2_world_get_plugins_by_filter(SLV2World world,
diff --git a/src/plugin.c b/src/plugin.c
index b3577f2..722caa1 100644
--- a/src/plugin.c
+++ b/src/plugin.c
@@ -37,7 +37,7 @@ slv2_plugin_new(SLV2World world, librdf_uri* uri, const char* binary_uri)
plugin->world = world;
plugin->plugin_uri = librdf_new_uri_from_uri(uri);
plugin->binary_uri = strdup(binary_uri);
- plugin->data_uris = raptor_new_sequence((void (*)(void*))&raptor_free_uri, NULL);
+ plugin->data_uris = slv2_strings_new();
plugin->ports = raptor_new_sequence((void (*)(void*))&slv2_port_free, NULL);
plugin->storage = NULL;
plugin->rdf = NULL;
@@ -69,7 +69,7 @@ slv2_plugin_free(SLV2Plugin p)
p->storage = NULL;
}
- raptor_free_sequence(p->data_uris);
+ slv2_strings_free(p->data_uris);
free(p);
}
@@ -81,6 +81,7 @@ slv2_plugin_query(SLV2Plugin plugin,
const char* sparql_str);
+/*
SLV2Plugin
slv2_plugin_duplicate(SLV2Plugin p)
{
@@ -105,6 +106,7 @@ slv2_plugin_duplicate(SLV2Plugin p)
return result;
}
+*/
/** comparator for sorting */
@@ -136,9 +138,11 @@ slv2_plugin_load(SLV2Plugin p)
}
// Parse all the plugin's data files into RDF model
- for (int i=0; i < raptor_sequence_size(p->data_uris); ++i) {
- librdf_uri* data_uri = raptor_sequence_get_at(p->data_uris, i);
+ for (unsigned i=0; i < slv2_strings_size(p->data_uris); ++i) {
+ const char* data_uri_str = slv2_strings_get_at(p->data_uris, i);
+ librdf_uri* data_uri = librdf_new_uri(p->world->world, (const unsigned char*)data_uri_str);
librdf_parser_parse_into_model(p->world->parser, data_uri, NULL, p->rdf);
+ librdf_free_uri(data_uri);
}
// Load ports
diff --git a/src/plugininstance.c b/src/plugininstance.c
index 6d957b6..013e33c 100644
--- a/src/plugininstance.c
+++ b/src/plugininstance.c
@@ -16,6 +16,8 @@
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+#define _XOPEN_SOURCE 500
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -65,7 +67,10 @@ slv2_plugin_instantiate(SLV2Plugin plugin,
// Search for plugin by URI
// FIXME: Kluge to get bundle path (containing directory of binary)
- const char* const bundle_path = strrchr(plugin->binary_uri, '/') + 1;
+ char* bundle_path = strdup(plugin->binary_uri);
+ char* const bundle_path_end = strrchr(bundle_path, '/');
+ if (bundle_path_end)
+ *(bundle_path_end+1) = '\0';
printf("Bundle path: %s\n", bundle_path);
for (uint32_t i=0; 1; ++i) {
@@ -95,6 +100,8 @@ slv2_plugin_instantiate(SLV2Plugin plugin,
break;
}
}
+
+ free(bundle_path);
}
assert(result);
diff --git a/src/pluginlist.c b/src/pluginlist.c
index 50bb2ad..d4cd058 100644
--- a/src/pluginlist.c
+++ b/src/pluginlist.c
@@ -36,14 +36,16 @@
SLV2Plugins
slv2_plugins_new()
{
- return raptor_new_sequence((void (*)(void*))&slv2_plugin_free, NULL);
+ //return raptor_new_sequence((void (*)(void*))&slv2_plugin_free, NULL);
+ return raptor_new_sequence(NULL, NULL);
}
void
-slv2_plugins_free(SLV2Plugins list)
+slv2_plugins_free(SLV2World world, SLV2Plugins list)
{
- raptor_free_sequence(list);
+ if (list != world->plugins)
+ raptor_free_sequence(list);
}
#if 0
diff --git a/src/private_types.h b/src/private_types.h
index 8f2f89d..48bed0a 100644
--- a/src/private_types.h
+++ b/src/private_types.h
@@ -37,6 +37,7 @@ struct _Port {
//char* node_id; ///< RDF Node ID
};
+
SLV2Port slv2_port_new(uint32_t index, const char* symbol/*, const char* node_id*/);
SLV2Port slv2_port_duplicate(SLV2Port port);
void slv2_port_free(SLV2Port port);
@@ -60,13 +61,16 @@ struct _Plugin {
SLV2Plugin slv2_plugin_new(SLV2World world, librdf_uri* uri, const char* binary_uri);
void slv2_plugin_load(SLV2Plugin p);
+void slv2_plugin_free(SLV2Plugin plugin);
-/** List of references to plugins available for loading */
-struct _PluginList {
- size_t num_plugins;
- struct _Plugin** plugins;
-};
+/** Create a new, empty plugin list.
+ *
+ * Returned object must be freed with slv2_plugins_free.
+ */
+SLV2Plugins
+slv2_plugins_new();
+
/** Pimpl portion of SLV2Instance */
struct _InstanceImpl {
@@ -84,6 +88,19 @@ struct _World {
SLV2Plugins plugins;
};
+/** Load all bundles found in \a search_path.
+ *
+ * \param search_path A colon-delimited list of directories. These directories
+ * should contain LV2 bundle directories (ie the search path is a list of
+ * parent directories of bundles, not a list of bundle directories).
+ *
+ * If \a search_path is NULL, \a world will be unmodified.
+ * Use of this function is \b not recommended. Use \ref slv2_world_load_all.
+ */
+void
+slv2_world_load_path(SLV2World world,
+ const char* search_path);
+
#ifdef __cplusplus
}
diff --git a/src/world.c b/src/world.c
index afb71ad..e10e7d4 100644
--- a/src/world.c
+++ b/src/world.c
@@ -59,7 +59,9 @@ slv2_world_free(SLV2World world)
/*raptor_free_uri(slv2_ontology_uri);
slv2_ontology_uri = NULL;*/
- slv2_plugins_free(world->plugins);
+ for (int i=0; i < raptor_sequence_size(world->plugins); ++i)
+ slv2_plugin_free(raptor_sequence_get_at(world->plugins, i));
+ raptor_free_sequence(world->plugins);
world->plugins = NULL;
librdf_free_parser(world->parser);
@@ -78,7 +80,25 @@ slv2_world_free(SLV2World world)
}
-/* private */
+void
+slv2_world_load_bundle(SLV2World world, const char* bundle_uri_str)
+{
+ librdf_uri* bundle_uri = librdf_new_uri(world->world,
+ (const unsigned char*)bundle_uri_str);
+
+ librdf_uri* manifest_uri = librdf_new_uri_relative_to_base(
+ bundle_uri, (const unsigned char*)"manifest.ttl");
+
+ librdf_parser_parse_into_model(world->parser, manifest_uri, NULL, world->model);
+
+ librdf_free_uri(manifest_uri);
+ librdf_free_uri(bundle_uri);
+}
+
+
+/** Load all bundles under a directory.
+ * Private.
+ */
void
slv2_world_load_directory(SLV2World world, const char* dir)
{
@@ -91,24 +111,17 @@ slv2_world_load_directory(SLV2World world, const char* dir)
if (!strcmp(pfile->d_name, ".") || !strcmp(pfile->d_name, ".."))
continue;
- char* bundle_uri_str = slv2_strjoin("file://", dir, "/", pfile->d_name, "/", NULL);
- librdf_uri* bundle_uri = librdf_new_uri(world->world, (unsigned char*)bundle_uri_str);
+ char* uri = slv2_strjoin("file://", dir, "/", pfile->d_name, "/", NULL);
- DIR* bundle_dir = opendir(bundle_uri_str + 7);
+ // FIXME: Probably a better way to check if a dir exists
+ DIR* bundle_dir = opendir(uri + 7);
if (bundle_dir != NULL) {
closedir(bundle_dir);
-
- librdf_uri* manifest_uri = librdf_new_uri_relative_to_base(
- bundle_uri, (const unsigned char*)"manifest.ttl");
-
- librdf_parser_parse_into_model(world->parser, manifest_uri, NULL, world->model);
-
- librdf_free_uri(manifest_uri);
+ slv2_world_load_bundle(world, uri);
}
- free(bundle_uri_str);
- librdf_free_uri(bundle_uri);
+ free(uri);
}
closedir(pdir);
@@ -155,7 +168,8 @@ slv2_world_load_all(SLV2World world)
{
char* lv2_path = getenv("LV2_PATH");
- // Read all manifest files
+ /* 1. Read all manifest files into model */
+
if (lv2_path) {
slv2_world_load_path(world, lv2_path);
} else {
@@ -171,6 +185,8 @@ slv2_world_load_all(SLV2World world)
}
+ /* 2. Query out things to cache */
+
// Find all plugins and associated data files
unsigned char* query_string = (unsigned char*)
"PREFIX : <http://lv2plug.in/ontology#>\n"
@@ -205,7 +221,8 @@ slv2_world_load_all(SLV2World world)
plugin->world = world;
// FIXME: check for duplicates
- raptor_sequence_push(plugin->data_uris, librdf_new_uri_from_uri(data_uri));
+ raptor_sequence_push(plugin->data_uris,
+ strdup((const char*)librdf_uri_as_string(data_uri)));
raptor_sequence_push(world->plugins, plugin);
@@ -267,16 +284,14 @@ slv2_world_get_all_plugins(SLV2World world)
SLV2Plugins
slv2_world_get_plugins_by_filter(SLV2World world, bool (*include)(SLV2Plugin))
{
- SLV2Plugins all = slv2_world_get_all_plugins(world);
SLV2Plugins result = slv2_plugins_new();
- for (int i=0; i < raptor_sequence_size(all); ++i) {
- SLV2Plugin p = raptor_sequence_get_at(all, i);
+ for (int i=0; i < raptor_sequence_size(world->plugins); ++i) {
+ SLV2Plugin p = raptor_sequence_get_at(world->plugins, i);
if (include(p))
- raptor_sequence_push(result, slv2_plugin_duplicate(p));
+ raptor_sequence_push(result, p);
}
- slv2_plugins_free(all);
return result;
}
diff --git a/utils/lv2_inspect.c b/utils/lv2_inspect.c
index a6a949d..710b791 100644
--- a/utils/lv2_inspect.c
+++ b/utils/lv2_inspect.c
@@ -20,8 +20,6 @@
#include <stdio.h>
#include <slv2/slv2.h>
-// FIXME: remove
-#include "../src/private_types.h"
void
print_port(SLV2Plugin p, uint32_t index)
@@ -93,41 +91,53 @@ print_plugin(SLV2Plugin p)
{
char* str = NULL;
- printf("<%s>\n", slv2_plugin_get_uri(p));
-
- printf("FIXME: Data URIs\n");
- /*printf("\tData URIs:\n");
- SLV2Strings data_uris = slv2_plugin_get_data_uris(p);
- for (unsigned i=0; i < slv2_strings_size(data_uris); ++i)
- printf("\t\t%s\n", slv2_strings_get_at(data_uris, i));
- */
-
- printf("\n\tLibrary URI: %s\n\n", slv2_plugin_get_library_uri(p));
-
+ printf("<%s>\n\n", slv2_plugin_get_uri(p));
+
str = slv2_plugin_get_name(p);
- printf("\tName: %s\n", str);
+ printf("\tName: %s\n\n", str);
free(str);
if (slv2_plugin_has_latency(p))
- printf("\tHas latency: yes\n");
+ printf("\tHas latency: yes\n\n");
else
- printf("\tHas latency: no\n");
+ printf("\tHas latency: no\n\n");
+
+ printf("\tBinary: %s\n\n", slv2_plugin_get_library_uri(p));
+
+ printf("\tData URIs:\n");
+ SLV2Strings data_uris = slv2_plugin_get_data_uris(p);
+ for (unsigned i=0; i < slv2_strings_size(data_uris); ++i)
+ printf("\t\t%s\n", slv2_strings_get_at(data_uris, i));
+
+ /* Properties */
- printf("\tProperties:\n");
SLV2Strings v = slv2_plugin_get_properties(p);
+
+ if (slv2_strings_size(v) > 0)
+ printf("\n\tProperties:\n");
+
for (unsigned i=0; i < slv2_strings_size(v); ++i)
printf("\t\t%s\n", slv2_strings_get_at(v, i));
slv2_strings_free(v);
- printf("\tHints:\n");
+
+ /* Hints */
+
v = slv2_plugin_get_hints(p);
+
+ if (slv2_strings_size(v) > 0)
+ printf("\n\tHints:\n");
+
for (unsigned i=0; i < slv2_strings_size(v); ++i)
printf("\t\t%s\n", slv2_strings_get_at(v, i));
slv2_strings_free(v);
+
+ /* Ports */
+
uint32_t num_ports = slv2_plugin_get_num_ports(p);
- printf("\n\t# Ports: %d\n", num_ports);
+ //printf("\n\t# Ports: %d\n", num_ports);
for (uint32_t i=0; i < num_ports; ++i)
print_port(p, i);
@@ -157,7 +167,7 @@ main(int argc, char** argv)
return -1;
}
- slv2_plugins_free(plugins);
+ slv2_plugins_free(world, plugins);
slv2_world_free(world);
return (p != NULL ? 0 : -1);
diff --git a/utils/lv2_list.c b/utils/lv2_list.c
index 56afe4a..3e62c24 100644
--- a/utils/lv2_list.c
+++ b/utils/lv2_list.c
@@ -40,7 +40,7 @@ main()//int argc, char** argv)
list_plugins(plugins);
- slv2_plugins_free(plugins);
+ slv2_plugins_free(world, plugins);
slv2_world_free(world);
return 0;