aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/lv2_plugin_guide/guide.adoc130
1 files changed, 50 insertions, 80 deletions
diff --git a/doc/lv2_plugin_guide/guide.adoc b/doc/lv2_plugin_guide/guide.adoc
index eb64657..c59f346 100644
--- a/doc/lv2_plugin_guide/guide.adoc
+++ b/doc/lv2_plugin_guide/guide.adoc
@@ -2,7 +2,7 @@ Programming LV2 Plugins
=======================
:toc:
:source-highlighter: pygments
-
+:pygments-style: friendly
Introduction
------------
@@ -26,7 +26,7 @@ provides basic .ttl file information
A MIDI gate:: Shows midi processing, introduces LV2 atoms, introduces LV2
extension API
Fifths:: A more complex MIDI processor, explains ??? LV2 concept
-Metromome:: Explores timining information, explains ??? LV2 concept
+Metronome:: Explores timining information, explains ??? LV2 concept
A trivial sampler:: Provides a MIDI waveform sampler, introduces the LV2 worker
extension and extensions in general
A GUI oscilloscope:: Discusses user interfaces in the context of the LV2
@@ -36,7 +36,7 @@ This manual encourages users to jump around, but recommends reading the LV2
asides in each chapter in order to best understand how the LV2 specific
concepts relate to each other.
-Building a basic amplifier
+Building a Basic Amplifier
--------------------------
In this example we're going to build a simple amplifier plugin.
@@ -64,12 +64,11 @@ Let's start off by including the core LV2 header.
[source,c]
--------------------------------------------------------------------------------
-#include <lv2/lv2plug.in/ns/lv2core/lv2.h>
+#include <lv2/core/lv2.h>
--------------------------------------------------------------------------------
-The include path of LV2 headers reflect the URI of the specification they are a part of by design.
-This makes it easy to find detailed information about the API.
-This header is part of the "core" LV2 specification: http://lv2plug.in/ns/lv2core.
+LV2 has many "extensions" each with their own headers.
+This simple plugin uses only `lv2.h` from the "core" LV2 specification, http://lv2plug.in/ns/lv2core.
LV2 plugins are are responsible for keeping track of what ports they have and what host-controlled data structures they're attached to.
In our simple amplifier, these are the only variables stored in the plugin structure:
@@ -87,27 +86,12 @@ include::../../plugins/eg-amp.lv2/amp.c[tags=PortIndex]
----
With the data for our amplifier set up we need to implement the functions needed
-for the host to communicate with our plugin.
-These functions are summarized in the link:http://lv2plug.in/doc/html/group__lv2core.html#structLV2&lowbar;_Descriptor[LV2_Descriptor] which is passed to a
-host and it includes:
-
-//More details in later examples
-// Actually the LV2 spec for these should have a bunch more detail on each,
-// though perhaps it should still be integrated
-
-instantiate:: Allocate and initialize the plugin.
-connect_port:: Connect a port to a host-provided buffer.
-activate:: Reset the plugin to a default state and prepare it to run.
-run:: Process data for a given number of samples.
-deactivate:: Stop the plugin from running (counterpart to activate).
-cleanup:: Free plugin (counterpart to instantiate).
-extension_data:: Get data defined by LV2 extensions.
+for the host to communicate with it.
+These functions will end up in the link:http://lv2plug.in/doc/html/group__lv2core.html#structLV2&lowbar;_Descriptor[LV2_Descriptor]
+which is accessed by the host.
This plugin does not need the `activate`, `deactivate`, or `extension_data` functions, which are optional and do not need to be defined if they are not needed.
-
-NOTE:: For this simple plugin we don't really need to care about when each one
-of these callbacks can be called. For more detailed information about what
-guarantees you have for when each callback may be invoked see XXX
+That leaves `instantiate`, `connect_port`, `run`, and `cleanup`.
Since this plugin contains minimal state, the `instantiate` and `cleanup` functions simply allocate and free the `Amp` structure:
@@ -121,96 +105,82 @@ include::../../plugins/eg-amp.lv2/amp.c[tags=instantiate]
include::../../plugins/eg-amp.lv2/amp.c[tags=cleanup]
--------------------------------------------------------------------------------
-Connecting ports provided by the LV2 host is somewhat more complex.
-Each call from the host will provide a pointer to a buffer for one of the ports.
-The plugin will need to store that pointer and either read from it or write to
-it depending upon if it's an input or an output.
+Connecting ports provided by the host is a bit more involved.
+The host will provide a pointer to a buffer for one of the ports by calling `connect_port`.
+The plugin needs to store that pointer for use while it is running.
[source,c]
----
include::../../plugins/eg-amp.lv2/amp.c[tags=connect_port]
----
-After the host has connected data to each one of the ports and activated the
-plugin then the amplfier LV2 plugin can run for a number of samples.
+After the host has connected data to each one of the ports and activated the plugin,
+the plugin is ready to process audio.
+This is done by the `run()` function, which is called repeatedly for blocks of samples:
[source,c]
----
include::../../plugins/eg-amp.lv2/amp.c[tags=run]
----
-All that's left is providing the host with a descriptor containing pointers to
-all of these functions.
-Since multiple LV2 plugins can be contained in the same shared library this is
-done through the exported lv2_descriptor(link) function:
+Now that we've implemented the core of our plugin,
+all that's left is to provide a descriptor to the host so that it can use the plugin.
+For this, we define an
+link:http://lv2plug.in/doc/html/group__lv2core.html#structLV2&lowbar;_Descriptor[LV2_Descriptor]:
[source,c]
----
include::../../plugins/eg-amp.lv2/amp.c[tags=descriptor]
----
-Part 2: The specification
-~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Now that we have an amplifier plugin setup, you might expect that a host could
-load it and be ready to run.
-The code however doesn't define all of the details.
-For instance the code doesn't provide a list of the inputs and outputs of the
-plugin, so how does the host know about them?
-
-The answer is that LV2 uses data files to store this information.
-
+Then, expose it to the host with the `lv2_descriptor()` function,
+which is the entry point to our library:
-LV2 plugins are defined in two parts: code and data.
-The code is written in C, or any C compatible language such as C++.
-Static data is described separately in the human and machine friendly http://www.w3.org/TeamSubmission/turtle/[Turtle] syntax.
-
-Generally, the goal is to keep code minimal,
-and describe as much as possible in the static data.
-There are several advantages to this approach:
-
- * Hosts can discover and inspect plugins without loading or executing any plugin code.
- * Plugin data can be used from a wide range of generic tools like scripting languages and command line utilities.
- * The standard data model allows the use of existing vocabularies to describe plugins and related information.
- * The language is extensible, so authors may describe any data without requiring changes to the LV2 specification.
- * Labels and documentation are translatable, and available to hosts for display in user interfaces.
+[source,c]
+----
+include::../../plugins/eg-amp.lv2/amp.c[tags=lv2_descriptor]
+----
+Part 2: The data
+~~~~~~~~~~~~~~~~
-A .ttl file maps a collection of properties to values using a collection of
-URLs.
-Now let's build one for the amplifier called 'amp.ttl'
+Now that we have an amplifier plugin written, you might expect that a host could run it.
+However, the code doesn't include all the necessary details.
+For example, the code doesn't provide a list of the inputs and outputs of the plugin,
+so how does the host know about them?
-We can start out by saying that the AMP_URL which we previously defined is 'a'
-plugin:
+For various reasons, this information is provided in a separate data file which describes the plugin.
+Plugins, along with other things in LV2, are described in the human-friendly but machine-readable http://www.w3.org/TeamSubmission/turtle/[Turtle] syntax.
-[source, turtle]
---------------------------------------------------------------------------------
-<http://lv2plug.in/plugins/eg-amp>
- a http://lv2plug.in/ns/lv2core#Plugin .
---------------------------------------------------------------------------------
+A Turtle file describes things as sets of properties.
+If you are familiar with JSON, the basic idea is similar,
+but property keys are URIs rather than arbitrary strings.
-Since we're going to define a number of properties in the LV2 namspace, let's
-define a few macros to condense the file and since we're defining multiple
-properties on our plugin let's use the continuation ';' rather than the property
-terminator '.'.
+First we will define some prefixes for the namespaces we use,
+to keep things nice and readable later on:
[source, turtle]
--------------------------------------------------------------------------------
include::../../plugins/eg-amp.lv2/amp.ttl[tags=prefixes]
--------------------------------------------------------------------------------
-Now we can begin describing our plugin, by first stating that it is 'a' LV2 plugin:
+
+To describe our plugin,
+we can start by saying that our plugin is `a` link:http://lv2plug.in/ns/lv2core#Plugin[Plugin]:
+footnote:[`a` here is a special shorthand for `rdf:type`]
[source, turtle]
--------------------------------------------------------------------------------
<http://lv2plug.in/plugins/eg-amp>
- a lv2:Plugin ;
+ a lv2:Plugin ;
--------------------------------------------------------------------------------
-IMPORTANT: The URI used to identify the plugin in the data must match the one in the code, `AMP_URI` in this example.
+IMPORTANT: The URI used to identify the plugin must match the one in the code,
+`AMP_URI` in this example.
+
+From here we can provide all kinds of information about our plugin,
+such as an associated project, display name, license, and supported features:
-From here we can provide information to what project the plugin is associated
-with, a display name, a license, and even specify features of the plugin:
[source, turtle]
--------------------------------------------------------------------------------
lv2:project <http://lv2plug.in/ns/lv2> ;
@@ -523,7 +493,7 @@ typedef struct {
Now in instantiate we can find the value of the MIDI event URID:
-
+[source,c]
--------------------------------------------------------------------------------
static LV2_Handle
instantiate(const LV2_Descriptor* descriptor,