diff options
Diffstat (limited to 'doc/c')
-rw-r--r-- | doc/c/Doxyfile | 26 | ||||
-rw-r--r-- | doc/c/index.rst | 10 | ||||
-rw-r--r-- | doc/c/overview.rst | 18 | ||||
-rw-r--r-- | doc/c/plugins.rst | 90 | ||||
-rw-r--r-- | doc/c/uis.rst | 21 | ||||
-rw-r--r-- | doc/c/world.rst | 153 | ||||
-rw-r--r-- | doc/c/wscript | 43 |
7 files changed, 361 insertions, 0 deletions
diff --git a/doc/c/Doxyfile b/doc/c/Doxyfile new file mode 100644 index 0000000..ce10524 --- /dev/null +++ b/doc/c/Doxyfile @@ -0,0 +1,26 @@ +PROJECT_NAME = Lilv +PROJECT_BRIEF = "A library for simple use of LV2 plugins" + +QUIET = YES +WARN_AS_ERROR = NO +WARN_IF_UNDOCUMENTED = NO +WARN_NO_PARAMDOC = NO + +JAVADOC_AUTOBRIEF = YES + +CASE_SENSE_NAMES = YES +HIDE_IN_BODY_DOCS = YES +REFERENCES_LINK_SOURCE = NO + +GENERATE_HTML = NO +GENERATE_LATEX = NO +GENERATE_XML = YES +XML_PROGRAMLISTING = NO +SHOW_FILES = NO + +MACRO_EXPANSION = YES +PREDEFINED = LILV_API LILV_DEPRECATED + +INPUT = ../../include/lilv/lilv.h + +OUTPUT_DIRECTORY = . diff --git a/doc/c/index.rst b/doc/c/index.rst new file mode 100644 index 0000000..6968981 --- /dev/null +++ b/doc/c/index.rst @@ -0,0 +1,10 @@ +#### +Lilv +#### + +.. include:: summary.rst + +.. toctree:: + + overview + api/lilv diff --git a/doc/c/overview.rst b/doc/c/overview.rst new file mode 100644 index 0000000..6abc123 --- /dev/null +++ b/doc/c/overview.rst @@ -0,0 +1,18 @@ +.. default-domain:: c +.. highlight:: c + +######## +Overview +######## + +The complete API is declared in ``lilv.h``: + +.. code-block:: c + + #include <lilv/lilv.h> + +.. toctree:: + + world + plugins + uis diff --git a/doc/c/plugins.rst b/doc/c/plugins.rst new file mode 100644 index 0000000..3551e08 --- /dev/null +++ b/doc/c/plugins.rst @@ -0,0 +1,90 @@ +.. default-domain:: c +.. highlight:: c + +####### +Plugins +####### + +After bundles are loaded, +all discovered plugins can be accessed via :func:`lilv_world_get_all_plugins`: + +.. code-block:: c + + LilvPlugins* plugins = lilv_world_get_all_plugins(world); + +:struct:`LilvPlugins` is a collection of plugins that can be accessed by index or plugin URI. +The convenicne macro :macro:`LILV_FOREACH` is provided to make iterating over collections simple. +For example, to print the URI of every plugin: + +.. code-block:: c + + LILV_FOREACH (plugins, i, list) { + const LilvPlugin* p = lilv_plugins_get(list, i); + printf("%s\n", lilv_node_as_uri(lilv_plugin_get_uri(p))); + } + } + +More typically, +you want to load a specific plugin, +which can be done with :func:`lilv_plugins_get_by_uri`: + +.. code-block:: c + + LilvNode* plugin_uri = lilv_new_uri(world, "http://example.org/Osc"); + + const LilvPlugin* plugin = lilv_plugins_get_by_uri(list, plugin_uri); + +:struct:`LilvPlugin` has various accessors that can be used to get information about the plugin. +See the :doc:`API reference <api/plugin>` for details. + +********* +Instances +********* + +:struct:`LilvPlugin` only represents the data of the plugin, +it does not load or access the actual plugin code. +To do that, you must instantiate a plugin to create :struct:`LilvInstance`: + +.. code-block:: c + + LilvInstance* instance = lilv_plugin_instantiate(plugin, 48000.0, NULL); + +Connecting Ports +================ + +Before running a plugin instance, its ports must be connected to some data. +This is done with :func:`lilv_instance_connect_port`. +Assuming the plugins has two control input ports and one audio output port, +in that order: + +.. code-block:: c + + float control_in_1 = 0.0f; + float control_in_2 = 0.0f; + + float audio_out[128]; + + lilv_instance_connect_port(instance, 0, &control_in_1); + lilv_instance_connect_port(instance, 1, &control_in_2); + lilv_instance_connect_port(instance, 2, &audio_out); + +Processing Data +=============== + +Once the ports are connected, the instance can be activated and run: + +.. code-block:: c + + lilv_instance_activate(instance); + + lilv_instance_run(instance, 128); + // Copy buffers around and probably run several times here... + + lilv_instance_deactivate(instance); + +Once you are done with an instance, +it can be destroyed with :func:`lilv_instance_free`: + +.. code-block:: c + + lilv_instance_free(instance); diff --git a/doc/c/uis.rst b/doc/c/uis.rst new file mode 100644 index 0000000..cbca8f6 --- /dev/null +++ b/doc/c/uis.rst @@ -0,0 +1,21 @@ +.. default-domain:: c +.. highlight:: c + +############### +User Interfaces +############### + +Plugins may have custom user interfaces, or `UIs`, +which are installed in bundles just like plugins. + +The available UIs for a plugin can be accessed with :func:`lilv_plugin_get_uis`: + +.. code-block:: c + + LilvUIs* uis = lilv_plugin_get_uis(plugin); + +:struct:`LilvUIs` is a collection much like `LilvPlugins`, +except it is of course a set of :struct:`LilvUI` rather than a set of :struct:`LilvPlugin`. +Also like plugins, +the :struct:`LilvUI` class has various accessors that can be used to get information about the UI. +See the :doc:`API reference <api/ui>` for details. diff --git a/doc/c/world.rst b/doc/c/world.rst new file mode 100644 index 0000000..4128f77 --- /dev/null +++ b/doc/c/world.rst @@ -0,0 +1,153 @@ +.. default-domain:: c +.. highlight:: c + +##### +World +##### + +The world is the top-level object which represents an instance of Lilv. +It is used to discover and load LV2 data, +and stores an internal cache of loaded data for fast searching. + +An application typically has a single world, +which is constructed once on startup and used throughout the application's lifetime. + +************ +Construction +************ + +A world must be created before anything else. +A world is created with :func:`lilv_world_new`, for example: + +.. code-block:: c + + LilvWorld* world = lilv_world_new(); + +*************** +Setting Options +*************** + +Various options to control Lilv's behavior can be set with :func:`lilv_world_set_option`. +The currently supported options are :c:macro:`LILV_OPTION_FILTER_LANG`, +:c:macro:`LILV_OPTION_DYN_MANIFEST`, and :c:macro:`LILV_OPTION_LV2_PATH`. + +For example, to set the LV2 path to only load plugins bundled in the application: + +.. code-block:: c + + LilvNode* lv2_path = lilv_new_file_uri(world, NULL, "/myapp/lv2"); + + lilv_world_set_option(world, LILV_OPTION_LV2_PATH, lv2_path); + +************ +Loading Data +************ + +Before using anything, data must be loaded from disk. +All LV2 data (plugins, UIs, specifications, presets, and so on) is installed in `bundles`, +a standard directory format + +Discovering and Loading Bundles +=============================== + +Typical hosts will simply load all bundles in the standard LV2 locations on the system: + +.. code-block:: c + + lilv_world_load_all(world); + +This will discover all bundles on the system, +as well as load the required data defined in any discovered specifications. + +It is also possible to load a specific bundle: + +.. code-block:: c + + LilvNode* bundle_uri = lilv_new_file_uri(world, NULL, "/some/plugin.lv2"); + + lilv_world_load_bundle(world, bundle_uri); + +The LV2 specification itself is also installed in bundles, +so if you are not using :func:`lilv_world_load_all`, +it is necessary to manually load the discovered specification data: + +.. code-block:: c + + lilv_world_load_specifications(world); + lilv_world_load_plugin_classes(world); + +************* +Querying Data +************* + +The world contains a model of all the loaded data in memory which can be queried. + +Data Model +========== + +LV2 data is a set of "statements", +where a statement is a bit like a simple machine-readable sentence. +The "subject" and "object" are as in natural language, +and the "predicate" is like the verb, but more general. + +For example, we could make a statement about a plugin in english: + + MyOsc has the name "Super Oscillator" + +We can break this statement into 3 pieces like so: + +.. list-table:: + :header-rows: 1 + + * - Subject + - Predicate + - Object + * - MyOsc + - has the name + - "My Super Oscillator" + +Statements use URIs to identify things. +In this case, we assume that this plugin has the URI ``http://example.org/Osc``. +The LV2 specification defines that ``http://usefulinc.com/ns/doap#name`` is the property used to describe a plugin's name. +So, this statement is: + +.. list-table:: + :header-rows: 1 + + * - Subject + - Predicate + - Object + * - ``http://example.org/Osc`` + - ``http://usefulinc.com/ns/doap#name`` + - "My Oscillator" + +Finding Values +============== + +Based on this model, you can find all values that match a certain pattern. +Patterns are just statements, +but with ``NULL`` used as a wildcard that matches anything. +So, for example, you can get the name of a plugin using :func:`lilv_world_find_nodes`: + +.. code-block:: c + + LilvNode* plugin_uri = lilv_new_uri(world, "http://example.org/Osc"); + LilvNode* doap_name = lilv_new_uri(world, "http://usefulinc.com/ns/doap#name"); + + LilvNodes* values = lilv_world_find_nodes(world, plugin_uri, doap_name, NULL); + +Note that a set of values is returned, +because some properties may have several values. +When you are only interested in one value, +you can use the simpler :func:`lilv_world_get` instead: + +.. code-block:: c + + LilvNode* value = lilv_world_get(world, plugin_uri, doap_name, NULL); + +If you are only interested if a value exists at all, +use :func:`lilv_world_ask`: + +.. code-block:: c + + bool has_name = lilv_world_ask(world, plugin_uri, doap_name, NULL); diff --git a/doc/c/wscript b/doc/c/wscript new file mode 100644 index 0000000..d515ddf --- /dev/null +++ b/doc/c/wscript @@ -0,0 +1,43 @@ +#!/usr/bin/env python + +def build(bld): + dox_to_sphinx = bld.path.find_node("../../scripts/dox_to_sphinx.py") + index_xml = bld.path.get_bld().make_node("xml/index.xml") + + files = [ + ("../summary.rst", "sphinx/summary.rst"), + ("index.rst", "sphinx/index.rst"), + ("overview.rst", "sphinx/overview.rst"), + ("plugins.rst", "sphinx/plugins.rst"), + ("uis.rst", "sphinx/uis.rst"), + ("world.rst", "sphinx/world.rst"), + ] + + # Run Doxygen to generate XML documentation + bld(features="doxygen", doxyfile="Doxyfile") + + # Substitute variables to make Sphinx configuration file + bld(features="subst", + source="../conf.py.in", + target="sphinx/conf.py", + LILV_VERSION=bld.env.LILV_VERSION) + + # Copy static documentation files to Sphinx build directory + for f in files: + bld(features="subst", is_copy=True, source=f[0], target=f[1]) + + # Generate Sphinx markup from Doxygen XML + bld.add_group() + bld(rule="${PYTHON} " + dox_to_sphinx.abspath() + " -f ${SRC} ${TGT}", + source=index_xml, + target="sphinx/api/") + + doc_dir = bld.env.DOCDIR + "/lilv-%s/" % bld.env.LILV_MAJOR_VERSION + + # Run Sphinx to generate HTML documentation + for builder in ["html", "singlehtml"]: + bld(features="sphinx", + sphinx_source=bld.path.get_bld().make_node("sphinx"), + sphinx_output_format=builder, + sphinx_options=["-E", "-q", "-t", builder], + install_path=doc_dir + "c/%s/" % builder) |