CLAP: The New Audio Plug-in Standard (by U-he, Bitwig and others)

DSP, Plugin and Host development discussion.
Post Reply New Topic
RELATED
PRODUCTS

Post

A_SN wrote: Fri Jul 08, 2022 6:46 pm
koalaboy wrote: Wed Jun 15, 2022 6:03 pm there's a reason that C/C++/Rust are still leading the way in performance when necessary.
I don't know about the practical aspects of accomplishing this, but compilers these days turn all code into an intermediary representation, then the IR is turned into another IR (same format) that is optimised depending on the target, then that IR is turned into whatever type of bytecode. In theory you could have plugins that represent an IR (or something that can be parsed by a LLVM parser), then the DAW could call CLAP's LLVM compiler which would compile the plugin IR into a binary, and cache the compilation for later.
As it turns out... the LLVM bitcode that Clang produces from C/C++ is already machine and platform dependent... because that's kinda what you have to do for performance.

Post

mystran wrote: Fri Jul 08, 2022 7:34 pm As it turns out... the LLVM bitcode that Clang produces from C/C++ is already machine and platform dependent... because that's kinda what you have to do for performance.
Yeah but you're most likely thinking of Clang outputting a .bc file, that's not quite what I'm talking about. LLVM (not talking about Clang specifically) parses all languages into an IR, then at a later stage it turns that naive IR into an IR that is optimised according to the target architecture. So what you want into your universal plugin format is something that reflects the naive IR, which is what things like SPIR do, SPIR represents a GPU shader or kernel without anything platform-specific. Interestingly SPIR used LLVM but SPIR-V doesn't anymore (I assume they didn't want to rely on LLVM's own format so much), but the SPIR-LLVM IR can still be converted to SPIR-V. I think SPIR-V could definitely inspire what I have in mind for CLAP.

It sounds like you're saying what I'm talking about isn't possible, it's already been done though, I think Google's PNaCl did something similar.
Developer of Photosounder (a spectral editor/synth), SplineEQ and Spiral

Post

I doubt requiring regular users to have the whole LLVM installed on their machines as a prerequisite just to be able to locally compile JIT based plugins in order to bypass notarization is a good idea, but ok.

Post

A_SN wrote: Fri Jul 08, 2022 7:52 pm It sounds like you're saying what I'm talking about isn't possible, it's already been done though, I think Google's PNaCl did something similar.
Ofcourse you can compile to portable bytecode and then JIT that to native. JVM does that, .NET does that, emscripten does that... the list goes on and on...

The question is not whether this is actually possible, but rather whether you can match the performance of C/C++ code that might be making decisions based on the platform already at the preprocessor stage.

Post

EvilDragon wrote: Fri Jul 08, 2022 8:10 pm I doubt requiring regular users to have the whole LLVM installed on their machines as a prerequisite just to be able to locally compile JIT based plugins in order to bypass notarization is a good idea, but ok.
That's absolutely not how it works, I wish you would all become more familiar with the topic before making conclusions or dismissing anything. The CLAP library used by the DAW would include whatever parts of LLVM (which is a set of libraries, not a program) it needs go compile from IR to native binary (it's not even that big due to not containing all the big language parsing stuff). So it's just a library that CLAP would use, nothing extraordinary about this. Again, that kind of approach is common enough, your GPU drivers have LLVM included for compiling shaders and kernels, there's no such thing as having "the whole LLVM installed" for this (I assume you said this because you're thinking of how your system's package manager let's you install "LLVM").

Oh and it's not "just to bypass notarisation", as people have said in this thread weeks ago you need such an approach now. This isn't the 1990s anymore, "one binary for one platform supported" isn't good enough in the 2020s. I already made points about futureproofing through this approach.
mystran wrote: Fri Jul 08, 2022 8:19 pm Ofcourse you can compile to portable bytecode and then JIT that to native. JVM does that, .NET does that, emscripten does that... the list goes on and on...

The question is not whether this is actually possible, but rather whether you can match the performance of C/C++ code that might be making decisions based on the platform already at the preprocessor stage.
And yet that's not what I'm talking about. I'm not talking about interpreting a portable bytecode JIT like WebAssembly does, I'm talking about compiling an intermediate representation to a native binary machine code blob, then running that. Again, that's the SPIR approach (and apparently what PNaCl also did). I wish you knew more about the topic.

So in that case, like I've already said before, you're moving part of the compilation from the dev's machine to the user's machine, with the advantage that you can target the user's specific architecture (kind of like Homebrew does as opposed to downloading binaries, but that's something else), so it's exactly the same result except you can better target the architecture.

