Make LV2 plugins with Faust

This is a guide that I made for me (a complete dummy) to remember the tool to use for making lv2 plugin on the fly. With Faust, you make also to create VST, JUCE, a standalone application and more other, but I need an lv2 plugin!

So if you search a guide for the tool you use for creating an audio plugin for complete dummy you are in the correct place.

Faust Web IDE

Faust (Functional Audio Stream) is an interesting programming language for sound synthesis and audio processing.

The best advantages for dummies is that it has a web IDE, so you can program it with zero-configuration.

Faust web IDE

With this IDE we can coding live and run our plugins to test. This is a very good way to work for simply plugins.

The example button gets we very interesting sample to learn how to program.

By clicking the truck we can export in many formats as lv2 or lv2 with qt5 or qt4 GUI automatic generated.

Compile from Faust web IDE

It also have a simple gui builder but it is only for web assembly (issue), but if some contributor want, it is possible to port this issue to whole kind of export.

Make your first plugin

The example is very interesting but we can start with a simple noise plugin.

We can start to see the whole plugin code:

declare name "Noise";declare version "0.1";
declare author "You";
declare license "The licence you want";
declare copyright "(c)You 2021";
import("stdfaust.lib");volume = hslider("Volume", 0.5, 0, 1, 0.1);
noise = no.noise;
process = noise * volume;

It is possible to cut and paste into the Faust IDE to try it.

In the first part we can declare some information about the plugin we write

declare version "0.1";
declare author "You";
declare license "The licence you want";
declare copyright "(c)You 2021";

After we can import the Faust lib that gets us some standard utility

import("stdfaust.lib");

After we start to define a Volume slider, with defaut=0.5, and range [0, 1] with 0.1 step

volume = hslider("Volume", 0.5, 0, 1, 0.1);

Now we can use the noise from the Faust lib

volume = hslider("Volume", 0.5, 0, 1, 0.1);

At the end, we define what we export in output, the noise moduled by volume

process = noise * volume;

In this case to the process that we assign to process the interested value, but if our plugin has an input we can find this input inside the process, before our assignment.

You can obviously create a plugin with midi input etc., for all other information you can use the manual or the examples into the IDE.

A typical way that I see in the dsp language is the “with” construction: it is possible to define the operations between parameters first and after how to obtain these parameters. So we can rewrite the code as follow:

process = noise * volume
with {
noise = no.noise;
volume = hslider("Volume", 0.5, 0, 1, 0.1);
};

The last trick that I think you want is to have a knob instead of a slider, this is possible by redefining volume as follow:

volume = hslider("Volume[style:knob]", 0.5, 0, 1, 0.1);

Live lv2 Coding plugin with Mephisto

Sometimes is enough to use the web IDE with its run button, but sometimes we want to develop it in a more complex environment. So we can develop our plugin using the Mephisto lv2 plugin that is an lv2 plugin with a code area in witch we can code directly into our DAW.

mephisto screenshot

It can use vim or emacs.

Develop on my pc

If you want to compile and develop without the web IDE you need to install faust and if you want something like the web ide you can install faustlive.

But personally, I do not use faustlive since now.

The Codebase and Continous Delivery

If you are not interested in releasing your code publicly or you do not want a CD (Continous Delivery) pipeline skip to the conclusion.

Recently I used to use gitlab.com to create my remote git repository, and it offers also a free CI/CD system and a Package Registry in which we can add the binary.

The idea is to release automatically the compiled binary automatically every time the code change.

So we add to the codebase the <FILE_NAME>.dsp file with our git repository and push to gitlab (if you do not know how to do you can use this link).

The CI/CD in gitlab can be ontained by adding and pushing a .gitlab-ci.yml file:

build-lv2:
image: registry.gitlab.com/nicolalandro/simple-pink-noise
script:
- faust2lv2 <FILE_NAME>.dsp
- mkdir lv2_no_gui
- cp -r <FILE_NAME>.lv2 lv2_no_gui
- faust2lv2 -qt5 <FILE_NAME>.dsp
- mkdir lv2_qt
- cp -r <FILE_NAME>.lv2 lv2_qt
- tar -czvf <FILE_NAME>.tar.gz lv2_no_gui lv2_qt
- 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file <FILE_NAME>.tar.gz "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/<RELEASE_NAME>/0.0.1/<FILE_NAME>.tar.gz"'

This file specify a script that compile your dsp file to lv2 with the command faust2lv2 <FILE_NAME>.dsp for non gui version and faust2lv2 -qt5 <FILE_NAME>.dsp for the qt5 version, pack it into a tar.gz and upload to the gitlab package registry of your repository.

Now every push the script is executed and it creates the release automatically. Each push of master you can see a CI/CD>pipelines start, and after into the Packages & Registies>Package Registry you can find the tar.gz with compiled .lv2 files with qt5 GUI and without GUI.

ps. Do not remember to include a README.md file in your repo.

Faust Docker container

Up to now, I do not find an official version of Docker container, so I create the container “registry.gitlab.com/nicolalandro/simple-pink-noise” used in the script for Simple Pink a pink noise lv2 plugin.

The Dockerfile is the following

FROM debian:stable-slim

RUN apt-get update && apt-get install -y git
RUN git clone https://github.com/grame-cncm/faust.git

WORKDIR /faust
RUN git submodule update --init

RUN \
apt-get update && \
apt-get install -y build-essential llvm libncurses5-dev libncurses5 libmicrohttpd-dev git cmake pkg-config && \
rm -rf /var/lib/apt/lists/*

RUN \
make && make install && \
make clean && \
apt-get purge -y build-essential llvm libncurses5-dev && apt-get autoremove -y

# lv2 compile
RUN apt-get update && apt-get install -y g++ lv2-dev libboost-dev

# delivery gitlab-ci
RUN apt-get update && apt-get install -y curl

# qt5 compile (it need qmake-qt5 not qmake)
RUN apt-get update && apt-get install -y qt5-default
RUN ln -sf /usr/lib/qt5/bin/qmake /usr/lib/qt5/bin/qmake-qt5
RUN ln -sf /usr/bin/qmake /usr/bin/qmake-qt5

If you want to obtain other build for example the vst or other, you can improve this Dockerfile by install the library you need and add the compilation instruction into the .gitlab-ci.yml file.

To upload the new Dockerfile to your repository container registry you can do

docker login registry.gitlab.com
docker build -t registry.gitlab.com/<UNAME>/<CODEBASE_NAME> .
docker push registry.gitlab.com/<UNAME>/<CODEBASE_NAME>

To use this new Container you should change into the .gitlab-ci.yml file the second line with the following:

image: registry.gitlab.com/<UNAME>/<CODEBASE_NAME>

Conclusions

This is my first solution to develop lv2 plugin with Faust so if you have corrections or only to start a discussion comment this post!

Contribute to open-source plugins!

Linux user and Open Source fun. Deep learning PhD Student, Full stack web developer, Mobile developer