Skip to content

Latest commit

 

History

History
325 lines (239 loc) · 12.7 KB

my-first-lv2-plugin.rst

File metadata and controls

325 lines (239 loc) · 12.7 KB

My First LV2 Plug-in

Author: Christopher Arndt
Date: 2018-08-09

The Simple Gain Effect Plug-in

In this project we are going to build a simple audio effect plug-in without having to write a single line of code! This is possible by using the cookiecutter tool to generate our project from a template. This template provides the code for an effect plug-in based on the DISTRHO Plugin Framework (DPF). The effect is a simple audio level gain (or rather attenuation) control. From a single code base we can compile the plug-in in LV2, VST, and LADSPA format. In a later stage we can adapt the code generated by the template to different kinds of plug-ins.

This guide assumes that you are working on a common Linux distribution of your choice. Unless otherwise noted, install the requirements below from the package repository of your distribution.

  • Software build tools (GCC, make, etc.)

    debian / Ubuntu users install the build-essential package.

  • pkg-config

  • Python 3

    debian / Ubuntu users install the python3-dev and python-pip packages.

  • JACK server, library and development files

    debian / Ubuntu users install the jackd or jackd2 and libjack-dev or libjack-jackd2-dev package.

  • cookiecutter

    Do not install the debian / Ubuntu package (it is outdated), install with:

    pip install --user cookiecutter
    

    and then add $HOME/.local/bin to the PATH environment variable in ~/.bashrc (you need to log out and in again to make the change effective in your whole desktop session).

  • git

  • jalv

  • lilv resp. lilv-utils or the appropriate package to install the lv2ls and lv2info programs

  • An LV2 host of your choice, e.g. Carla, Ardour, Ingen, etc.

  • An internet connection

There are a few things we need to take care of, before we can generate our project. The commands given below are shell command lines, which you type or copy & paste into a terminal window (without the leading $ prompt). So open a new terminal window now and use that same window for all subsequent commands (unless told otherwise).

  1. If you haven't done so already in the past, configure your Git client (you may of course substitute your real name and email address):

    $ git config --global user.name "John Doe"
    $ git config --global user.email [email protected]
    

    This is needed because when you generate the project, it will initialize a Git repository and make an initial commit, for which Git needs to know what to use as the author of the commit. If you don't want to, you don't need to use Git after that and neither do you need to have a GitHub account, but the project will be ready be pushed to GitHub, if you so desire.

  2. Make or choose a directory where the project will be generated, e.g.:

    $ mkdir -p ~/projects; cd ~/projects
    
  3. (Optional) This step is not needed but makes things easier if you want to start over and run cookiecutter again to re-generate the project or use it to make other projects.

    Create a file named ~/.cookiecutterrc in your home directory and put the following in it:

    default_context:
        full_name: "Joe Doe"
        domain: "mydomain.com"
        email: "[email protected]"
        github_username: "JoeDoe"
    

    Again, substitute your real personal data, or something you made up.

Still in the same terminal window, in your project directory, run cookiecutter to generate the new project:

$ cookiecutter https://github.com/SpotlightKid/cookiecutter-dpf-effect

For this step you will need an internet connection, at least for the first time you run this, since this will download the project template from the given URL and then prompt you for some values, which are used when generating the project. If you just press the return key at any question, the default value in square brackets will be used. Here's an example run:

