Skip to content
Milkii Brewster edited this page Nov 12, 2023 · 489 revisions

Overview

LV2 is a platform-agnostic Free Software plugin specification with a liberal license. It defines a minimal yet extensible C API for plugin code and a format for plugin "bundles". LV2 separates static semantic metadata from code, so information about installed plugins can be discovered without loading any modules or executing any third-party code. A property-centric design combined with audio, control, "control voltage" (audio-rate control), and "atom" message (MIDI/OSC/control/GUI/etc.) ports for plugin control from UIs, other code or the outside world. Extensibility allows almost any feature to be possible within LV2.

"LV2 is what I call a 'click' technology (like LISP or RDF), it seems insane until it "clicks" and you get it. You really need that little enlightenment experience to be able to work with it well (and especially to be able to work on it)." --drobilla.net : Writing an LV2 Book

This is page is a WIP overview of the LV2 standards, bundles and tools available. If you have some information to list, or something is incorrect, please do make a change.

GitHub tags to use or check: lv2, lv2-plugin, lv2-plugins, lv2-host

Donations for drobilla: Github, Patreon

Communications

Development

See also the frameworks section.

Example code

Specification Information

  • LV2 Specifications / Modules API Reference - Reference Documentation for each module/extension.
    • LV2 - git repo, "contains specifications (C headers and Turtle files), documentation generation tools, and example plugins."
    • File List - list and descriptions of header files.
    • lv2specgen - a documentation generator for LV2 specifications.
  • Data Structures - list of data structures with brief descriptions.
  • Data Fields - list of struct and union fields with links to the struct/union documentation for each field.

Core

Turtle metadata

RDF is a very simple yet powerful way to codify information about data and its relations. A chunk of RDF data is essentially an edge-labelled directed graph database. RDF is only an abstract data model, it doesn't have any one particular syntax for text representations. A modern way of representing RDF is the Turtle syntax, and LV2 plugins use this to store metadata in files ending .ttl. The primary data for an LV2 bundle is be in a file called manifest.ttl though further .ttl files can be referenced.

"The main usefulness [of Turtle] for LV2 is within the host. You can easily/quickly find all the plugins with some particular kind of input port and so on." "... just a dumb syntactic veneer for triples." --drobilla

In the example below, first the shortcut/namespace prefixes for the lv2, doap and spdx ontologies are declared. Next, every plugin must have its own URI. Then the 4 following lines declare that this resource is of the type lv2:Plugin, has a shared library with the filename silence.so, is known under the name Silence and is licensed under the GNU GPL 3+. These 4 properties are mandatory for an LV2 plugin - if a plugin does not have all of them a host might not load it.

@prefix lv2:  <http://lv2plug.in/ns/lv2core#>.
@prefix doap: <http://usefulinc.com/ns/doap#>.
@prefix spdx: <http://spdx.org/rdf/terms#>.

<http://example.org/lv2/wikipediaexample/silence>
  a lv2:Plugin;
  lv2:binary <silence.so>;
  doap:name "Silence";
  doap:license spdx:GPL-3.0-or-later;
  rdfs:comment "This is an example plugin that includes an example plugin description."
 
  lv2:port [
    a lv2:AudioPort, lv2:OutputPort;
    lv2:index 0;
    lv2:symbol "output";
    lv2:name "Output";
  ].

The rest of the file describes the plugin's input and output ports. The plugin only above has one single port with the name Output, the symbol output, the index 0 and the types lv2:AudioPort and lv2:OutputPort. Every port must have all these properties, with the rest of the file describing the plugin's input and output ports. Every port symbol must be unique and a valid C identifier, 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.

If the manifest.ttl file contains a lot of data this can hard to manage; instead we can just have the bare minimum in manifest.ttl, so the host knows that this bundle contains that plugin, what the binary is, and a reference to another RDF file that the host can load if it wants to know more about that plugin.

<http://example.org/lv2/wikipediaexample/silence>
    a lv2:Plugin ;
    lv2:binary <silence.so> ;
    rdfs:seeAlso <silence.ttl> .

Translation

Turtle has a syntax for translating values, an example of which can be seen in the noise-repellent ttl;

  doap:name "Noise repellent",
    "Repelente de ruido"@es ,
    "Répulseur de bruit"@fr ;

URI and versioning

