Overview
Atlassian SourceTree is a free Git and Mercurial client for Windows.
Atlassian SourceTree is a free Git and Mercurial client for Mac.
faust-lv2
Albert Gräf <aggraef@gmail.com>, 2014-02-20
This project provides an LV2 plugin architecture for the Faust programming language. The package contains the Faust architecture and templates for the needed LV2 manifest (ttl) files, a collection of sample plugins written in Faust, and a generic GNU Makefile for compiling the plugins.
faust-lv2 is free and open source software. The latest source can be found in the git repository at https://bitbucket.org/agraef/faust-lv2. In the downloads section of this site you can also find released tarballs along with my faust-lv2 paper for the 2013 Linux Audio Conference. Please use the issue tracker for bug reports and requests. You're also invited to join one of the Faust mailing lists (off-site) to discuss faust-lv2 or Faust in general.
Note: As of Faust 0.9.58, the faust-lv2 architectures are included in the official Faust distribution. (Faust versions up to 0.9.65 still have an older version of the architectures and build scripts, though, so you might want to replace them using make install-faust, see Installation below for details.) Both lv2 and lv2synth are also available as target architectures in the Faust online compiler, so you can compile your favourite Faust dsps as LV2 plugins even without installing the Faust compiler. Please head over to the Faust website to learn more.
Copying
Copyright (c) 2012-2014 by Albert Gräf <aggraef@gmail.com>
This document is available under the GNU Free Documentation License.
faust-lv2 is distributed under the GNU Lesser General Public License v3+. Please see the included COPYING and COPYING.LESSER files for details.
Overview
The aim of this project is to provide a full-featured LV2 implementation of Faust plugins which supports both audio and instrument plugins. Faust is Grame's functional signal processing language. LV2 is the new open-source audio and MIDI plugin standard for Linux and other Unix-like systems, successor of the venerable LADSPA standard.
faust-lv2 is the first (and, at the time of this writing, still the only) LV2 implementation for Faust. It's also the only Faust architecture which provides full support for both effect processors and polyphonic synths with automatic voice allocation in a single package. faust-lv2 thus makes it really easy to create great working LV2 plugins ready to be used in LV2 hosts such as Ardour3 and Qtractor.
The main items in the faust-lv2 package are the Faust architecture files lv2.cpp and lv2synth.cpp which are needed to compile LV2 plugins with the Faust compiler. These are now included in recent Faust versions, but you can also install them from the faust-lv2 package if necessary.
The package also includes some sample Faust dsps in the effects and synths directories, as well as a GNU Makefile and some convenience scripts showing how to automatize the build process.
Supported hosts
LV2 is supported by sequencing and DAW software such as Ardour and Qtractor. Support for Miller Puckette's Pd is available through the author's lv2plugin~ external. Standalone hosts such as jalv can be used to interface with other software which doesn't support LV2 yet, such as Rosegarden.
The current release has been tested and is known to work with jalv, lv2plugin~, Ardour3 (from the Ardour git repository) and Qtractor 0.5.12 and later (including the latest svn versions of Qtractor). We generally recommend using hosts based on Dave Robillard's LV2 host library lilv, which should be readily available in most Linux distributions. All plugin hosts mentioned above will work with this library if it is available on your system.
Please note that faust-lv2 does not support custom plugin GUIs in the current version. This may be provided in the future, but for the time being you'll have to rely on the LV2 host to display a GUI for the control elements. Both Ardour and Qtractor do a reasonably good job at this. However, note that the hierarchical layout of GUI controls prescribed by the Faust source is lost in the generic plugin GUIs provided by LV2 hosts.
Features
Plugins created with lv2.cpp and lv2synth.cpp provide the following basic features:
- Audio inputs and outputs of the Faust dsp are made available as LV2 audio input and output ports.
- Faust controls are made available as LV2 control ports with the proper label, initial value, range and (if supported by the host) step size. Both "active" (input) and "passive" (output) Faust controls are supported and mapped to the corresponding LV2 input and output ports, but note that many LV2 hosts don't provide access to LV2 control output ports (a.k.a. Faust passive controls) at this time.
- If the dsp defines any controls with corresponding MIDI mappings (midi:ctrl attributes in the Faust source), the plugin also provides an LV2 MIDI input port and interprets incoming MIDI controller messages accordingly. (This feature can also be disabled by uncommenting the corresponding option in the Makefile or by resetting the FAUST_MIDICC macro in the architecture files, which may be useful if it gets in the way of the host's own MIDI mapping and automation facilities. Also note that in the lv2synth.cpp architecture certain MIDI controllers have a predefined meaning and hence cannot be assigned using the midi:ctrl attribute, see below.)
- Plugin name, description, author and license information provided as metadata in the Faust source is translated to the corresponding fields in the LV2 manifest of the plugin. (This can also be disabled with the corresponding Makefile option or by resetting the FAUST_META macro in the architecture files, if you'd rather like to provide this information yourself by editing the static manifest.)
The architectures also recognize the following Faust control metadata and set up the LV2 control port properties accordingly. Note that some of these properties rely on extensions which may not be supported by all LV2 hosts. Also note that all of these can be disabled with the corresponding Makefile option. Please refer to the LV2 documentation for a closer description of these options.
The unit attribute (e.g., [unit:Hz]) in the Faust source is translated to a corresponding LV2 unit attribute. The host may then display this information in its GUI rendering of the plugin controls.
LV2 scale points can be set with the lv2:scalePoint (or lv2:scalepoint) attribute on the Faust side. The value of this attribute in the Faust source takes the form of a list of pairs of descriptive labels and corresponding values, for instance:
toggle = button("trigger [lv2:scalepoint on 1 off 0]");The host may then display the given scale points with a descriptive label in its GUI.
The lv2:integer attribute in the Faust source is translated to the lv2:integer LV2 port property, so that the control may be shown as an integer-only field in the host's GUI.
The lv2:hidden or lv2:notOnGUI attribute maps to the LV2 notOnGUI port property, so that hosts honoring this property may suppress the display of this control in their GUI.
In addition, plugins created with lv2synth.cpp provide the necessary logic to drive a polyphonic synth with automatic voice allocation. The desired maximum number of voices can be configured with the corresponding option in the Makefile or by setting the NVOICES macro in the lv2synth.cpp file accordingly. The plugin will manage that many instances of the Faust dsp. The actual number of voices can be changed dynamically from 1 to NVOICES with a special Polyphony control provided by the plugin.
This kind of plugin always provides a MIDI input port and interprets incoming MIDI note and pitch bend messages, as well as a number of General MIDI standard controller and sysex messages, as detailed below. By default, the synth units have a pitch bend range of +/- 2 semitones (General MIDI default) and are tuned in equal temperament with A4 at 440 Hz. These defaults can be adjusted as needed using some of the controller and sysex messages described below.
- The "all notes off" (123) and "all sounds off" (120) MIDI controllers stop sounding notes on the corresponding MIDI channel.
- The "all controllers off" (121) MIDI controller resets the current RPN and data entry controllers on the corresponding MIDI channel (see below).
- The registered parameters (RPNs) 0 (pitch bend range), 1 (channel fine tuning) and 2 (channel coarse tuning) can be used to set the pitch bend range and fine/coarse master tuning on the corresponding MIDI channel in the usual way, employing a combination of the RPN (101, 100) and data entry controller pairs (6 and 38, as well as 96 and 97). Please check the MIDI specification for details.
- Universal realtime and non-realtime scale/octave tuning messages following the MIDI Tuning Standard (MTS), Section MIDI Tuning Scale/Octave Extensions, can be used to set the synth to a given octave-based tuning specified as cent offsets relative to equal temperament, which is repeated in every octave of the MIDI note range 0..127. Please check MTS Support below for further details.
MTS Support
The general format of the supported MTS messages is as follows (using hexadecimal notation):
f0 7f/7e <device-id> 08 08/09 bb bb bb tt ... tt f7
Note that the f0 7f and f0 7e headers are used to denote a universal realtime and non-realtime sysex message, respectively, and the final f7 byte terminates the message. Both types of messages will take effect immediately, but the realtime form will also change the frequencies of already sounding notes. The device id can be any 7-bit value from 00 to 7f and will be ignored, so that the unit will always respond to these messages, no matter which device id is specified. The following 08 id denotes an MTS message, followed either by the 08 subid to denote 1-byte, or the 09 subid to denote 2-byte encoding (see below).
The lv2synth.cpp architecture keeps track of separate tunings for different MIDI channels. The three bb bytes together specify the bitmask of MIDI channels the message applies to, most significant byte first; the bitmask 03 7f 7f thus sets the tuning for all MIDI channels, while the bitmask 00 00 01 only affects the tuning of the first MIDI channel. (Note that bits 3..7 of the most significant byte aren't used right now, but are reserved by MTS for future use, so you shouldn't set these unless you know what you're doing.)
The tt bytes specify the tuning itself, as a sequence of 12 tuning offsets for the notes C, C#, D, etc., thru B. In the one-byte encoding (subid 08), each tuning offset is a 7 bit value in the range 00..7f, with 00, 40 and 7f denoting -64, 0 and +63 cents, respectively. Thus equal temperament is specified using twelve 40 bytes, and a quarter comma meantone tuning could be denoted, e.g., as 4a 32 43 55 3d 4e 36 47 2f 40 51 39. The two-byte encoding (subid 09) works in a similar fashion, but provides both an extended range and better resolution. Here each tuning offset is specified as a 14 bit value encoded as two data bytes (most significant byte first), mapping the range 0..16384 to -100..+100 cents with the center value 8192 (40 00) denoting 0 cents. Please check the MMA's MIDI Tuning Standard document for details.
Dynamic Manifests
Plugins created with lv2.cpp and lv2synth.cpp also support the dynamic manifest extension, so that all requisite information about the plugin's name, author, ports, etc. can be included in the plugin module itself. (To provide better compatibility with current LV2 hosts, which usually don't have this extension enabled, this feature isn't used by default in the provided Makefile. But you can select it by uncommenting the corresponding option in the Makefile, see the corresponding remarks under Static and dynamic manifests for details.)
Build requirements
To compile this package (or any Faust source using the included LV2 architecture files), you'll need GNU make, the GNU C++ compiler and the Boost headers, as well as recent versions of the Faust compiler and LV2. Faust version 0.9.65 (as well as 2.0.a13 from the Faust2 branch) and LV2 1.8 have been tested with the latest release and are known to work. (Older Faust versions >= 0.9.58 and LV2 versions >= 1.0 probably work as well, but might require some fiddling with the sources.)
Installation
Please review the build requirements above and check that you have all the necessary third-party software installed.
To compile the sample Faust plugins, simply run make in the source directory. The compiled LV2 plugins will end up in the lv2/faust.lv2 directory, ready to be run with your favourite LV2 host.
You can also run make install to install the the sample plugins in the system-wide LV2 directory (/usr/local/lib/lv2). (You need to do this as root, e.g., via sudo, if you're installing into system directories. Package maintainers can add something like DESTDIR=/buildroot and prefix=/usr to the make install command to install into a staging directory and change the installation prefix.)
The installation step is optional. If you just want to try the plugins with your favourite LV2 host after compilation, it should be enough to set your LV2_PATH environment variable (or configure your LV2 host) so that the host includes the generated faust-lv2/lv2 directory in its LV2 plugin search path.
There are a number of compilation options which can be changed by setting the appropriate variables in the Makefile, please check the Makefile for details. In particular, the installation prefix can be changed with the prefix variable, and you can also use the lv2libdir variable to set the LV2 installation path in a direct fashion. In addition, you can change the default name faust.lv2 of the plugin directory with the bundledir variable. Moreover, it is possible to build and install the plugins in separate bundles (one per plugin) by running make with the following targets:
make split-bundles make install-split
The plugins will then be found in separate directories named after the plugin (amp.lv2 for the amp.dsp plugin etc.) so that you can also cherrypick the plugins that you want.
For your convenience, we have also included the faust2lv2 and faust2lv2synth scripts from the Faust distribution. If necessary, you can install these along with the lv2.cpp and lv2synth.cpp architecture files over an existing Faust installation with make install-faust (you may have to specify the prefix variable to point the Makefile to the proper Faust installation prefix, usually either /usr or /usr/local). The faust2lv2 and faust2lv2synth scripts don't offer all the options you have when using the Makefile or compiling plugins manually, but they make it very easy to create a self-contained LV2 bundle from a single Faust source, see Using the build scripts below for details.
Static and dynamic manifests
By default, faust-lv2 uses static "manifests" (ttl files generated at compile time, cf. The manifest) for the plugins; this offers the best compatibility with existing LV2 hosts.
It is also possible to compile the plugins for LV2's dynamic manifest extension which allows most of the manifest to be included in the plugin module itself. This is selected by uncommenting the corresponding line reading dyn-manifests = 1 in the Makefile, or by adding dyn-manifests=1 to the make command.
This option considerably speeds up the build process, but requires that the LV2 host supports the dynamic manifest extension. Unfortunately, at present there doesn't seem to be any LV2 host which includes this extension out of the box, hence this isn't the default right now. If you want to go that route, we recommend using hosts based on the lilv library, such as Ardour3 and the latest Qtractor versions. You'll also have to configure lilv with --dyn-manifest when building it in order to enable the dynamic manifest extension.
Using the LV2 architectures in your own Faust programs
Basic usage of the architecture files is as with any other Faust architecture, i.e., you simply specify the architecture that you want with Faust's -a option. E.g., the following creates a plain (audio-only) LV2 plugin from the Faust source:
faust -a lv2.cpp -cn myplugin myplugin.dsp -o myplugin.cpp
Note the use of Faust's -cn (class name) option. This isn't strictly necessary, but it sets a reasonable default for the plugin URI which is used to identify the plugin (see below for a more detailed explanation of this). If you do not specify this option, Faust will use the default class name mydsp.
Likewise, the following command creates a polyphonic synth (instrument) plugin which takes MIDI input and generates audio output:
faust -a lv2synth.cpp -cn mysynth mysynth.dsp -o mysynth.cpp
To make this work, the Faust dsp must be able to function as a monophonic synth which provides controls named freq, gain and gate to set the pitch, velocity and gate of a note, respectively. Voice allocation is then handled automatically in lv2synth.cpp. Please check the Faust sources (.dsp files) in the synths folder included in the distribution for examples which show how to implement such synth units in Faust.
In either case, you should now have the C++ source of the plugin in the current directory. To create an actual LV2 plugin from the C++ source, you'll have to go through the following steps:
- compile the plugin source to a shared module
- create an LV2 "manifest" for the plugin
- create an LV2 "bundle" containing the plugin module and its manifest
These steps can be carried out manually, as explained below, but it's usually better to automatize them with a Makefile or some build scripts. We first discuss the build scripts included in this package which handle the special use case of plugins created from a single Faust source in a very convenient fashion. We then go on to take a closer look at the additional steps required to create a working LV2 bundle, so that you have a good understanding of the build process. This will enable you to handle more complex use cases, diagnose problems, customize scripts and Makefile, and even come up with your own build system if the need arises.
Using the build scripts
The distribution includes two scripts, faust2lv2 and faust2lv2synth, which run the Faust compiler for you and handle all steps necessary to create a working LV2 bundle in an automatic fashion. Using the scripts, you can create an LV2 bundle for an effect or instrument plugin simply as follows:
faust2lv2 myplugin.dsp faust2lv2synth mysynth.dsp
The resulting LV2 bundles myplugin.lv2 and mysynth.lv2 will be created in the current working directory, ready to be moved to your LV2 plugin directory. It doesn't get much easier than that. The same scripts are also used by the Faust online compiler when creating LV2 bundles. The scripts also recognize a few options which let you configure some aspects of the resulting LV2 bundle. Currently the most important of these are:
- -dyn-manifest tells the script to create a plugin with dynamic manifests; the default is to use static manifests. See Static and dynamic manifests above for details on this option and when you may want to use it.
- -uri-prefix URI sets the prefix of the plugin URI to the given option value. The plugin URI is used by LV2 plugin hosts to uniquely identify a plugin, see Compiling the plugin below for details.
If you need more control over the build process, you'll have to use the provided Makefile or compile the plugins manually, as explained below.
Compiling the plugin
After running the dsp source through the Faust compiler, the resulting C++ source file for the plugin must be compiled to a shared module, using your favourite C++ compiler. For instance, using gcc under Linux:
g++ -shared myplugin.cpp -o myplugin.so
Add -fPIC and other compilation options such as -O3 as needed. To make this work, you'll need the LV2 framework, so that the required LV2 header files are available. In the case of an instrument plugin created with the lv2synth.cpp architecture, you'll also need some of the header files of the Boost C++ library, so you should have at least the headers from that project installed as well.
To create a working plugin, you may also have to modify the URI of the plugin. As already mentioned, the URI ("uniform resource identifier", cf. RFC3986 and RFC1630) serves as a global name which is used to identify the plugin and differentiate it from other installed LV2 plugins, hence this name must be unique. For instance, the URI might be the actual URL of the website where the plugin may be downloaded, or it may just be an abstract name using one of the available URI schemes.
In order to support dynamic manifests, the URI needs to be included in the plugin source. The LV2 architectures thus contain a definition for the plugin URI. By default the URI http://faust-lv2.googlecode.com/myplugin will be used, where myplugin is the actual class name of the plugin as set with Faust's -cn option, as discussed at the beginning of this section. Of course, you will want to change this when compiling your own plugins.
There are some macro definitions which can be adjusted on the g++ command line to change the URI according to your needs:
- URI_PREFIX specifies the prefix of the URI to which the class name of the plugin will be appended.
- PLUGIN_URI specifies the entire URI. This overrides the URI no matter what URI_PREFIX value and class name have been specified.
These values must be given as double-quoted strings. For instance, if the class name myplugin has been set with the Faust -cn option, then it's usually sufficient to just change the URI prefix, e.g., as follows:
g++ -shared -DURI_PREFIX='"http://somewhere.org/plugins"' \ myplugin.cpp -o myplugin.so
If you really need to adjust the entire plugin URI, you can also compile the plugin with:
g++ -shared -DPLUGIN_URI='"http://somewhere.org/plugins/myplugin"' \ myplugin.cpp -o myplugin.so
In either case, the plugin URI given here must match the URI specified in the manifest of the plugin, see The manifest below.
The manifest
With the steps described in the previous subsection the compilation of the plugin is now essentially complete. However, LV2 also requires that you prepare a manifest.ttl file for the plugin, as explained in the LV2 documentation. The manifest is read by LV2 hosts to discover which plugins are available and how they can be loaded. You could prepare the manifest files by hand, but for non-trivial plugins this will be very error-prone and thus is not recommended. Therefore faust-lv2 comes with some templates which can be used to create the manifest files in a more or less automatic fashion, as explained below.
A minimal manifest must at least include the URI of the plugin and the name of the binary (shared module) from which the plugin can be loaded. If your LV2 host supports the dynamic manifest extension (see the corresponding remarks under Static and dynamic manifests), this is in fact all that is needed, since the remaining information (human-readable name, author and license of the plugin, port information, etc.) can be provided by the plugin module itself.
Manifest files are so-called RDF files written in Turtle syntax, which customarily have the .ttl filename extension. You can find a template for a minimal manifest in the lv2-manifest-template.ttl file which is included in the faust-lv2 distribution. This file can be edited by hand or, e.g., with the sed program to replace the placeholders uri@, Tom Redman@ and @dllext@ with the URI, basename and the (OS-specific) filename extension of the plugin module. For instance:
sed -e 's?@uri@?http://somewhere.org/plugins/myplugin?g' \ -e 's?@name@?myplugin?g' -e 's?@dllext@?.so?g' \ < lv2-manifest-template.ttl > manifest.ttl
The plugin URI must match what was set when compiling the plugin, see Compiling the plugin above. Here's how the created manifest might look like:
@prefix doap: <http://usefulinc.com/ns/doap#> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix dman: <http://lv2plug.in/ns/ext/dynmanifest#> .
<http://somewhere.org/plugins/myplugin/manifest>
lv2:binary <myplugin.so> ;
a dman:DynManifest .
This is all that's needed for the dynamic manifest case. If your LV2 host does not support the dynamic manifest extension (most LV2 hosts currently don't, at least not out of the box), a static manifest will be needed in the form of a ttl file which includes all the requisite information about the plugin. Instead of lv2-manifest-template.ttl you should use lv2-manifest-static-template.ttl in this case. Replacing the uri@ etc. placeholders in this file works the same as above. This will give you something like:
@prefix doap: <http://usefulinc.com/ns/doap#> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
<http://somewhere.org/plugins/myplugin>
a lv2:Plugin ;
lv2:binary <myplugin.so> ;
rdfs:seeAlso <myplugin.ttl> .
Note that the static manifest refers to an additional .ttl file with the same basename as the plugin module which contains all the additional information about plugin name, ports etc. You can create this file from the same C++ source as the plugin module itself, by compiling the source to an executable. This executable, when run, simply prints the dynamic manifest of the plugin to standard output, from where it can be redirected into the ttl file. After creating the ttl file, the executable is no longer needed and can be deleted. For instance:
g++ myplugin.cpp -o myplugin ./myplugin > myplugin.ttl rm myplugin
You should add to the g++ command all options that may be needed to compile the plugin. In particular, the same symbol definitions which set the plugin URI will be needed as described under Compiling the plugin.
LV2 bundles
Finally, shared module and manifest are packaged together as an LV2 bundle, a directory which customarily has the .lv2 extension. For dynamic manifests, this can be done as follows:
mkdir myplugin.lv2 cp myplugin.so manifest.ttl myplugin.lv2
If you use a static manifest, as described in the previous subsection, you must also copy the generated ttl file to this directory:
cp myplugin.ttl myplugin.lv2
You can then set up LV2_PATH to point to the parent directory of the myplugin.lv2 folder, or copy the folder to some directory on your LV2_PATH to have the plugin recognized by your LV2 host.
Bundling of plugin libraries
If you have more than one Faust plugin, you can simply repeat the three steps described above for each plugin to be compiled. However, in this case you also have the option to create a single bundle from the entire plugin collection. To these ends, just concatenate all the manifest.ttl files of the individual plugins to one big manifest.ttl file. Then place this file along with all the plugin modules (and, in the case of static manifests, the corresponding .ttl file for each plugin) into a single folder. (This is also the way that the distributed Makefile packages the plugins unless the split-bundle make target is used, cf. Installation.)
For instance, suppose that we have three plugins amp, chorus and freeverb in corresponding .lv2 subdirectories, then we can bundle them together in a single folder, say, faust.lv2, as follows:
mkdir faust.lv2 for plugin in amp chorus freeverb; do cat $plugin.lv2/manifest.ttl >> faust.lv2/manifest.ttl cp $plugin.lv2/$plugin.so $plugin.lv2/$plugin.ttl faust.lv2 done
Automatizing the build process
The steps needed to build and install a working LV2 plugin or an entire plugin collection from Faust source can of course be automatized, using any build tool of your choice. In fact the entire faust-lv2 package is just one big example which illustrates how to do this with GNU make or with the included scripts. Please have a look at the Makefile and the faust2lv2 and faust2lv2synth scripts which should give you an idea how this works.
You can also just use the existing infrastructure of the faust-lv2 package as is. To these ends, drop your Faust programs into the effects and synths folders and run make to have them compiled. (Instrument plugins should go into the synths directory so that they are compiled with the lv2synth.cpp architecture, while ordinary audio plugins go into the effects folder and are compiled with the lv2.cpp architecture.)
Future work
While the LV2 plugin implementation of the Faust LV2 architectures is fully functional and reasonably complete already, there are ways in which they could be further improved. These will hopefully be addressed in future releases.
- Add improvements for smoother playback. In particular, the polyphony control provided by lv2synth.cpp is fairly disruptive right now, as it simply resets all voices each time the control changes. Another idea would be to do fully dynamic voice allocation so that the polyphony control wouldn't be needed at all. Also, it would be useful to implement crossfading to prevent clicks when a plugin is activated or deactivated.
- Add custom plugin GUIs which honor the hierarchical GUI layout defined in the Faust source. Corresponding code is readily available in other Faust architectures such as jack-gtk and jack-qt, but would need to be integrated with the LV2 architectures and the LV2 GUI extension.
- Add support for the new LV2 Time extension, which provides transport information such as current position, tempo and meter to a plugin.
- Implement MIDI output for passive Faust controls. It's unclear if and how existing LV2 hosts would process such data, however, so there's still some research to be done there.