project_name [Simple Gain]:
plugin_description [A simple audio volume gain plugin]:
full_name [Joe Doe]:
domain [example.com]: mydomain.com
github_username [joe.doe]: JoeDoe
email [[email protected]]: [email protected]
plugin_brand [mydomain.com]:
plugin_name [SimpleGain]:
repo_name [simplegain]:
plugin_uri [http://mydomain.com/plugins/simplegain]:
project_license [MIT]:
version [0.1.0]:
year [2018]:

Running post-project-generation hook...

Initializing new Git repository:
Initialized empty Git repository in /home/joe/projects/simplegain/.git/
Adding Git submodule for DPF library:
Checking out submodules:
Cloning into '/home/joe/projects/simplegain/dpf'...
remote: Counting objects: 7168, done.
remote: Total 7168 (delta 0), reused 0 (delta 0), pack-reused 7167
Receiving objects: 100% (7168/7168), 12.13 MiB | 1.30 MiB/s, done.
Resolving deltas: 100% (6078/6078), done.
Making initial Git commit:
[master (root-commit) dbdfbb6] Initial commit
 12 files changed, 699 insertions(+)
 create mode 100644 .gitignore
 create mode 100644 .gitmodules
 create mode 100644 LICENSE
 create mode 100644 Makefile
 create mode 100644 Makefile.mk
 create mode 100644 README.md
 create mode 160000 dpf
 create mode 100644 plugins/Makefile.mk
 create mode 100644 plugins/SimpleGain/DistrhoPluginInfo.h
 create mode 100644 plugins/SimpleGain/Makefile
 create mode 100644 plugins/SimpleGain/PluginSimpleGain.cpp
 create mode 100644 plugins/SimpleGain/PluginSimpleGain.hpp

Your DPF audio effect plugin project is now ready!
To compile it, change into the 'simplegain' directory and type 'make'.
The plugin binaries and LV2 bundle will be placed in the 'bin' subdirectory.
Have fun!

Just follow the instructions, which were printed to the console at the end of the previous step:

$ cd simplegain
$ make

If you have all the required software development tools and libraries, this will compile the plug-in in LV2, LADSPA, DSSI and VST2 format. The first time you run make, compilation will take a couple of seconds, because the DPF library sources have to be compiled. The next time you run make (without running make clean in between), these will not have to be compiled again, and compilation should be much faster.

The plug-in binaries will be placed in a bin sub-directory of your project's repository root. For each the LADSPA, DSSI and VST2 format this will produce a shared library file (i.e. with .so extension) and the filename will consists of the plug-in's name in lower case and the format, e.g. simplegain-vst.so. For the LV2 format a bundle directory will be created (simplegain.lv2), which also contains a shared library, a manifest.ttl file and further .ttl file.

If you get any compiler warnings during the compilation, don't worry, these are probably due to some occurences of deprecated C++ syntax in the DPF library sources.

If you get any errors, please double-check that you have all the development tools and libraries installed, are in the correct directory, and that you haven't accidentally entered any weird data when creating the project. When trying to compile again, it's best to issue a make clean first, to make sure everything is compiled again anew.

After the compilation, check that the bin directory contains three .so files and an LV2 bundle directory with current timestamps:

$ ls -l bin
total 92
drwxr-xr-x 2 joe users  4096 09.08.2018 18:26 simplegain.lv2/
-rwxr-xr-x 1 joe users 27056 09.08.2018 18:26 simplegain-dssi.so*
-rwxr-xr-x 1 joe users 26960 09.08.2018 18:26 simplegain-ladspa.so*
-rwxr-xr-x 1 joe users 30904 09.08.2018 18:26 simplegain-vst.so*

To make the LV2 plug-in known to host programs, we need to put it into either /usr/lib/lv2 or a .lv2 directory in our home directory. Since we don't want to mess with the system-installed files, we will install the bundle into the latter, creating it first, if it doesn't exist yet. Instead of simply copying the bundle directory, we will create a symbolic link to it, so when we compile the plug-in again, we don't have to copy it again (or scratch our head when the changes we did do not seem to take effect):

$ mkdir -p ~/.lv2   # Notice the leading dot in the directory name!
$ ln -s "$(pwd)/bin/simplegain.lv2" ~/.lv2

Let's check whether our plug-in can be found with lv2ls (make sure that the LV2_PATH environment variable is unset or includes $HOME/.lv2):

$ lv2ls | grep simplegain
http://mydomain.com/plugins/simplegain

This should print out the LV2 URI (i.e. its unique name) of the plug-in. With this URI we can get some more information about the plug-in with lv2info:

$ lv2info http://example.com/plugins/simplegain
http://mydomain.com/plugins/simplegain

    Name:              SimpleGain
    Class:             Plugin
    Author:            mydomain.com
    Author Homepage:   http://mydomain.com/plugins/simplegain
    Has latency:       no
    Bundle:            file:///home/chris/.lv2/simplegain.lv2/
    Binary:            file:///home/chris/.lv2/simplegain.lv2/simplegain_dsp.so
    Data URIs:         file:///home/chris/.lv2/simplegain.lv2/manifest.ttl
                       file:///home/chris/.lv2/simplegain.lv2/simplegain_dsp.ttl
    Required Features: http://lv2plug.in/ns/ext/urid#map
                       http://lv2plug.in/ns/ext/options#options
    Optional Features: http://lv2plug.in/ns/ext/buf-size#boundedBlockLength
                       http://lv2plug.in/ns/lv2core#hardRTCapable
    Extension Data:    http://lv2plug.in/ns/ext/state#interface
                       http://kxstudio.sf.net/ns/lv2ext/programs#Interface
    Presets:
             Default

    Port 0:
        Type:        http://lv2plug.in/ns/lv2core#AudioPort
                     http://lv2plug.in/ns/lv2core#InputPort
        Symbol:      lv2_audio_in_1
        Name:        Audio Input 1

    Port 1:
        Type:        http://lv2plug.in/ns/lv2core#AudioPort
                     http://lv2plug.in/ns/lv2core#InputPort
        Symbol:      lv2_audio_in_2
        Name:        Audio Input 2

    Port 2:
        Type:        http://lv2plug.in/ns/lv2core#AudioPort
                     http://lv2plug.in/ns/lv2core#OutputPort
        Symbol:      lv2_audio_out_1
        Name:        Audio Output 1

    Port 3:
        Type:        http://lv2plug.in/ns/lv2core#AudioPort
                     http://lv2plug.in/ns/lv2core#OutputPort
        Symbol:      lv2_audio_out_2
        Name:        Audio Output 2

    Port 4:
        Type:        http://lv2plug.in/ns/lv2core#ControlPort
                     http://lv2plug.in/ns/lv2core#InputPort
        Symbol:      volume
        Name:        Volume
        Minimum:     0.000000
        Maximum:     1.000000
        Default:     0.100000
        Properties:  http://lv2plug.in/ns/ext/port-props#logarithmic

Let's try to load the plug-in with the jalv LV2 host. Make sure you have started the JACK audio server (e.g. with qjackctl) and run:

$ jalv.gtk http://mydomain.com/plugins/simplegain

This should open a small window with a menu bar and a numeric spin box and a slider for the volume control of our plug-in.

Open a JACK patchbay program (e.g. qjackctl, patchage or Catia) to see the JACK client for the plug-in created by jalv. It should have two audio inputs and outputs and one event (MIDI) input.

Now route some audio into the audio inputs of the plug-in and connect its audio outputs to the system:playback_1 and system:playback_2 inputs of your soundcard. Then change the volume parameter via the slider. The audio level of the signal should change accordingly.

That's all for now. You can test your plugin in different hosts, e.g. Carla or Ardour and try automating the volume parameter via OSC, MIDI or a DAW track automation. Then have a look at the source code of your plug-in in the plugins/SimpleGain directory. We will discuss the plug-ins C++ classes and its various methods next time.