Hi all,
Once upon a time I posted on this blog (somewhat) regularly. Currently I dont. Why? I'm running OpenAV Productions, and that is where the updates are!
If you're still interested in Linux audio, C++ programming or software in general, checkout the site:
www.openavproductions.com
Developers may have particular interest in the developer topics like implementing NSM or dealing with memory in real-time.
Audio programming folks, checkout some articles that I've written on the topics of real-time programming, memory management, implementing NSM and more:
http://openavproductions.com/conferences.
I probably won't post here for another long time, so bye for now! -Harry
A blog dedicated to Linux Audio. Some Programming tutorials will be posted, some howTo articles for using certain features of a program, or just my own thoughts/options on any topic.
Monday, December 30, 2013
Saturday, June 22, 2013
Real time audio programming languages
Introduction
Over the last couple of years I've written various real-time audio programs. Its difficult to adhere to real-time regulations: you've got to get threading and memory management right.C++ is the often concidered the obvious choice language for large real-time audio programs: its a compiled language, and is deterministic in time if used carefully. This is necessary for real time (RT) work, and rules out VM based languages like Python for any low-latency work.
In C++ there's many a way to achieve real-time, one of which I have detailed here: https://github.com/harryhaaren/fypRealtimeCppPrograming
Other languages
C++ is one way to go, but in recent times there are various other programming languages which are becoming increasingly attractive to the real-time audio programmer. Particularly these two languages have caught my eye recently:Rust : http://www.rust-lang.org
Iolanguage: http://iolanguage.org
Both of these languages have certain characteristics which make them possible candidates for RT programming.
Rust
Language Overview
Rust is a language that focuses on "blocks", using boundaries. Integrity, availability and concurrency are its main goals. It uses lightweight tasks with message passing for concurrency, no shared memory.The Interesting Stuff
I'm most intrigued by the memory management of the language: everything is static unless declared "mut" (or "mutable"), and ownership of objects is very strict. This means that managing resources in a real-time safe way is well defined, and hence the code will be maintainable.Three different "pointer" types exist, as well as new concepts like owned boxes and managed boxes... these new concepts may aid memory allocation troubles, but perhaps it complicates them too, I don't have much experience yet with it, so only time will tell...
Learning It
Most of what I know comes straight from their homepage or tutorial:Homepage: www.rust-lang.org
Tutorial: http://static.rust-lang.org/doc/0.6/tutorial.html
Conclusion
A cool language, and if the memory concepts prove useful, it could be an awesome new language to learn for the audio-programming enthusiast.IOlanguage
Language Overview
This is a smalltalk inspired language, while also incorporating various different elements from other languages together. Actors based concurrency is used (a la Act1), while it is also kept small for embeddable purposes. Runs in a small VM.The Interesting Stuff
Intensive inspecting of object instances / program state (like LISP) aids debugging significantly. Extensive concurrency possibilities: co-routines, actors, futures and yield statements allow for flexible "time" programming.Learning It
Extensive documentation and example code here:http://iolanguage.org/scm/io/docs/IoGuide.html#Introduction
Conclusion
Cool language, unfortunately probably not fully real-time safe / deterministic due to running in a VM.Sum Up
"So what language will I use for my next project?" I hear you ask: well I'm staying with the tried and tested C++ for a while. I've dabbled with Vala previously ( see ValaLooper and Prehear ), but they're not quite suitable to RT work in my opinion.Although its nice to work with a slightly higher level language, its hard to determine if the generated code is genuinely real-time safe.
The perfect real-time safe code for me is code that is so simple, that proving its real-time safe under any conditions is trivial. Then the code is maintainable and readable.
Know of any RT capable language I've left out? Get in touch: I'm interested in hearing about it!
Labels:
audio programming,
c++,
iolanguage,
language,
programming,
realtime,
rust
Sunday, February 10, 2013
LV2 and Atom communication
EDIT: There are now better resources to learn LV2 Atom programming: please use them!
www.lv2plug.in/book
http://lac.linuxaudio.org/2014/video.php?id=24
/EDIT
Situation: You're trying to write a synth or effect, and you need to communicate between your UI and the DSP parts of the plugin, and MIDI doesn't cut it: enter Atom events. I found them difficult to get to grips with, and hope that this guide eases the process of using them to achieve communication.
It is the official documentation on the Atom spec. Just read the
description. It gives a good general overview of these things called Atoms.
This is "message passing": we send an Atom event from the UI to the DSP part of the plugin. This message needs to be safe to use in a real-time context.
(Note it is assumed that the concepts of URIDs is familiar to you. If they're not, go back and read this article: http://harryhaaren.blogspot.ie/2012/06/writing-lv2-plugins-lv2-overview.html )
Step 1: Set up an LV2_Atom_Forge. The lv2_atom_forge_* functions are how you build these events.
LV2_Atom_Forge forge;
lv2_atom_forge_init( &forge, map ); // map = LV2_URID_Map feature
something_Something represents an noun or item, while something_something (note the missing capital letter) is represents an aspect of the noun.
LV2_URID eg_Cat;
LV2_URID eg_name;
In short classes and types are Capitalized, and nothing else is.
LV2_Atom_Forge_Frame frame;
// Here we write a "blank" atom, which contains nothing (yet). We're going to fill that blank in with some data in a minute. A blank is a dictionary of key:value pairs. The property_head is the key, and the value comes after that. Note that the last parameter to this function represents the noun or type of item the Atom is about.
LV2_Atom* msg = (LV2_Atom*)lv2_atom_forge_blank(
&forge, &frame, 1, uris.eg_Cat );
// then we write a "property_head": this uses a URID to describe the next bit of data coming up, which will form the value of the key:value dictionary pair.
lv2_atom_forge_property_head(&forge, uris.eg_name, 0);
// now we write the data, note the call to forge_string(), we're writing string data here! There's a forge_int() forge_float() etc too!
lv2_atom_forge_string(&forge, "nameOfCat", strlen("nameOfCat") );
// Popping the frame is like a closing } of a function. Its a finished event, there's nothing more to write into it.
lv2_atom_forge_pop( &forge, &frame);
uint8_t obj_buf[1024];
// Then we tell the forge to use that buffer
lv2_atom_forge_set_buffer(&forge, obj_buf, 1024);
// now check the "Code to write messages" heading above, that code goes here, where you write the event.
// We have a write_function (from the instantiate() call) and a controller. These are used to send Atoms back. Note that the type of event is atom_eventTransfer: This means the host should pass it directly the the input port of the plugin, and not interpret it. write_function(controller, CONTROL_PORT_NUMBER,
lv2_atom_total_size(msg),
uris.atom_eventTransfer, msg);
const uint32_t notify_capacity = self->notify_port->atom.size;
lv2_atom_forge_set_buffer(&self->forge,
(uint8_t*)self->notify_port,
notify_capacity);
// Start a sequence in the notify output port
lv2_atom_forge_sequence_head(&self->forge,
&self->notify_frame, 0);
Now look back at the "Code to write messages" section. that's it, write the event into the Notify atom port, and done.
// Read incoming events directly from control_port, the Atom input port
LV2_ATOM_SEQUENCE_FOREACH(self->control_port, ev)
{
// check if the type of the Atom is eg_Cat
if (ev->body.type == self->uris.eg_Cat)
{
// get the object representing the rest of the data
const LV2_Atom_Object* obj = (LV2_Atom_Object*)&ev->body;
// check if the type of the data is eg_name
if ( obj->body.otype == self->uris.eg_name )
{
// get the data from the body
const LV2_Atom_Object* body = NULL;
lv2_atom_object_get(obj, self->uris.eg_name,
&body, 0);
// convert it to the type it is, and use it
string s = (char*)LV2_ATOM_BODY(body);
cout << "Cat's name property is " << s << endl;
}
}
}
Questions or comments, let me know :) -Harry
www.lv2plug.in/book
http://lac.linuxaudio.org/2014/video.php?id=24
/EDIT
Situation: You're trying to write a synth or effect, and you need to communicate between your UI and the DSP parts of the plugin, and MIDI doesn't cut it: enter Atom events. I found them difficult to get to grips with, and hope that this guide eases the process of using them to achieve communication.
Starting out
I advise you to first read this : http://lv2plug.in/ns/ext/atom/It is the official documentation on the Atom spec. Just read the
description. It gives a good general overview of these things called Atoms.
This is "message passing": we send an Atom event from the UI to the DSP part of the plugin. This message needs to be safe to use in a real-time context.
(Note it is assumed that the concepts of URIDs is familiar to you. If they're not, go back and read this article: http://harryhaaren.blogspot.ie/2012/06/writing-lv2-plugins-lv2-overview.html )
Step 1: Set up an LV2_Atom_Forge. The lv2_atom_forge_* functions are how you build these events.
LV2_Atom_Forge forge;
lv2_atom_forge_init( &forge, map ); // map = LV2_URID_Map feature
Atoms
Atoms are "plain old data" or POD. They're a sequence of bytes written in a contiguous part of memory. Moving them around is possible with a single memcpy() call.Writing Atoms
Understanding the URID naming convention
// we need URID's to represent functionality: There's a naming scheme here, and its *essential* to understand it. Say the functionality we want to represent is a name of a Cat (similar to the official atom example). Here eg_Cat represents the "noun" or "item" we are sending an Atom about. eg_name represents something about the eg_Cat.something_Something represents an noun or item, while something_something (note the missing capital letter) is represents an aspect of the noun.
LV2_URID eg_Cat;
LV2_URID eg_name;
In short classes and types are Capitalized, and nothing else is.
Code to write messages
// A frame is essentially a "holder" for data. So we put our event into a LV2_Atom_Forge_Frame. These frames allow the "appending" or adding in of data.LV2_Atom_Forge_Frame frame;
// Here we write a "blank" atom, which contains nothing (yet). We're going to fill that blank in with some data in a minute. A blank is a dictionary of key:value pairs. The property_head is the key, and the value comes after that. Note that the last parameter to this function represents the noun or type of item the Atom is about.
LV2_Atom* msg = (LV2_Atom*)lv2_atom_forge_blank(
&forge, &frame, 1, uris.eg_Cat );
// then we write a "property_head": this uses a URID to describe the next bit of data coming up, which will form the value of the key:value dictionary pair.
lv2_atom_forge_property_head(&forge, uris.eg_name, 0);
// now we write the data, note the call to forge_string(), we're writing string data here! There's a forge_int() forge_float() etc too!
lv2_atom_forge_string(&forge, "nameOfCat", strlen("nameOfCat") );
// Popping the frame is like a closing } of a function. Its a finished event, there's nothing more to write into it.
lv2_atom_forge_pop( &forge, &frame);
From the UI
// To write messages, we set up a buffer:uint8_t obj_buf[1024];
// Then we tell the forge to use that buffer
lv2_atom_forge_set_buffer(&forge, obj_buf, 1024);
// now check the "Code to write messages" heading above, that code goes here, where you write the event.
// We have a write_function (from the instantiate() call) and a controller. These are used to send Atoms back. Note that the type of event is atom_eventTransfer: This means the host should pass it directly the the input port of the plugin, and not interpret it. write_function(controller, CONTROL_PORT_NUMBER,
lv2_atom_total_size(msg),
uris.atom_eventTransfer, msg);
From the DSP
// Set up forge to write directly to notify output port. This means that when we create an Atom in the DSP part, we don't allocate memory, we write the Atom directly into the notify port.const uint32_t notify_capacity = self->notify_port->atom.size;
lv2_atom_forge_set_buffer(&self->forge,
(uint8_t*)self->notify_port,
notify_capacity);
// Start a sequence in the notify output port
lv2_atom_forge_sequence_head(&self->forge,
&self->notify_frame, 0);
Now look back at the "Code to write messages" section. that's it, write the event into the Notify atom port, and done.
Reading Atoms
// Read incoming events directly from control_port, the Atom input port
LV2_ATOM_SEQUENCE_FOREACH(self->control_port, ev)
{
// check if the type of the Atom is eg_Cat
if (ev->body.type == self->uris.eg_Cat)
{
// get the object representing the rest of the data
const LV2_Atom_Object* obj = (LV2_Atom_Object*)&ev->body;
// check if the type of the data is eg_name
if ( obj->body.otype == self->uris.eg_name )
{
// get the data from the body
const LV2_Atom_Object* body = NULL;
lv2_atom_object_get(obj, self->uris.eg_name,
&body, 0);
// convert it to the type it is, and use it
string s = (char*)LV2_ATOM_BODY(body);
cout << "Cat's name property is " << s << endl;
}
}
}
Conclusion
That's it. Its not hard. It just takes getting used to. Its actually a very powerful and easy way of designing a program / plugin, as it *demands* separation between the threads, which is a really good thing.Questions or comments, let me know :) -Harry
Labels:
documentation,
learn,
lv2 atom,
plugin,
tutorial
Thursday, January 17, 2013
MlTutorial: Working with the MediaLovinToolkit
Hi!
I've been interested in doing some video coding for a while now, but never really got into it yet. Until today, when I re-attempted (yes, I'd tried before :) to achieve some simple functionality with MLT.
Initially I found it very difficult to find any resources as to how one can use the MLT framework from C++, but some googling led me to various resources scattered around the internet.
The MLT github repo as a super-simple example (which although informative doesn't scale up to the use of filters or any advanced functionality):
https://github.com/mltframework/mlt/blob/master/src/examples/play.cpp
A search around the net showed me this post on a forum http://ubuntuforums.org/showthread.php?p=7370184
This seemed to be more along the lines of what I had hoped for, however the code segfaults upon running...
Finally the "tests" subdir in the MLT tarball provide some test program code, but its difficult to understand (IMO) as its not commented for learning purposes: https://github.com/mltframework/mlt/tree/master/src/tests
So between these resources I've decided to bunch together some examples of how to use MLT using C++. The code is online on github, and may be useful to others hoping to learn to use the MLT framework.
There's currently two "playback" tutorials, and one "filter" tutorial. Reading them will show the rough design of the MLT library, and how to use it. Advanced functionality tutorials will be added as I learn it myself :)
https://github.com/harryhaaren/mltutorial
Welcoming issues / merge requests from MLT users / devs / anybody!
Cheers, -Harry
I've been interested in doing some video coding for a while now, but never really got into it yet. Until today, when I re-attempted (yes, I'd tried before :) to achieve some simple functionality with MLT.
Initially I found it very difficult to find any resources as to how one can use the MLT framework from C++, but some googling led me to various resources scattered around the internet.
The MLT github repo as a super-simple example (which although informative doesn't scale up to the use of filters or any advanced functionality):
https://github.com/mltframework/mlt/blob/master/src/examples/play.cpp
A search around the net showed me this post on a forum http://ubuntuforums.org/showthread.php?p=7370184
This seemed to be more along the lines of what I had hoped for, however the code segfaults upon running...
Finally the "tests" subdir in the MLT tarball provide some test program code, but its difficult to understand (IMO) as its not commented for learning purposes: https://github.com/mltframework/mlt/tree/master/src/tests
So between these resources I've decided to bunch together some examples of how to use MLT using C++. The code is online on github, and may be useful to others hoping to learn to use the MLT framework.
There's currently two "playback" tutorials, and one "filter" tutorial. Reading them will show the rough design of the MLT library, and how to use it. Advanced functionality tutorials will be added as I learn it myself :)
https://github.com/harryhaaren/mltutorial
Welcoming issues / merge requests from MLT users / devs / anybody!
Cheers, -Harry
Tuesday, December 11, 2012
Getting to grips with Ganv
So you want to create a "Graph" based program? Use Ganv! It looks awesome, and David Robillard has already done the hard parts :)
So you'll need to install:
ganv
gtkmm
Easiest way to do this is just checkout Drobilla's svn:
svn co http://svn.drobilla.net/lad/trunk drobillad
./waf configure --prefix=/usr
./waf
./waf install
Read the code, its pretty self explanatory.
Ganv: is the way you interface with the whole
FlowCanvas: is the canvas itself, behind the scenes.
GTKmm: is your window, and you do what you like with it.
So the final structure is somewhat like this:
Gtk window
Ganv Canvas
Ganv Module
Ganv Port
Ganv Edge (connects ports)
That's all for now, hope I saved you a bit of time and effort! -Harry
Starting Out:
We're just doing a single file, proof of concept right now. Nothing fancy yet.So you'll need to install:
ganv
gtkmm
Easiest way to do this is just checkout Drobilla's svn:
svn co http://svn.drobilla.net/lad/trunk drobillad
./waf configure --prefix=/usr
./waf
./waf install
What next:
Install ganv system wide. Download this tutorial's code from here: https://github.com/harryhaaren/openAudioProgrammingTutorials/blob/master/flowCanvas/flowcanvas.cppRead the code, its pretty self explanatory.
Then what?
Its a good idea to get to grips with how all this works together:Ganv: is the way you interface with the whole
FlowCanvas: is the canvas itself, behind the scenes.
GTKmm: is your window, and you do what you like with it.
So the final structure is somewhat like this:
Gtk window
Ganv Canvas
Ganv Module
Ganv Port
Ganv Edge (connects ports)
That's all for now, hope I saved you a bit of time and effort! -Harry
Monday, November 19, 2012
Luppp: Status as of Nov '12?
Hey everybody,
I'm writing to let you all know that the Luppp project is not dead. I've not posted here about Luppp since May, and also haven't pushed code to the repo at github for 6 months. So what is the status?
Luppp is "taking the back seat" for a while. I mean that real-life has currently taken over, and with my final year of college and projects on, I don't see myself spending a lot of time on Luppp before the next LAC (that's the middle of May).
Don't worry, the reason for not pushing code recently is only partly due to time, the other reason is that during the summer I started doing (another...) total re-write. This time I'm confident that the code is a lot more maintainable. I hope :)
Till next, -Harry
I'm writing to let you all know that the Luppp project is not dead. I've not posted here about Luppp since May, and also haven't pushed code to the repo at github for 6 months. So what is the status?
Luppp is "taking the back seat" for a while. I mean that real-life has currently taken over, and with my final year of college and projects on, I don't see myself spending a lot of time on Luppp before the next LAC (that's the middle of May).
Don't worry, the reason for not pushing code recently is only partly due to time, the other reason is that during the summer I started doing (another...) total re-write. This time I'm confident that the code is a lot more maintainable. I hope :)
Till next, -Harry
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. (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. (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:
- manifest.ttl
- <pluginName>.ttl
- <pluginName>.so
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 ;
]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!
Labels:
beginning lv2,
LV2,
overview of lv2,
plugin,
write
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
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:
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
Labels:
live,
Luppp,
pitch shift,
realtime,
resample,
timestretch
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
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:
-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!
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:
-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:
Tuesday, January 17, 2012
Luppp: Settling into Github
In the last couple of days the Luppp repo has made a new home on github, now complete with issue tracker & wiki.
The "manual" for Luppp will be constructed slowly in the Wiki part of github:
https://github.com/harryhaaren/Luppp/wiki
It currently contains some info on how to download & build:
http://wiki.github.com/harryhaaren/Luppp/downloading-building-installing
as well as a basic overview of what does what in the GUI:
https://github.com/harryhaaren/Luppp/wiki/Interface-Overview
Also new: A master "progress" widget that shows time into your 4 bars, or time till the next "4th queue" process, ie: Event quantization.
Read "When it goes from red to green, your Scene will change."
Fancy GUI suggestions welcomed, I don't really know how to spice this one up yet...
Hopefully in the next couple of days I can update it some more, and fix a couple of critical bugs that really hinder the use of scenes. More news soon!
The "manual" for Luppp will be constructed slowly in the Wiki part of github:
https://github.com/harryhaaren/Luppp/wiki
It currently contains some info on how to download & build:
http://wiki.github.com/harryhaaren/Luppp/downloading-building-installing
as well as a basic overview of what does what in the GUI:
https://github.com/harryhaaren/Luppp/wiki/Interface-Overview
Also new: A master "progress" widget that shows time into your 4 bars, or time till the next "4th queue" process, ie: Event quantization.
Read "When it goes from red to green, your Scene will change."
Fancy GUI suggestions welcomed, I don't really know how to spice this one up yet...
Hopefully in the next couple of days I can update it some more, and fix a couple of critical bugs that really hinder the use of scenes. More news soon!
Labels:
github,
issue tracker,
Luppp,
manual,
wiki
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! ):
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! ):
Monday, December 19, 2011
Tutorial: Load & Loop Samples
Hey all,
This tutorial will show you how to load a sample into memory, and then play it back trough a JACK port, continually looping. There's not really that much to it, just a bit of thinking of the order things happen, and arrays.
If you've read the "Writing a sample" tutorial, you'll already be familiar with LibSndFile, the library we use to read / write samples, so there's nothing too hard to handle :)
Check out the source here: https://github.com/harryhaaren/Linux-Audio-Programming-Documentation/blob/master/loopedSample/loopedSample.cpp
Any queries / suggestions, you know how to get to me :) -Harry
This tutorial will show you how to load a sample into memory, and then play it back trough a JACK port, continually looping. There's not really that much to it, just a bit of thinking of the order things happen, and arrays.
If you've read the "Writing a sample" tutorial, you'll already be familiar with LibSndFile, the library we use to read / write samples, so there's nothing too hard to handle :)
Check out the source here: https://github.com/harryhaaren/Linux-Audio-Programming-Documentation/blob/master/loopedSample/loopedSample.cpp
Any queries / suggestions, you know how to get to me :) -Harry
Saturday, December 17, 2011
Arch Linux : The quest for a minimal system with maximal RT performance
Hey All,
My install of TangoStudio is getting old, and its repos are getting polluted with conflicts & nastiness, that means a reinstall! So a quick bit of searching for a minimal yet configurable, RT capable and rock-solid led to some intresting distro choices.
TangoStudio - Worked well enough ( 30ms lowest lat on stock kernel )
64Studio - a touch oudated by now, but it was always very good
Pure::Dyne - personal favorite for a while, also gone a touch out of date
Gentoo - probably not good for a non-kernel hacker type... but then
Arch has been a distro I've tried a couple of times because I love the sound of it:
So off I went, download the 380mb ISO, install it on a seperate partition, get going. You get a minimal system that drops to a root prompt on install, and "startx" isn't going to help much untill you install you video driver packages etc. Note this can be done during install but I opted not to, as I wanted the control to select only needed packages.
So after a bit of haggling with the X server, reading some wiki entries using the text only webbroswer links, and installing the "slim" display manager, messing with /etc/inittab and ~/.xinitrc there's a system up and running, straight to a graphical logic screen (with awesome "darch-white" theme") and then to a barebones LXDE desktop with OpenBox as WM.
The speed of the menu's & actions in unreal, it feels like its there before you clicked. Some small issues with ugly themes and nasty font's were quickly ironed out using lxapperance.
Couple of "nasty" little things:
-Hotkeys: https://wiki.archlinux.org/index.php/Xbindkeys
-Keymap: https://wiki.archlinux.org/index.php/loadkeys
-Touchpad: https://wiki.archlinux.org/index.php/Touchpad
Then on to the audio side of things:
There's a project called ArchAudio, who are maintaining lots of up to date software for audio / multimedia purposes, you'll want to install that repo:
http://archaudio.org/packages/ has all the info you'll need!
I'm a JACK1 user, so first thing I wanted to do was install that:
the "Extra" repository has a build of 0.121.3, so a simple pacman -S extra/jack1 done the trick. FFADO installation for my Echo AudioFire was quick and painless: pacman -S libffado That installs your needed library, the ffado-mixer, ffado-test etc programs, and sets up the privelidges so that you can run JACK in RT mode.
If you want to use this install as your "daily", you'll need to install a mountain of stuff, things like gtkmm,flashplayers, media players, codecs, etc. But if you want to run audio... no need. Actually you'd be better off without that stuff.
The end result:
A system that will run JACK @ 4ms latency, 192kHz samplerate, with a *non-RT* kernel. That's currently still compiling, and I'm hoping to squeeze another ms or 2 off the RT_PREEMPT & IRQ tuning (& IRQ threading.. but that's dangerous territory AFAIK!)
So far I'm very satisfied with Arch and its amazing documentation :)
Will keep this up to date with the RT kernel progress & latency tuning,
-Harry
My install of TangoStudio is getting old, and its repos are getting polluted with conflicts & nastiness, that means a reinstall! So a quick bit of searching for a minimal yet configurable, RT capable and rock-solid led to some intresting distro choices.
TangoStudio - Worked well enough ( 30ms lowest lat on stock kernel )
64Studio - a touch oudated by now, but it was always very good
Pure::Dyne - personal favorite for a while, also gone a touch out of date
Gentoo - probably not good for a non-kernel hacker type... but then
Arch has been a distro I've tried a couple of times because I love the sound of it:
Arch Linux, a lightweight and flexible Linux® distribution that tries to Keep It Simple.However any time I tried it I had been put off by its "initial configuration" that needs doing before you can get yourself online to look at some forums / wiki's for help!
So off I went, download the 380mb ISO, install it on a seperate partition, get going. You get a minimal system that drops to a root prompt on install, and "startx" isn't going to help much untill you install you video driver packages etc. Note this can be done during install but I opted not to, as I wanted the control to select only needed packages.
So after a bit of haggling with the X server, reading some wiki entries using the text only webbroswer links, and installing the "slim" display manager, messing with /etc/inittab and ~/.xinitrc there's a system up and running, straight to a graphical logic screen (with awesome "darch-white" theme") and then to a barebones LXDE desktop with OpenBox as WM.
The speed of the menu's & actions in unreal, it feels like its there before you clicked. Some small issues with ugly themes and nasty font's were quickly ironed out using lxapperance.
Couple of "nasty" little things:
-Hotkeys: https://wiki.archlinux.org/index.php/Xbindkeys
-Keymap: https://wiki.archlinux.org/index.php/loadkeys
-Touchpad: https://wiki.archlinux.org/index.php/Touchpad
Then on to the audio side of things:
There's a project called ArchAudio, who are maintaining lots of up to date software for audio / multimedia purposes, you'll want to install that repo:
http://archaudio.org/packages/ has all the info you'll need!
I'm a JACK1 user, so first thing I wanted to do was install that:
the "Extra" repository has a build of 0.121.3, so a simple pacman -S extra/jack1 done the trick. FFADO installation for my Echo AudioFire was quick and painless: pacman -S libffado That installs your needed library, the ffado-mixer, ffado-test etc programs, and sets up the privelidges so that you can run JACK in RT mode.
If you want to use this install as your "daily", you'll need to install a mountain of stuff, things like gtkmm,flashplayers, media players, codecs, etc. But if you want to run audio... no need. Actually you'd be better off without that stuff.
The end result:
A system that will run JACK @ 4ms latency, 192kHz samplerate, with a *non-RT* kernel. That's currently still compiling, and I'm hoping to squeeze another ms or 2 off the RT_PREEMPT & IRQ tuning (& IRQ threading.. but that's dangerous territory AFAIK!)
So far I'm very satisfied with Arch and its amazing documentation :)
Will keep this up to date with the RT kernel progress & latency tuning,
-Harry
Labels:
arch audio,
arch linux,
JACK,
linux audio distro,
realtime
Wednesday, November 16, 2011
Tutorial: JACK Ringbuffers
Hey All,
A quick tutorial on basic Jack ringbuffer usage. Ringbuffers are an easy way to exchange data from one thread to another in a realtime safe way. This means that no thread will block when reading or writing, and hence you use ringbuffers in a real-time thread.
For this tutorial I'll be using the "standard" linux audio ringbuffer that comes with JACK. Its docs are available here: http://jackaudio.org/files/docs/html/ringbuffer_8h.html
So what were going to do is:
1. Setup a ring buffer
2. Register a JACK client, and give it a process callback
3. Write data in the "local" thread, ie: our main()
4. Make JACK print out any data it recieves in its RT thread
Note that here the JACK thread is our READ thread , and the main() thread is the WRITE thread. This is important, because a ringbuffer like the JACK one will only work in ONE direction.
Find the well commented source here: https://sites.google.com/site/harryhaaren/Home/main.cpp
Note the compile command is: g++ main.cpp `pkg-config --cflags --libs jack` (its also in the source.. but just to make sure :)
Responses welcome, -Harry
PS: Note there are many different implementations of ringbuffers, all with benefits of their own. The JACK ringbuffer is a simple and IMO easily usable one, and that's the reason I like it. I don't want a fancy impossible multi-read multi-write templated 13 class derived special oval ringbuffer, just something that does what it says on the tin :)
A quick tutorial on basic Jack ringbuffer usage. Ringbuffers are an easy way to exchange data from one thread to another in a realtime safe way. This means that no thread will block when reading or writing, and hence you use ringbuffers in a real-time thread.
For this tutorial I'll be using the "standard" linux audio ringbuffer that comes with JACK. Its docs are available here: http://jackaudio.org/files/docs/html/ringbuffer_8h.html
So what were going to do is:
1. Setup a ring buffer
2. Register a JACK client, and give it a process callback
3. Write data in the "local" thread, ie: our main()
4. Make JACK print out any data it recieves in its RT thread
Note that here the JACK thread is our READ thread , and the main() thread is the WRITE thread. This is important, because a ringbuffer like the JACK one will only work in ONE direction.
Find the well commented source here: https://sites.google.com/site/harryhaaren/Home/main.cpp
Note the compile command is: g++ main.cpp `pkg-config --cflags --libs jack` (its also in the source.. but just to make sure :)
Responses welcome, -Harry
PS: Note there are many different implementations of ringbuffers, all with benefits of their own. The JACK ringbuffer is a simple and IMO easily usable one, and that's the reason I like it. I don't want a fancy impossible multi-read multi-write templated 13 class derived special oval ringbuffer, just something that does what it says on the tin :)
Labels:
c++,
JACK,
multithreading,
ringbuffer,
tutorial
Wednesday, September 21, 2011
Luppp : 30,000 loc
Somewhere yesterday Luppp passed the 30 k lines mark, currently on 30, 255. There's been quite some UI work going on, as well as some (essential) features being implemented in the engine... full update soon :)
Subscribe to:
Posts (Atom)








