Monday, June 11, 2012

Writing Lv2 plugins : An Lv2 Overview

 

Although I'm relatively aware of what Lv2 is, and also relatively aware of how it works, and relatively know how to write a "host" class: what's inside an Lv2 plugin???

Starters: I'm assuming you know a bit of C/C++, you know what a plugin is, and you're well able to use a terminal. I'm not assuming you know much about plugin specs, Lv2 URI's, manifest files, or Turtle RDF. These things will become apparent as we go along.

For this tutorial, I'm going to talk us trough the "eg-amp" code, that comes with the lv2 source code. If you don't have it yet, grab it now. Extract, and /plugins/eg-amp.lv2/ shows you the sources.

Introduction:

Lv2 works by defining URI's. A URI means *nothing*. It is a string, that contains a unique identifyer for *stuff*. Usually it is in the form of a http:// address, and that web link will show you more info on the plugin. Don't fret about details, just remember this:
A URI IS AN IDENTIFIER FOR THINGS

Lv2 plugins come in "bundles". A bundle contains one or more plugins. For simplicity, this example contains only one plugin. A bundle is just a directory, with three files inside:
  1. manifest.ttl
  2. <pluginName>.ttl
  3. <pluginName>.so
The other files (waf and wscript) are only to compile the source code into the binary plugin, and install them. Of course any other build system can be used to compile Lv2 plugins too!

Walk trough of the files:

Manifest.ttl

This file lists all plugins that can be found in the bundle. For this example, there's only one. The file has various different bits of information about the bundle its contained in, and this information defines the plugin.

The eg-amp manifest contains this:
@prefix lv2:  <http://lv2plug.in/ns/lv2core#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .

<http://lv2plug.in/plugins/eg-amp>
    a lv2:Plugin ;
    lv2:binary <amp.so>  ;
    rdfs:seeAlso <amp.ttl> .


First of all two "convenience" prefix' are defined. The core Lv2 URI, and the RDF scheme URI.

Next we declare a URI. It is the unique string, that when used always means exactly this object. Afterwards, some details about the "resource" are added:
The resource <http://lv2plug.in/plugins/eg-amp> has the property lv2:Plugin, the property lv2:binary and for more info look at <amp.ttl>.


<PluginName>.ttl

This file contains all the details about the plugin: think "Who what when how where"?. I won't paste the code here,the 85 lines would clog up this post. I'll talk you through it though, dont' worry!

First section after the license (lines 17-21):
One can declare some RDF data to show the "author" of a plugin. This can point to your own website, or else a company website.

The next section (lines 29-87) contain the implementation details of the plugin: things like the Maintainer of the plugin, the name of the plugin, the license, the plugins "features", and what "ports" it exposes.

<PluginName>.so

Finally: the binary file, that a host will load, and use to do whatever the plugin does. Not much more to say really!

Lv2 Extensions

An extension is a definition of some extra functionality, that isn't contained in the core lv2 spec. These definitions have their own unique URI, and each has its own .ttl and C header files.

Since Lv2 is a "modular" or "extensible" format, anybody can write a Lv2 Feature, and then write plugins or hosts to use that feature. Note that not all hosts support every feature, so using "rare" features may mean you plugin can't be used in a host somebody else wrote.

Lv2 Ports

(If you are familiar with LADSPA ports, skip this section: they're pretty similar)
Ports are a way to transfer data between the plugin and the host. There are various types of ports, some built into the "lv2-core" spec (always available in every host) and some that are "feature" ports, (ie contained in a feature extension to lv2, and perhaps not every host supports it).

Most ports send float values around, like in the eg-amp:
lv2:port [
        a lv2:InputPort ,
        lv2:ControlPort ;
        lv2:index 0 ;
        lv2:symbol "gain" ;
        lv2:name "Gain";
        lv2:default 0.0 ;
        lv2:minimum -90.0 ;
        lv2:maximum 24.0 ;
               ]

The above RDF snipped defines a port, its an input port (to the plugin), its a control rate port (not audio), its index is 0, and it changes the "Gain" parameter of the plugin. Pretty readable right? I'll leave the rest to you! :D

Compiling eg-amp

So to get the eg-amp lv2 bundle compiled and running you've a couple of steps to take:
./waf configure           will setup Waf so it knows how to build
./waf                            will compile & link the files
./waf install                moves the .lv2 bundle to /usr/local/lib/lv2/ (by default)

Note that doing a
./waf configure --strict --debug --prefix=/usr
will enable strict compiler checks, a debug build, and install in /usr/lib/lv2/

Test the plugin using any Lv2 host, Ardour, QTractor, Jalv, lv2rack, zynjacku : they should all work, assuming they're up to date!

Finished!

That's most of the main topics of Lv2 covered: you now have a decent understanding of what is necessary to write Lv2 plugins. In a future post I hope to cover the details of eg-amp.lv2, and the C code it consits of. Also intended is to post about how to implement extra features; both for hosts and plugins. But that'll remain for another day.

PS: Comments and changes welcomed: I'm new to writing Lv2 plugins myself, and I'm sure that improvements can be made on this post!

Wednesday, May 2, 2012

Luppp milestone: Timestretch!

Although its been a relatively quite period for development (due to lots of deadlines) today one of Luppp's long term goals has been reached: on-the-fly time stretching per track.

For the non-techie: This means that you can play a melody loop, and slow it down or speed it up, and the audio will remain in the same key! (No turntable RPM effect? Nope :)

Mandatory examples:

Although I'd call the quality "passable" is obviously not fantastic but there's some parameters in the algorithm that are available to tweak, so I hope to be able to improve it a bit a least :)