A plugin URI is a unique reference to the "form" of ports and abilities that plugin provides. All plugin versions with the same URI are compatible by definition. Replacing a resource with a newer version of that resource MUST NOT break anything. If a change violates this rule, then the URI of the resource (which serves as the major version) MUST be changed.

Binaries

  lv2:binary <silence.so>;

The lv2:binary value of an lv2:Plugin MUST be noted in the bundle's manifest.ttl file and MUST be a URI that resolves to a shared library object containing the lv2_descriptor() or lv2_lib_descriptor() function.

This property may be used similarly by extensions to relate other resources to their implementations.

If multiple binary files are declared, suggested host behaviour is to try and execute each in turn, though this is not official.

Ports

Plugins communicate via "ports", which can transmit any type of data. Data is processed by first "connecting" each port to a buffer, then repeatedly calling a plugin's run() method to process blocks of data.

All LV2 port descriptions MUST have a rdf:type that is one of:

  • lv2:Port
  • lv2:InputPort
  • lv2:OutputPort.

Additionally there MUST be at least one other rdf:type which more precisely describes type of the port:

displayPriority - Indicates how important a port is to controlling the plugin.

Control

A lv2:ControlPort is connected to a pointer to a single value of C type float. This value is fixed and valid for the duration of the call to run(). Thus the "control rate" is determined by the block size, which is controlled by the host (and not necessarily constant).

Audio

lv2:AudioPort - Ports of this type will be connected to an array of length sample_count with elements of C type float.

Audio ports contain arrays with one float element per sample, allowing a block of audio to be processed in a single call to run().

  lv2:port [
    a lv2:AudioPort, lv2:InputPort;
    lv2:index 4;
    lv2:symbol "input_4";
    lv2:name "Mixer Channel 4";
  ].

CV

Control data at audio rate.

A unit can also be noted for hosts to optionally display or calculate with.

  lv2:port [
    a lv2:CVPort, lv2:InputPort;
    lv2:index 1;
    lv2:symbol "osc1_freq";
    lv2:name "Osc A Freq";
	lv2:maximum "0"
    lv2:maximum "20000"
    units:unit   units:hz
  ].

N.b. the older AMS LV2 modules use a float between 0 and 1 and -1 and 1, and the newer MOD Devices LV2 modules use a float in a range from 10 down to -10 (to represent Eurorack voltage).

The MOD Devices vocabulary notes it's requirements: "Ports with the type mod:CVPort MUST define their minimum and maximum values. and those need to be within the possible 3 cases: - Unipolar mode (minimum: -10, maximum: 0), Bipolar mode (minimum: -5, maximum: +5), + Unipolar mode (minimum: 0, maximum: +10).

Atom

Here is an example of an Atom that contains every currently defined Atom type, serialised to Turtle by sratom:

[]
    rdf:value [
        a eg:Object ;
        eg:one "1"^^xsd:int ;
        eg:two "2"^^xsd:long ;
        eg:three "3.0"^^xsd:float ;
        eg:four "4.0"^^xsd:double ;
        eg:true true ;
        eg:false false ;
        eg:path </foo/bar> ;
        eg:uri eg:value ;
        eg:urid eg:value ;
        eg:string "hello" ;
        eg:langlit "bonjour"@fra ;
        eg:typelit "value"^^eg:Type ;
        eg:blank [
            a eg:Object ;
        ] ;
        eg:tuple [
            a atom:Tuple ;
            rdf:value (
                "foo"
                true
            ) ;
        ] ;
        eg:vector [
            a atom:Vector ;
            rdf:value (
                "1"^^xsd:int
                "2"^^xsd:int
                "3"^^xsd:int
                "4"^^xsd:int
            ) ;
        ] ;
  ].

Examples of AtomSequences for plugin <-> UI communication:

  • EQ10Q equalizer
  • x42 Sisco oscilliscope

Tools and guides:

MIDI

MIDI is done with the atom extension coupled with just MIDI raw bytes, the same way you use { 0x90, 64, 100 } etc.

The midigate plugin can be useful as a reference.