As for the preprocessor thing, well, yeah your code won't know anything about the machine it's on at that stage, but there are alternatives (for instance like how you can detect CPU instruction set at run time), and it's not such a big deal. I can think of an example where that could be a slight problem (for instance in my endianness-sensitive code I have a macro for assuming LE or not assuming endianness), but I can't imagine this being a big deal.
Developer of Photosounder (a spectral editor/synth), SplineEQ and Spiral

Post

A_SN wrote: Fri Jul 08, 2022 5:14 pm
DRMR wrote: Fri Jul 08, 2022 4:56 pm As with all software on MacOS: yes.
Damn shame, I thought maybe whoever makes a new plugin format in the 2020s would consider making a portable interpreted plugin format, so you could have a plugin that works on any platform, even on a WebAssembly host (I feel strongly that WebAssembly is the future that will allow me to soft-ditch macOS).
Which is why, in fact, we did consider it :)

Nothing stops you compiling a clap to wasm today.

Whether there is a daw which can run wasm directky at audio rate is a separate issue. There isn’t. Today.

Post

I have a simple question that hopefully isn't off topic, but have not seen addressed by anyone who is currently compiling CLAP plugins. Are symbol exports destined to follow a prescribed rule on decorations? I think some of my plugins in the past had problems because of MinGW not following the MSVC symbol decorations.

Post

mystran wrote: Fri Jul 08, 2022 11:14 am I guess the argument here is that you can't directly turn extensions into interfaces and pass vtables because the 'this' pointers would have wrong offsets as all the CLAP methods take the same 'clap_plugin_t' pointer?
I was thinking about this. People can write extensions however they like right? And an extension is just a list of function pointers. So the author of a CLAP extension could choose to use the same trick as COM (make a C struct that is laid out exactly like a C++ interface).

It still 100% qualifies as a regular CLAP extension. (clap_plugin_t has no virtual methods of its own, so there is no compatibility issues there I think. Probly need to try it to be sure.).

With this one simple trick - either plugin, or host, or both can opt-in to calling the extension directly via the high-efficiency C++ interface.
If you do this, then VST3 doesn't get to claim to be the more efficient calling convention any longer :)
mystran wrote: Fri Jul 08, 2022 11:14 am That's true.. but you don't need to go through the vtable at all if you instead just populate the extensions with pointers to regular (non-virtual) or static methods.
For sure, if you write a plugin directly in a C style (no C++ objects) - you don't pay the overhead of a 'helper' to convert from C to C++. But realistically, a large segment of our industry writes plugins in C++, using classes and objects. They are worth considering.

Post

Jeff McClintock wrote: Fri Jul 08, 2022 10:56 pm
mystran wrote: Fri Jul 08, 2022 11:14 am I guess the argument here is that you can't directly turn extensions into interfaces and pass vtables because the 'this' pointers would have wrong offsets as all the CLAP methods take the same 'clap_plugin_t' pointer?
I was thinking about this. People can write extensions however they like right? And an extension is just a list of function pointers. So the author of a CLAP extension could choose to use the same trick as COM (make a C struct that is laid out exactly like a C++ interface).
If you write your own extensions.. then sure.. but to get anything done you have to support a couple of standard extensions (eg. audio ports, probably parameters, note ports for instruments, gui if you want such a thing) which all take a pointer to the plugin as the first argument to every method.
mystran wrote: Fri Jul 08, 2022 11:14 am That's true.. but you don't need to go through the vtable at all if you instead just populate the extensions with pointers to regular (non-virtual) or static methods.
For sure, if you write a plugin directly in a C style (no C++ objects) - you don't pay the overhead of a 'helper' to convert from C to C++. But realistically, a large segment of our industry writes plugins in C++, using classes and objects. I don't think the industry is moving back to C.
So .. I posted the basic idea above, but.. here's my "zero-cost" wrapper (ie. all the 'helpers' are supposed to either inline or compile into a trivial tail-calls = regular direct jumps) so far:

https://github.com/signaldust/clap-glue [edit: now a proper repo]

Basically implement an object with all the methods you need (including whatever extensions you want) then in plug_get_extension query extensions with ClapExt_Whatever<MyPlug>::check(id) to get the relevant table to generate (at which point the compiler will also check that you really implemented the stuff).. and then just declare a global factory object (one per plugin class) like this:

Code: Select all

static ClapFactory<MyPlug>  test_factory;
Rest of it is then supposed to happen by magic... and I'd argue it's pretty C++ and OOP even if there's no vtables in sight. :)

edit: Just for emphasis.. you absolutely CAN do things like implement general GUI support once and then just derive your plugin from a base-class that brings that functionality in... so it's not like you lose inheritance, you just don't need a vtable for that anymore.
Last edited by mystran on Sat Jul 09, 2022 1:55 pm, edited 1 time in total.

Post

mystran wrote: Fri Jul 08, 2022 11:56 pm If you write your own extensions.. then sure.. but to get anything done you have to support a couple of standard extensions .. which all take a pointer to the plugin as the first argument to every method.
yeah, I had my hopes up, but I think you are correct :(

Post

Still too bad something like LV2 Atoms where never considered, they are ultimately the most flexible way to provide (or ignore) functionality: http://lv2plug.in/ns/ext/atom
Heck, you could have two plugins communicate information on a Host that doesn't even support that Atom format. Not something I see possible with CLAP. ("maybe with an extension" << yeah but it's a core concept of the entire format. not something you can simply bolt on :P)

Post

camsr wrote: Fri Jul 08, 2022 10:37 pm I have a simple question that hopefully isn't off topic, but have not seen addressed by anyone who is currently compiling CLAP plugins. Are symbol exports destined to follow a prescribed rule on decorations? I think some of my plugins in the past had problems because of MinGW not following the MSVC symbol decorations.
There’s only one symbol you need to export, which is the clap entry data structure. I don’t know if anyone has built with mingw on windows yet but if the export macros in the clap headers need adjusting for that toolchain just hit us up on github and I’m sure we can figure it out.

Post

DRMR wrote: Sat Jul 09, 2022 7:34 am("maybe with an extension" << yeah but it's a core concept of the entire format
Erm, aren't LV2 atoms an extension bolted on to the core LV2 spec? I mean it's even in the link you posted, "ext" :P

Post

A_SN wrote: Fri Jul 08, 2022 8:34 pm
EvilDragon wrote: Fri Jul 08, 2022 8:10 pm I doubt requiring regular users to have the whole LLVM installed on their machines as a prerequisite just to be able to locally compile JIT based plugins in order to bypass notarization is a good idea, but ok.
That's absolutely not how it works, I wish you would all become more familiar with the topic before making conclusions or dismissing anything. The CLAP library used by the DAW would include whatever parts of LLVM (which is a set of libraries, not a program) it needs go compile from IR to native binary (it's not even that big due to not containing all the big language parsing stuff). So it's just a library that CLAP would use, nothing extraordinary about this. Again, that kind of approach is common enough, your GPU drivers have LLVM included for compiling shaders and kernels, there's no such thing as having "the whole LLVM installed" for this (I assume you said this because you're thinking of how your system's package manager let's you install "LLVM").

Oh and it's not "just to bypass notarisation", as people have said in this thread weeks ago you need such an approach now. This isn't the 1990s anymore, "one binary for one platform supported" isn't good enough in the 2020s. I already made points about futureproofing through this approach.
mystran wrote: Fri Jul 08, 2022 8:19 pm Ofcourse you can compile to portable bytecode and then JIT that to native. JVM does that, .NET does that, emscripten does that... the list goes on and on...

The question is not whether this is actually possible, but rather whether you can match the performance of C/C++ code that might be making decisions based on the platform already at the preprocessor stage.
And yet that's not what I'm talking about. I'm not talking about interpreting a portable bytecode JIT like WebAssembly does, I'm talking about compiling an intermediate representation to a native binary machine code blob, then running that. Again, that's the SPIR approach (and apparently what PNaCl also did). I wish you knew more about the topic.

So in that case, like I've already said before, you're moving part of the compilation from the dev's machine to the user's machine, with the advantage that you can target the user's specific architecture (kind of like Homebrew does as opposed to downloading binaries, but that's something else), so it's exactly the same result except you can better target the architecture.

As for the preprocessor thing, well, yeah your code won't know anything about the machine it's on at that stage, but there are alternatives (for instance like how you can detect CPU instruction set at run time), and it's not such a big deal. I can think of an example where that could be a slight problem (for instance in my endianness-sensitive code I have a macro for assuming LE or not assuming endianness), but I can't imagine this being a big deal.
I understand how it works, but i’m not sure this is what Apple wants.

Post

Any news on any wrappers?

Post Reply

Return to “DSP and Plugin Development”