Showing posts with label linux vst. Show all posts
Showing posts with label linux vst. Show all posts

Monday, February 24, 2014

Linux VST Plug-in for Ardour

I now have a functioning template for a working VST effect in Ardour. I'm still using 2.x format, since my version of Ardour (v3.0) doesn't recognize VST v3.0 (at least not on a Linux platform). The video below is just a screen capture of the plug in in action. The effect algorithm is just a signal-finding method I used at the cosmic ray experiment I worked at during grad school called the Generalized Second Difference (Mariscotti 1995).

Despite the controls going from zero to one, the parameter 'z' really ranges from 0 to 30 and 'm' goes from 1 to 17. The filter kernel will have 3 + 2*m*z elements, so this works well to test the limits of the DSP (it actually performed way better than I expected). 'm' determines the "width" of the filter while 'z' affects the "smoothness".

Some notes:

I compiled everything but the examples in VST3 SDK into a static library. I copy vstplugmain.cpp into whatever project I'm working at and add -I${VST_HOME} to my include flags for compiling. I add the static library directly so the compiler can pull whatever it needs from it when creating the plugin .so file. With that "template", all I really need to use for reference when writing the code for the plugin are the files in public.sdk/sources/vst2.x.

Still can't get my own GUI working. When I try to use Qt, Ardour seg-faults before the recent projects window pops up. When I try skeleton code Ardour crashes when I try to open the controls for the plugin. I presume the latter case occurs because I'm not handling signals from the Host program. But I don't understand what's going on in the first case. I can't run a proper "debugging" environment because I didn't build debugging versions of any of the dependent packages for Ardour. Not saying I can't, just looking at a few day's work to get that going and I feel like the solution probably isn't all that complicated.

Friday, February 7, 2014

Ardour and Linux VST

I have Ardour 3 compiled and working. I don't have a realtime kernel, so I can't run Jack in realtime mode and there is some significant latency (~1/4-1/2 second, didn't time exactly). I looked up the interwebs to see what was involved in getting a realtime kernel set up and found this gem:

http://askubuntu.com/questions/72964/how-can-i-install-a-realtime-kernel 

I followed the instructions exactly on a VM running the same OS as my notebook and it worked without a hitch. I decided it may be better to use the same kernel version (3.2.0). The closest match with a corresponding RT patch was 3.2.52. It took about two hours to compile everything but so far it's working perfectly. Just one hitch, not sure it's totally related to the kernel update: Firefox and emacs look-and-feel reverted to some ugly state and Firefox stopped recognizing the printer. I did some ridiculous things like reinstalling gtk3 and cups. Eventually, I just rebooted and everything was back to normal (but I have and RT kernel now).

I tried running Ardour with Jack in RT mode, but it wouldn't open my project. Unsure if I needed to rebuild everything (looking back, I don't think I had to) I felt it better to do that anyway, since originally I was adding packages kind of willy-nilly as I was building the dependencies. The new build of Ardour still didn't work. After scanning the interwebs for people with similar problems, I found a solution that worked for me: Simply add my username to the audio group with sudo usermod -a -G audio ${username}. The latency is much more manageable now (~30-40ms).  Not good for real production stuff, but good enough as a sandbox for plugin development.

I tried compiling the examples that come with the VST3 SDK. The following define flags will get most to compile:

-DPTHREADS -DBYTEORDER=kLittleEndian -DFORMAT_INT64A="\"%ld\"" -DFORMAT_UINT64A="\"%lu\"" -DENDLINE_A="\"\\n\""
You will also need to define things like -DRELEASE/-DDEBUG/-DDEVELOPMENT and -DPLATFORM_64.

Even with all these, I still had to hack my way through to get some of the code to compile. I won't reproduce the code here but if you've been programming C/C++ for a while you should find the required mods to be pretty straightforward.

I skipped trying to compile the examples, especially because a bunch are in a subdirectory with a space in the name (pain in the butt!). I copied one of the examples into QtCreator, tinkered with the configuration a bit and got it to build a nice SO.

When Linux VST's are enabled in Ardour, it searches the standard shared object library path for a folder named lxvst (I think status quo is to put it in /usr/local/lib/lxvst). I opened the plugin manager by right clicking on the mixer pane. There wasn't anything obviously wrong with the SO itself, so I searched through the Ardour source code to find out where the load was failing. Turns out Ardour 3 isn't equipped to read Linux VSTs compiled according to VST version 3. It wasn't clear to me how to mod Ardour to get this to work. I also haven't been able to figure out how to get the example code to build in 2.x format.

Instead, I created a new dummy plugin called JustVisiting. It took a little bit of tinkering, but eventually I got Ardour to recognize it. Here's the skeleton code:

justvisiting.h:

#include <stdio>
#include "public.sdk/source/vst2.x/audioeffectx.h"

class JustVisiting : public AudioEffectX {
public:
    JustVisiting(audioMasterCallback iAudioMaster, 
        VstInt32 iNumPrograms, VstInt32 iNumParams);
    void processReplacing(float **inputs, float **outputs, VstInt32 sampleFrames);
    bool getVendorString(char *text);
    VstInt32 getVendorVersion();
    VstInt32 canDo(char *text);
    VstPlugCategory getPlugCategory();
};

justvisiting.cpp:

#include "justvisiting.h"

AudioEffect *createEffectInstance(audioMasterCallback audioMaster) {
    JustVisiting *effect = new JustVisiting(audioMaster,1,1);
    return effect;
}

JustVisiting::JustVisiting(audioMasterCallback iAudioMaster, 
    VstInt32 iNumPrograms, VstInt32 iNumParams)
    : AudioEffectX(iAudioMaster,iNumPrograms,iNumParams){
    // nothing to allocate
    this->setNumInputs(2);
    this->setNumOutputs(2);
    this->setBlockSize(1);
}

void JustVisiting::processReplacing(float **inputs, float **outputs, VstInt32 sampleFrames) {
    // TODO: do something
}

bool JustVisiting::getVendorString(char *text) {
    sprintf(text,"CamelNote");
}

VstInt32 JustVisiting::getVendorVersion() {
    return 0;
}

VstInt32 JustVisiting::canDo(char *text) {
    if ( strcasecmp(text,"sendVstEvents") )
        return -1;
    else if ( strcasecmp(text,"sendVstMidiEvent") )
        return -1;
    else if ( strcasecmp(text,"receiveVstEvents") )
        return -1;
    else if ( strcasecmp(text,"receiveVstMidiEvent") )
        return -1;
    else if ( strcasecmp(text,"receiveVstTimeInfo") )
        return 0;
    else if ( strcasecmp(text,"offline") )
        return -1;
    else if ( strcasecmp(text,"midiProgramNames") )
        return -1;
    else if ( strcasecmp(text,"bypass") )
        return -1;
    return 0;
}

VstPlugCategory JustVisiting::getPlugCategory() {
    return kPlugCategEffect;
}
Be sure to build this in with vstplugmain.cpp from the VST SDK so that the VSTPluginMain symbol gets compiled in. Ardour uses this as the entry point for the Linux VST (It actually looks for 'main' first, and if it can't find it, then looks for VSTPluginMain. When if finds that one, it will complain that the version is too new and may not be compatible with Ardour). At the bare minimum, you'll need to define processReplacing, but there are a number of other member functions you should override for safety. I haven't gone through them all yet.