In particular:

  1. you add in a port as "atom sequence" (which is basically a buffered sequence of atoms, 64bit aligned):

    const LV2_Atom_Sequence* control;

  2. you parse through the atom events during run/process, and handle those that have a "MidiEvent" tag:

  LV2_ATOM_SEQUENCE_FOREACH (self->control, ev) {
    if (ev->body.type == self->uris.midi_MidiEvent) {
      const uint8_t* const msg = (const uint8_t*)(ev + 1);
      switch (lv2_midi_message_type(msg)) {
      case LV2_MIDI_MSG_NOTE_ON:
        ++self->n_active_notes;
        break;
      case LV2_MIDI_MSG_NOTE_OFF:
        if (self->n_active_notes > 0) {
          --self->n_active_notes;
        }
        break;
...

Those midi utility functions come from https://github.com/lv2/lv2/blob/master/lv2/midi/midi.h but you don't need to use them of course, just makes things a bit more convenient for new plugins.

Here is an example of MIDI atoms, serialised to Turtle by sratom:

[]
    rdf:value [
        eg:seq [
            a atom:Sequence ;
            rdf:value (
                [
                    atom:frameTime 1 ;
                    rdf:value "901A01"^^midi:MidiEvent ;
                ] [
                    atom:frameTime 3 ;
                    rdf:value "902B02"^^midi:MidiEvent ;
                ]
            ) ;
        ] ;
    ] .

MPE & Note Expression

No-one has yet released work on relaying MPE or Note Expression information between hosts and plugins.

MIDI 2.0

  • https://github.com/atsushieno/lv2-midi2 - "experimental attempt to extend LV2 to add support for MIDI 2.0, which would look like existing MIDI 1.0 support through Atom. There is not of much implementation within this extension feature itself. It resembles how the existing MIDI 1.0 support is done. In LV2, most of the existing work (packet processing) is done through LV2 Atom API. So far I have imported my cmidi2 library (which is also experimental UMP processing library) to make it possible for LV2 developers."

OSC

Groups

Morph

"nobody cares about Morph and it's not in a state that really belongs in the "recommended standard" list (sorry, flagrant abuse of power on my part there)" --drobilla

MIDNAM

URID

State

Units

Time

UI

Avoid GUI frameworks

"I wouldn't say general GUI frameworks are inherently not suitable for plugins, but virtually all of them (in particular Gtk and Qt) aren't because of the [below] problems. (Some of which, in some cases, are sort of surmountable, maybe, but that's sort of beside the point)" --drobilla, #lv2, July 20

"1) meshing with the event loop of the host, 2) global state, 3) dynamic linker conflicts. "general purpose" UI toolkits own the whole application event loop by default and it's extra legwork to make them work with the host having its own already. When you add to the fact that there's no "de facto" cross-toolkit event loop on linux the way there is on windows or macos, you end up with something like suil which has to handle the messy details of specific combinations of plugin/host toolkit interop" --wrl, #lv2, July 20

"Please avoid big toolkits and be careful with C++

"gtk2 + gtk3 cannot exist in the same memory-space, likewise Qt4 + Qt5. This means a gtk2 host cannot load plugins with a gtk3 GUI, nor can you load a Qt4 plugin at the same time as plugin using a Qt5 GUI.

"While gtk and Qt allows for nicely portable applications, that is definitely not true for plugin GUIs. fltk is not trivial either. There are all sorts of edge-cases: e.g. relocating the library (dependent paths, modules), static initialization/unloading and ABI compatibility...

"The latter also extends to dependencies direct or indirect. A recent example is sigc++ gcc4/gcc5 ABI incompatibility (gtkmm uses sigc++)."

Libraries

Related to plugins:

Other projects:

File dialogs

Drag & drop

Testing

VST wrappers

Processing

Worker

"This extension allows plugins to schedule work that must be performed in another thread. Plugins can use this interface to safely perform work that is not real-time safe, and receive the result in the run context. The details of threading are managed by the host, allowing plugins to be simple and portable while using resources more efficiently."

Thread

Instance / Data Access

"the Data Access and Instance Access extensions are really just parts of the same thing and should live together" --drobilla

Dynamic Manifest

  • Dynamic Manifest - write plugin libraries where data is dynamically generated at runtime (e.g. API wrappers).

"The LV2 API, on its own, cannot be used to write plugin libraries where data is dynamically generated at runtime (e.g. API wrappers), since LV2 requires needed information to be provided in one or more static data (RDF) files. This API addresses this limitation by extending the LV2 API."

"it's a pretty ugly solution, and the caveats of using it currently aren't very clear." --drobilla

Extending the official specs

Usually if something is really interesting it ends up becoming official. That was the case with for example lv2:enabled, a designation we can place on control ports so the plugin can know it is under "bypass" mode, and more lately, properties were added for UIs; ui:scaleFactor, ui:foregroundColor and ui:backgroundColor. A few hosts already had support for these before they became official spec.

Further host extensions

Further extensions have been implemented by one or more hosts.

Ingen

Ingen Configuration

  • Ingen - Ingen is a modular audio processing environment. This vocabulary describes an Ingen configuration, and is used in both the control protocol and saved files. Conceptually, Ingen represents a tree of objects, each of which has a path (like /main/in or /main/osc/out) and a set of properties.

A basic audio thru example. Also used by MOD Devices to save 'Pedalboard' session graphs for sharing online.

Ardour / Harrison Consoles

Ardour MIDI Bank/Patch Notifications

Ardour Self-Automation

Ardour Plugin-provided bypass

  • Plugin-provided bypass - A port with the designation "processing#enable" must control a plugin's internal bypass mode.

Ardour Plugin port/routing control

Harrison Consoles Inline-Display

Harrison Consoles License-Report

KXStudio

KXStudio External UI

KXStudio Control Input Port Change Request

KXStudio Programs

"the program stuff I should leave a note to not use" --falktx

KXStudio Realtime-Safe Memory Pool

"rtmempool is something only ever used in zynadd, another dead project" --falktx

Open Music Kontrollers

Canvas.lv2

MOD

  • MOD - properties for describing MOD Devices related data.

"This is a vocabulary for describing extra plugin data specific to MOD software and devices."

MOD-GUI

  • MOD GUI - In MOD Devices, every plugin has a real pedal like representation in a web based environment, with several plugins in a pedalboard. For this, each plugin must have its html code that allows the browser to properly render it.

The SDK's goal is to allow LV2 plugin developers to implement the MOD Graphical User Interface extension using a template wizard to easily create a plugin GUI without the need to write any line of code, test the plugins and deploy them into a MOD device.

  • https://wiki.moddevices.com/wiki/Preparing_the_Bundle - In this page you will learn how to add the features of the MODGUI extension to an existing LV2 plugin bundle. This is a very mechanical procedure and all you need to know is how to edit some text files in a plain text editor, such as notepad. No programming skills are needed.

MOD-HMI Widgets

Libraries

C

  • lv2kit - Meta-repository for building all LV2 libraries at once
  • Sord - lightweight C library for storing RDF data in memory.
  • Serd - lightweight C library for RDF syntax which supports reading and writing Turtle, TRiG, NTriples, and NQuads.
  • props.lv2 - utility header for property based LV2 plugins.

C++

Rust

Go

Python

ECL Common Lisp

Pure

Zig

Frameworks

Utilities

  • lv2ls - list all LV2 plugins installed locally.
    • To output plugin uri and name together; IFS=$'\n' arr=($(lv2ls)) && IFS=$'\n' arr2=($(lv2ls -n)) && for (( i=0; i<${#arr[*]}; ++i)); do printf "%s %s\n" "${arr[$i]}" "${arr2[$i]}"; done
  • lv2info - print information about an installed LV2 plugin.
  • lv_plugin_uris.py - print URIs associated with an LV2 plugin

Presets

Development

Testing

  • sord_validate - Validate RDF data, checks that all used properties are actually defined, and that the domain and range of properties is explicitly correct. Given an appropriate schema, this is enough to validate against most of the standard XSD datatypes.
  • lv2lint - check whether a given LV2 plugin is up to the specification. for uri in $(lv2ls | grep example.org/lv2/plugin); do lv2lint $uri; done
  • lv2-plugin-checker - outputs basic plugin information.
  • Torture tester - a program to help with testing of LADSPA and LV2 plugins.
  • falkTX/lv2-state-test - A simple and dumb lv2 plugin to test host state support.

Benchmarking

Audio

MIDI

LV2 hosts

Libraries

C

C++

C#

Rust

OCaml

Pure

Standalone hosts

Audio processing tools

Graph & rack routing

DAW / 'groovebox'

  • Ardour - DAW. Record, Edit, and Mix on Linux, macOS and Windows.
  • Qtractor - an Audio/MIDI multi-track sequencer application written in C++ with the Qt framework.
  • MusE - a MIDI/Audio sequencer with recording and editing capabilities.
  • LMMS - Lv2 extension plan - support in progress
  • Zrythm - a highly automated and intuitive digital audio workstation
  • Traverso-DAW - a digital audio workstation designed to be an extension of your creativity and workflow.
  • Harrison-Mixbus - a full-featured digital audio workstation for recording, editing, mixing, and mastering your music.
  • Advanced Gtk+ Sequencer - play, capture and create music, with MIDI, piano roll, automation and wave form editor, sampler, soundfonts and virtual instruments.
  • REAPER - multitrack audio and MIDI recording, editing, processing, mixing and mastering toolset.
  • Any DAW that supports VST2 by using Carla as a plugin.
  • Any DAW that supports VST2 by using x42/lv2vst.
  • Any DAW that supports VST2/VST3/AU/AAX by using Element as a plugin.

DJing

Audio & video processing

Windows

Windows hosts include Ardour, Mixbus, Carla and Ingen (no-precompiled binary). Possibly Audacity.

Android

Hardware

LV2 plugins

These lists are not exhaustive.

Collections and listings

Precompiled LV2 plugins for Windows and macOS are available from DISTRHO, Zam, x42 (trial), Open Music Kontrollers, and come bundled with Carla, Ardour, as well as the non-free XT plugins with Harrison Mixbus.

Tools

Clock & tempo

Synthesis

Modular

See the JACK/LV2 CV thread on LinuxMusicians.com for more details.

Subtractive

Additive

Wavetable

Multimode

  • ZynAddSubFX - fully featured open source software synthesizer.
  • Yoshimi - a software audio synthesizer, originally forked from ZynAddSubFX.
  • Helm - polyphonic synth with lots of modulation.
  • Surge - previously sold as a commercial product, very powerful.
  • timowest/rogue - multimode softsynth.

FM

Chiptune

Organ

Modelled

Granular

Various / to sort

Drum synth

Test signal

Metronome

Sampler

  • live-cue - for triggering long samples.
  • handrumr.lv2 - config stored as JSON.
  • samplv1 - an old-school all-digital polyphonic sampler synthesizer with stereo fx.
  • drumkv1 - an old-school all-digital drum-kit sampler synthesizer with stereo fx.
  • openAV-Fabla - drum sampler plugin instrument.
  • ninjas2 - rewrite of Ninjas sample slicer.
  • beatslash-lv2 (has CV support)

Sample banks

Looping

MIDI

Sequencer

Volume & mixers

Metering & visuals

Recording

Processing & FX

Simulation

Compression etc.

Equalisation

Gate

Denoise

Reverb

Convolution

  • Anchakor/ir.lv2 - impulse response (convolution) plugin (for reverb and cabinet simulation).
  • x42 Convo.lv2 - no frills zero latency convolution engine (deprecated).
  • x42 Zeroconvo.lv2 - two variants: zero configuration options (IRs are only available via presets), zero latency and user-loadable IRs with gain controls.
  • polyeffects/polyconvo.lv2 - zeroconvolv2 to allow patch file setting and gain control

Delay

Sound retainer

Chorus

Distortion, bitcrush etc.

Pitch shifting

Feature detection

Streaming

Packaging

  • DebianMultimedia/Policy/LV2 - Debian Wiki - describes the packaging of LV2 core specification within the Debian GNU/Linux distribution and the policy requirements for packaged LV2 hosts, plugins and extensions.

Related information

History

From late 2006, nedko worked on probably the first (now defunct) LV2 host zynjacku and the (also defunct) zynadd.lv2 plugin. ll-plugins were one of the very first plugins, with its custom MIDI spec. Ardour, Carla and Ingen are the oldest hosts that are still actively developed today. The LV2core documentation was first published 2008-02-10, LV2 "version 8", aka 1.0.0. The pre-Git SVN history was not migrated.

Other

Issues / disadvantages?

  • The examples still use GTK which is not recommended these days
  • No changing number of ports after starting an LV2 plugin
  • No control ramp extension (yet)
  • The order that hosts handle multiple plugin UIs is undefined
  • User directory is $HOME/.lv2, not $HOME/.local/lib/lv2
  • Turtle, though very human-readable compared to XML, still puts some developers off. JSON-LD may be a way to make things more familiar without any deep breakage of the LV2 ecosystem.
  • Most plugins don't maintain a Turtle web presence for their uri., so data isn't "Linked" like the semantic web
  • Differing host UX affects how plugins develop. Some routing graphs show control ports, some don't
  • There exist differing conventions regarding CV normalisation (AMS vs MOD)
  • Relational/semantic aspect of plugin metadata isn't leveraged (use of properties like minimum, maximum and unit)
Clone this wiki locally