This document shows how to create a single bundle containing a single plugin (see the wiki:Bundle? Definition) using only the core LV2 specification. The reader is assumed to have some experience with basic GNU/Linux development tools for C programming ( GCC,  GNU Make).

The example plugin used in this document is available here.

==Writing the RDF files==

The one file that must exist in every LV2 bundle is <tt>manifest.ttl</tt>. It should list the URIs for the plugins available in the bundle, in this case <tt><nowiki>http:</nowiki>//lv2plug.in/plugins/example_amp</tt>. For every plugin there must be a RDF triple that says that its URI refers to a LV2 plugin. The triple looks like this:

<<nowiki>http:</nowiki>//lv2plug.in/plugins/example_amp> a lv2:Plugin

If there are additional files containing RDF data for this plugin they need to be referenced in <tt>manifest.ttl</tt> using a triple that looks like this:

<<nowiki>http:</nowiki>//lv2plug.in/plugins/example_amp> rdfs:seeAlso <amp.ttl>

assuming that <tt>rdfs:</tt> is defined as a prefix for <tt><nowiki>http:</nowiki>//www.w3.org/2000/01/rdf-schema#</tt>.

You can see the complete <tt>manifest.ttl</tt> file for the plugin here.

A plugin needs to provide more information in its RDF data. The Amp plugin has this information in <tt>amp.ttl</tt>, which looks like this:

@prefix lv2: <<nowiki>http:</nowiki>//lv2plug.in/ns/lv2core#> . @prefix foaf: <<nowiki>http:</nowiki>//xmlns.com/foaf/0.1/> . @prefix doap: <<nowiki>http:</nowiki>//usefulinc.com/ns/doap#> .

<<nowiki>http:</nowiki>//lv2plug.in/plugins/example_amp> a lv2:Plugin ;

doap:name "Simple amplifier" ; doap:licence <<nowiki>http:</nowiki>//usefulinc.com/doap/licenses/gpl> ; lv2:optionalFeature lv2:hardRtCapable ;

lv2:port [

a lv2:InputPort ; a lv2:ControlPort ; lv2:index 0 ; lv2:symbol "gain" ; lv2:name "gain" ; lv2:default 0.0 ; lv2:minimum -90.0 ; lv2:maximum 24.0 ;

] , [

a lv2:AudioPort ; a lv2:InputPort ; lv2:index 1 ; lv2:symbol "in" ; lv2:name "in" ;

] , [

a lv2:AudioPort ; a lv2:OutputPort ; lv2:index 2 ; lv2:symbol "out" ; lv2:name "out" ;

]

.

The line <tt><<nowiki>http:</nowiki>//lv2plug.in/plugins/example_amp> a lv2:Plugin</tt> is not strictly needed since this file will be read together with <tt>manifest.ttl</tt> which already contains that triple, but it doesn't hurt. The following 3 lines say that the plugin is known under the name Simple amplifier, is released under the GNU GPL and is capable of running in a realtime safe host (see the wiki:RDF? Schema Description for more information about Features). <tt>doap:name</tt> and <tt>doap:license</tt> are mandatory properties for an LV2 plugin - if a plugin does not have both of them a host might not load it. The RDF data of a plugin should also have a reference to the shared library that implements the plugin so the host knows where to find it. In this plugin that information is in <tt>manifest.ttl</tt> in the form of the triple <tt><<nowiki>http:</nowiki>//lv2plug.in/plugins/example_amp> lv2:binary <amp.so></tt>, it does not have to be repeated in <tt>amp.ttl</tt>.

The rest of the file describes the plugin's input and output ports. This plugin has one control input port, one audio input port and one audio output port. Every port must have the properties <tt>lv2:index</tt> (a nonnegative integer), <tt>lv2:symbol</tt> (a string that is a valid identifier in the C programming language) and <tt>lv2:name</tt> (a string that can be displayed in the host's user interface). Every port symbol must be unique, and the indices must start at 0 and be contiguous - you can't have a port with index 4 unless you also have ports with indices 3, 2, 1 and 0. The indices will be used in the shared library to identify the ports.

Each port must also have at least one type. Most of the time a port will have two types, one that says what type of data the port will handle (<tt>lv2:AudioPort</tt> and <tt>lv2:ControlPort</tt> are the only such types defined in the core LV2 spec) and one that says if the data should be read or written by the plugin (<tt>lv2:InputPort</tt> and <tt>lv2:OutputPort</tt>).

==Checking your RDF/TTL File==

After you write your RDF file, it's important that you run it through a parser for syntax/integrity checking. Two tools you can use are rapper (part of the raptor-utils package  http://librdf.org/raptor/) and serdi ( http://drobilla.net/software/serd/). You can do syntax checking like this:

$ raptor -g amp.ttl > /dev/null $ serdi amp.ttl > /dev/null

By sending output to /dev/null, all you'll see are the error message.

==Writing the code==

The full source code for the shared library part of the plugin is available in amp.c. Most of it consists of implementations of the mandatory plugin callbacks (see the wiki:C? API documentation). The last function is <tt>lv2_descriptor()</tt>, a function that must be present in all LV2 plugin libraries.

LV2_SYMBOL_EXPORT const LV2_Descriptor *lv2_descriptor(uint32_t index) {

if (!ampDescriptor) init();

switch (index) { case 0:

return ampDescriptor;

default:

return NULL;

}

}

<tt>LV2_SYMBOL_EXPORT</tt> is used to make sure that the function is available to runtime linkers on all platforms. The <tt>index</tt> parameter is an index into a conceptual array of LV2 descriptors, each containing pointers to the callbacks that implement that plugin. In this plugin library there is only one LV2 descriptor so the function returns that descriptor when <tt>index</tt> is 0 and <tt>NULL</tt> otherwise. If the library had contained 2 descriptors it should have returned one of them when <tt>index</tt> was 0, the other when <tt>index</tt> was 1, and <tt>NULL</tt> for any larger values.

==Creating the bundle==

The files <tt>manifest.ttl</tt>, <tt>amp.ttl</tt> and the shared library <tt>amp.so</tt> built from <tt>amp.c</tt> should be placed in an LV2 bundle. However, an LV2 bundle is just a directory with a name ending with <tt>.lv2</tt> and containing a <tt>manifest.ttl</tt>, so we can just build the shared library in the current directory and use that as the bundle. There is a <tt>Makefile</tt> in the directory that does this, just type <tt>make</tt> and Amp-example.lv2 will be a complete LV2 bundle containing one plugin.