So when is a beta release?? Don't hold your breath, sorry. There's still some work to be done before Luppp will be ready for prime-time, but until then feel free to test it if you're interested!

Will keep you posted, -Harry

Sunday, April 15, 2012

LAC performance

Hey All,

With the LAC on at the moment, its a prime time to do some extra development on features that need some finishing before being fully useful. That has been going on, and now the AutoMove feature allows the changing of the length of the fade. Currently the mapping to change the length is set to right click, that needs to be changed as we can only cycle up in length. Current options for beat lengths are 2, 4, 8, 16, and 32.

Also fixed was the "Master Beat Indicator", (the moving widget here). It now just syncs to JACK tempo, and will display which of the beats between 1 and 4 we're on. Since the AutoMove function is triggered on a downbeat (every 4th beat) the tempo indicator shows when the AutoMove fade will come into effect.

The current git head (master branch) is the exact version of Luppp that I used for the performance at the LAC Sound Night yesterday. Many thanks to Luigi Verona for his droning series which was the basis for the piece.

Greetings from the LAC, -Harry

Wednesday, April 11, 2012

Luppp : Scopes and Sends

New features have arrived in the devel branch:
-Interaction with the sends & return widgets
-Scope that displays the master output_W channel

Various code improvements have also been pushed along the way, be it that the headphones volume dial now goes up when you move up, or that that post-fade send now adhere's to the Mute status of the track.

Its another small step along the way! Mandatory screeny:

Wednesday, March 21, 2012

Luppp: New Feature! AutoMove

Over the last days a new feature was designed & implemented: AutoMove.

The idea is simple; in a live situation you just don't have time to write automation lines, not even simple ones! You also don't have a hand free to turn up your reverb during the next 16 bars, so what do you do? AutoMove it!

The following GIF animation of screenshots gives it all away:

There are preset automation lines, and widgets that are active get scaled by the AutoMove's value. You press one button, and it does the rest. Now we're making music :)

Available in the master branch as of right now!

Friday, March 16, 2012

Luppp: Alpha 1


Alpha 1 status:
100%  -  Closed



Today the last bug on the Alpha1 milestone has been closed, hence also the alpha1 release of Luppp 2.0. In a way this is a big occasion, its the first official release!

Alpha1 in action, with various effects and clips!


On the other hand, there's still a bucket load of work to be done before Luppp will be comfortable to use without various hardware controllers. I'm aware that there's lots of half-finished, half broken as well as broken stuff! Hey its still alpha!

Current milestone: Alpha2
There's already a list of bugs / feature requests up! There's also many GUI issues that are known and NOT there, but I'd prefer fix them than waste time posting a bug report.

Welcoming (adventurous alpha) testers, any issues will be dealt with as promptly as possible! Please file bug reports here: https://github.com/harryhaaren/Luppp/issues/new

Wednesday, March 7, 2012

Luppp: New Effects interface

After a "push" quiet period, I've just pushed up a couple of branches changes:
-Luppp's GUI has had a bit of work
-Effect control from the APC40 has been revamped
-Effects sends have been implemented

-The GUI now shows the effects under the track, in a small widget: reasons? Now you can always see the state of all your effects, not just the ones on your currently selected track. Better for live situations!

-The APC40 has 8 buttons under the Device controls, they now each map to Effect on/off. They're labelled for a different purpose, but I find this use quite intuitive.

-Post fader sends are implemented, including widget representing the state. The GUI widget doesn't work yet (ie won't change the value) but it does update upon a controller change.

I've pushed the changes to devel, but also the master branch, AFAIK its stable.


Screeny: