Showing posts with label LV2. Show all posts
Showing posts with label LV2. Show all posts

Monday, July 9, 2012

Writing Lv2 GUI's: Making it look snazzy

So we know how to build a basic "amp" plugin, but there's no GUI. We like shiny gui's right? Of course we do :) This tutorial will explain how to make one.

Gooeys - Or GUI's:

The GUI part of a plugin can be viewed as a totally separate entity to the "DSP" or audio part of the plugin. We will call these the "halves" of our plugin. Theres a little bit of theory to cover before we start looking at code. The next communication section describes how the DSP and GUI parts of the plugin can inform eachother about whats going on.

Communication:

So the GUI runs in the "GUI" part of the host program, and the DSP runs in the audio part of the host program. We can't communicate directly between the halves due to details that don't really concern us. (threading and thread safety if you must know..)

How it works: The two parts of our plugin are loaded into the two parts of the host program. How we communicate between the two "halves" of our plugin is by using Lv2 ports. These ports send communicate data between the host and the plugin. The host can then use that same data to update the GUI.

Similarly the GUI can write data, which will then be sent to the audio half by the host. That's all there is to it!

Choosing a toolkit

So there's a lot of GUI toolkits out there. The most prominent open-source ones are GTK and QT. This tutorial will explain how to create a custom GTK interface for an Lv2 plugin. My reason for choosing GTK? Its what I know. I also like it. If somebody would contribute code for doing the same in QT, I will gladly link to it from here.

Please note that I'm using the C++ wrapper around GTK (called GTKmm), and I use version 2, not the new stable GTK 3. I know that GTKmm 2 works, and have no reason to update to GTKmm 3.

Side note (skip if you want to get hands-on GUI writing): The loading of GUI plugins into hosts is done using the SUIL library. It is useful to know that it has certain toolkits that it supports, currently X11, GTK2 and QT. If you want to use a different toolkit please read the SUIL library page.

Making a GUI

So what do we actually do to get a GUI for an Lv2? We write a widget. If you're not at all familiar with GUI programming, I will suggest you look at the GTKmm2 Drawing Area tutorial code: Drawing a custom widget using a GTK::DrawingArea. When we have a widget created, we need to pass that widget to the Lv2 host, which will display it for us.

Code

Yes. Where is it? There is a copy of the Lv2 repo on my Github, where I will publish the code for this tutorial. Chances are that these tutorials will be merged into the main Lv2 examples from the Github page.

Communication in code

So we talked about the theory of communication between the halves, but how do we actually do that in code? The Lv2 UI extension that we use to load the GUI gives us two "things" that we need to write port events from the GUI to the host. What these things represent is not really important: we just need to use them. (if you must know: LV2UI_Controller is a pointer to the host's own stuff, and LV2UI_Write_Function is a function pointer that will do the work)

Github Lv2 repo: SinSynth folder at commit while writing this tutorial


Writing port events in the GUI

So we have these two things: LV2UI_Controller and LV2UI_Write_Function, how do we use them? More theory first. Events happen in the Widget, ie: if the user clicks, our Widget gets a function called. That function must decide what to do, and then call the write_function().

What this means in practical terms, is that the Widget class needs access to the LV2UI_Controller and LV2UI_Write_Function.

The way that I solve that, is by adding the LV2UI_Controller and LV2UI_Write_Function to the Widget class. Some people might say this is ugly design: but its simple and works well.

Look at Widget::on_button_press_event to see the code in action.

 

Testing the plugin

There's a program called Jalv, which is a great little host to test out your Lv2 plugins with: I've used it to develop this tutorial and the GUI for the tutorial. Grab it here: http://drobilla.net/software/jalv/


Running jalv.gtk http://lv2plug.in/plugins/eg-sinsynth
gives me this screenshot, clicking it will change the frequency!




 

That's all!

You've now made a custom GUI, that should work as a Lv2 plugin gui. Sure its not UI artwork yet, but I'll leave you to explore Cairo and its cool graphics functions on your own for a while ;)

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!

Saturday, January 14, 2012

Luppp : Source opened, but still pre-alpha!

Hi All!

With recent changes in the world of live looping software I've decided to open my private repo of Luppp.

The Luppp project has been one of my main occupations over the last couple of years, and I've tought myself C++ programming while working on it. Its a live looping instrument with similar features to the well known software Ableton Live, and more recently Bitwig studio. I feel the live workflow available with such programs is something the Linux Audio community would also benefit from, and hence it will be released under the GPL license, version 3.

Its current state is that most "basic" functionality is in place: Loading, playing back & recording of loops works, effects can be added to these audio streams, and later they are mixed. A basic config file is used to store information about loops, and hence Luppp can make more informed decisions how to use loops.

This is pre-alpha software, as not all features to fullfill alpha state are  implemented. On the other side, most features currently available are quite stable (on my local machine anyway :)

I would like to announce that I will continue to work on the Luppp project myself, but that I do also welcome input / testing / help from other developers. I am aware that there are some basic enough flaws in the program in its current state, however these are also the primary items on my TODO list.

Remember its pre-alpha, please keep that in mind :)
Git source repo: https://github.com/harryhaaren/Luppp
ZIP of master branch: https://github.com/harryhaaren/Luppp/zipball/master

If you're intrested in working on Luppp, have a feature request, have ideas, time, or want to build Luppp a website, feel free to get in contact!!
Cheers, -Harry

Mandatory screenshot (note your GTK theme will influence its looks, this is on the todo! ):

Tuesday, June 7, 2011

Luppp: 20,000 loc Lv2 support & a CSound display

Hey hey,

20,000 lines of code, some LV2 support, and the beginnings of a CSound haul-over.
For now a quick post, with the mandatory screenshots, later some more info on how its intended to support some of the (fancy) LV2 features like the instance access, and some others :)






Embedding LV2 gui's into the Luppp ui. Pop out windows will be supported too at some point :)
And a CSound text editor based on Gtk Source View, a csound.lang file must be created to syntax highlight all the opcodes & that


Till next! -Harry

Wednesday, May 25, 2011

Lv2: New host lib, lilv, a newbies guid to LV2

Hey All,

Ever tried to get your head around the Lv2 spec? Me too, and if one isn't used to the "lingo" of URI's, RDF's, and various other path etc it can all be a bit daunting. Yet some of the coolest and best plugins (check: this Parametric EQ, or this IR reverb) are on the Lv2 standard, so you really do want to support them...

If you wanna get your hands dirty, skip down to the bulletpoints, that's what you'll need to do to get started!

With this new library from David Robillard writing hosts to use these plugins should become easier & faster. The library I'm talking about here is of course Lilv. It depends on two of Robillards other libraries, namely Serd & Sord.

Serd handles the reading & writing of RDF data, as well as Turtle & NTriples. Don't worry, I don't know what they are either. Perhaps in the future I'll try understand them...
Sord is a library for storing RDF data in memory... apparently we'll need that!?

Getting Started:
Create a folder somewhere where's your gonna do all this stuff.

Grab all of the following:
http://download.drobilla.net/lilv-0.4.0.tar.bz2
http://download.drobilla.net/sord-0.4.0.tar.bz2
http://download.drobilla.net/serd-0.4.0.tar.bz2

Ensure these are installed:
lv2core

Untar the lot of those .tar.bz2's from drobilla, and cd into the serd-0.4.0 dir.
./waf configure
./waf
sudo ./waf install

cd into the sord-0.4.0 dir,
./waf configure
./waf
sudo ./waf install

then cd into lilv-0.4.0
./waf configure

This shouldn't give any problems, as we've just installed the 2 dependencies you probably didn't have. If JACK or any other common issues arise, just fix them.

If you get the following errors:
Checking for header lv2/lv2plug.in/ns/lv2core/lv2.h : no
Checking for header lv2/lv2plug.in/ns/ext/event/event.h : no
Checking for header lv2/lv2plug.in/ns/ext/event/event-helpers.h : no
Checking for header lv2/lv2plug.in/ns/ext/uri-map/uri-map.h : no

Then this is what you do:
1. Direct your browser to http://lv2plug.in/spec/
2. Grab lv2core,lv2-event, and lv2-uri-map.
3. Untar lv2core, ./waf configure, ./waf, ./waf install it (the first one should be fixed now)
4. Run "lv2config", this creates some symlinks around to headers
5. Bop open a terminal, cd /usr/include/lv2/lv2plug.in/ns/
6. sudo mkdir ext
7. Copy the event folder into ext, and copy the uri-map folder in too.
8. *CHECK THE DIRECTORY STRUCTURE!!!* the output of ./waf configure tells you *exactly* where its looking for the files, *PUT THEM THERE*. Can't stress this enough. Use your brain & figure out what's not where its meant to be

./waf configure should print out yes yes yes yes yes yes to all dependencies now, so
./waf build,

Only if *building* fails, ie: ./waf fails like so:
[28/36] c: utils/lv2jack.c -> build/utils/lv2jack.c.7.o
In file included from ../utils/lv2jack.c:29:0:
/usr/include/lv2/lv2plug.in/ns/ext/event/event-helpers.h:28:52: fatal error: lv2/http/lv2plug.in/ns/ext/event/event.h: No such file or directory
compilation terminated.

Get to your favorite text editor, and sudo up the cow powers, because we've got a header to edit.
1. sudo /usr/include/lv2/lv2plug.in/ns/ext/event/event-helpers.h
2. Go to line 28. its contents should be: #include "lv2/http/lv2plug.in/ns/ext/event/event.h"
3. Change those contents to "#include "lv2/lv2plug.in/ns/ext/event/event.h"
4. ./waf build again.

Edit: The author of the event extension is planning a release to fix this issue.

and then sudo ./waf install the whole thing.

Boom! You've got lilv running.
Check the lilv-0.4.0/utils directory for some examples of using the library.
If you've built lilv, then in /build/utils there are the binaries of the examples. Run them while looking at the source, understand what to do.

In the /bindings/python dir there are 2 files, lv2_list.py & lv2_apply.py
They might provide some insight into the steps nessiary to get Lv2 plugins instantiated and in a good mood to work... :D

Finally a huge thanks to all the members of LAD who have developed this awesome standard, awesome plugins, and last but not least, awesome hosts! :D
Cheers, -Harry