DISTRHO / DPF

DISTRHO Plugin Framework
ISC License
652 stars 96 forks source link

CLAP support development blog #383

Open falkTX opened 2 years ago

falkTX commented 2 years ago

I am opening this ticket as a sorta blog progress report style for anyone interested on following CLAP support in DPF.

I will be working on this for the next 2 months, starting with the basics for running a few plugins for this month. We can set dragonfly reverb as a target, as that has parameters, meters, UI and of course audio. Then next month going deeper in CLAP integration, for having time position, latency, and all other goodies.

falkTX commented 2 years ago

Let's start things today. I have put in place "stub" implementations which do nothing but allow things to build, in preparation for new plugin formats.

I was thinking of doing things in a "clap" branch, but as I am going through the files that will need tweaking I see old code that needs maintenance and little tweaks. I do not want those general tweaks and fixes to be stuck behind a specific branch, so I will just push the clap things directly into "develop".

Also, my initial thought for this development was to do regular live streams accompanying it. But seems better not, I keep waiting for the right moment to do a stream (cant do it when I only have <1h dev time, or when I expect to have regular breaks because I need to do something on the side, or other life things..), this delays the actual time spent working on the feature which is not good. Other people likely have better discipline, a fixed working routine and other habits that allow to work on such things in a more consistent way. And I don't.. Plus not always in the mood to appear in a stream... You get the point, I will not do live streams after all.

Let's focus on the technical stuff.

We call today "day 0". I put in place the stubs and needed files to build them, but there is no clap specific code in the codebase at all yet. So we can track how long it takes to put a complete implementation in place. I will try to make report/summaries on the status on a regular basis.

falkTX commented 2 years ago

Results of first day:

Works 🚀

image

Core API is quite simple, so fast start is not unexpected. The dev docs are missing on some critical details and have quite a few typos and grammar mistakes, will open tickets about it soon.

Already started some initial code for UI and parameters, but not pushed yet. Will report on that next time.

falkTX commented 2 years ago

Just randomly trying things 👏 👏 👏

image

CLAP seems to follow many of same approaches as VST3 does in regards to driving the UI. The plugin needs to ask for a UI resize before it happens (though unlike VST3, on CLAP the plugin remains in control for the 2nd stage of the resize action). It also (seems to me) does not provide a native way to hook into the host idle loop, having to ask the host to spawn a timer in order to drive UI events.

I am really missing a way to push events from UI to DSP here, instead plugins need to do all of that message passing on their own. We can just have it similar to VST2, with an array of booleans for the parameters that changed on the DSP side and should be updated on the UI.

Unlike other formats though we cant have the UI ask the host to change a value, instead all happens during audio processing (or if plugin is not active, during a special "flush" call meant to replace it for that case) So the UI -> DSP parameter change events need to be put in a queue of sorts to later be handled during RT/audio-process. Feels a bit weird, but at least it means there is 1 single point of entry for changing parameter values, plus threading being well defined.

falkTX commented 2 years ago

Results of 2nd day:

can start to see how the code needs to be structured for clap support. quite a few things that clap needs were already done for vst3, so I have been moving a few vst3-specific functions into common code.

still only works for single-bus plugins (those with only a fixed set of ports, which is the majority of dpf plugins). but that should be enough to get most plugins to work.

so implementation is progressing at a good pace. I will (attempt to) provide clap-enabled FX and Synth variants of Cardinal for its 22.09 release, release date TBD.

image

falkTX commented 2 years ago

I am giving up counting by days, there is not always something interesting to show every time. Would be cool to know how long the implementation takes, but also puts pressure to finalize it quickly which can lead to pressure-inducing mistakes. So, will just report here whenever there is anything interesting to show.

This time, it is transport information. Verified to work with bitwig and Cardinal.

image

Sending notes from UI to DSP also works now, plus some MIDI input related things are in place but it MIDI input doesnt work yet.

falkTX commented 2 years ago

We are close to the first target, dragonfly is only missing 1 feature to make it fully functional - state extension. Hosts can still save parameters without it, but dragonfly uses this to indicate which "preset" is selected on the GUI.

Spent some time on Linux to ensure the UI works there, can confirm it is the case.

image

Even resize works now (tested both host-initiated and plugin-initiated). REAPER ignores the "adjust size to fit" thing though, so it can go below the minimum size.

image

falkTX commented 2 years ago

Not a lot of development news recently, as I have been stabilizing the base implementation and doing tests, fixing the odd issues here and there as they appear.

As CLAP is so new, hosts can still do things in an odd way as they pretty much only been tested with a very small pool of plugins. So far it has been quite okay to adjust once a problem is found. Seems mainly Bitwig, where:

  1. I only report CLAP_NOTE_DIALECT_MIDI as supported, but Bitwig sends us fancy notes anyway (which should only be done if plugin reports it as supported)
  2. X11 UIs fail to init if a window is not created by the time Bitwig calls set_parent, so we just create the window during it instead of waiting for the show call

Now that things are getting stable, I already made a few releases with DPF+CLAP in place.

https://kx.studio/News/?action=view&url=introducing-masterme

https://kx.studio/News/?action=view&url=cardinal-2209-released

https://kx.studio/News/?action=view&url=ildaeil-v11-released

For the last one, yeah you can use Ildaeil CLAP as a way to load LV2 😅 Loading x42-plugins (which are LV2 only) inside Ildaeil-FX CLAP in Bitwig:

image

falkTX commented 2 years ago

Starting new month, developments will begin again.

For testing more specific and detailed features I find that doing the host side helps quite a lot. Because you get to see and experience things not just from the plugin side, but from the host side as well. On DPF-based plugins I typically use Carla to test features and do automated runtime testing, which is not possible until Carla supports CLAP natively. Well, that is about to change!

image

Scanning already works, so the next bits are hosting. Since CLAP has many similar ideas to VST2&3, likely I just need to copy the implementation and tweak a few things. That is what Bitwig did too anyway :P

For the advanced/next features, it is just the more deep plugin things:

perhaps parameter modulation? not sure how to best fit into DPF API yet.

falkTX commented 2 years ago

More indirect progress, Carla hosting with parameters and MIDI, and basic time and GUI support

image

This finally allows to try out all the small details for proper CLAP support in DPF. Thanks to it found a little bug where memory corruption could happen when plugins had 0 parameters (like Ildaeil).

There was another issue with high-dpi screens on macOS + Reaper, spotted by u-he folks. Already fixed that in git, but this means existing releases of DPF-based plugins are in need of an update. Will wait 1 more week for more possible fixes, then start doing release fixes.

falkTX commented 1 year ago

No pics or screenshots, but got latency stuff now working for CLAP too, as per 847000e4f224a0024a65e9c998ae481d91fd847a

This one was tricky.. CLAP is very restrictive on the threads that can query latency information, so we must do a little dance to ensure the information ends up in the host. In other formats we typically just report that the latency has changed from any thread, sometimes even giving the new value directly, but this is not doable in CLAP. For one, CLAP dictates the plugin must deactivated and activated again for a new latency value to take place. This means we need to not just inform of the latency change, but ask the host to reactivate the plugin too.

If the plugin is active and processing audio, then receives a parameter update (which can only happen during audio processing if plugin is active) which changes its internal latency, plugins must:

  1. request host to reactivate the plugin instance
  2. wait until host calls deactivate
  3. report to host that latency has changed (can only be done on this step, not before)
  4. wait until host activates back the plugin

Main issue here is that reporting of latency changes must happen on main thread and when plugin is deactivated. So even if already on main thread (for example loading plugin state), we still need to do the host reactivation dance if plugin is currently active. Which typically they would be, nothing in CLAP states plugins must be deactivated in order to load state or change parameters.

I only have 1 example plugin that makes use of latency, no other DPF based plugin does that I am aware of. Verified to work in Carla, for which I also needed to do special dances in order to ensure this latency update deal :sweat_smile:

Next up, will likely be multi-IO support. So we get sidechain and related things. An important step to get the big/main Cardinal running in CLAP...

falkTX commented 1 year ago

Some little news. Yesterday was release day, we got new Cardinal and Ildaeil that bring all CLAP fixes so far. Additionally, due to Ildaeil reusing Carla for hosting, we can now use it to load CLAP plugins in non-CLAP supported hosts! And vice-versa, of course.

Anklang (which only supports CLAP) loading LV2 plugins:

image

Ardour (which does not support CLAP) loading CLAP plugins:

image

falkTX commented 1 year ago

Good news, multi-IO is in. No fancy screenshots for this, it is just technicalities this time.

Did the testing with https://github.com/DISTRHO/ndc-Plugs which includes a DPF port of https://www.niallmoody.com/ndcplugs/ampimposer.htm This plugin is nothing fancy at all, but allows to test and verify the feature. Also with this I noticed that CLAP multi-IO hosting was broken in Carla, so that is corrected on latest git now.

On this same topic, now that we have multi-IO, I went ahead and enabled the Cardinal main variant for CLAP. Still does not have CV, but has 4x stereo audio pairs, with only the first being marked as "main".

falkTX commented 1 year ago

Oh forgot to mention, with CLAP hosting being available in Carla now, I have began to enable the runtime tests for plugin CI builds, as all other DPF-supported formats were handled already.

Can be seen in for example https://github.com/DISTRHO/ndc-Plugs/actions/runs/3301517161/jobs/5447073018 Need to spread out the CI workflow file to all projects now... but good timing as github has deprecated a bunch of stuff so I need to update these anyway.

EDIT: the error on the CI log is from the Carla CLAP multi-IO being broken on the version I have in the kxstudio repos, need to push an update-fix to that

falkTX commented 1 year ago

With a few more fixes in place, I went through the different kind of plugins in DPF-Plugins collection and verified the behaviour of each type. And with that done, we get new release https://github.com/DISTRHO/DPF-Plugins/releases/tag/v1.6 15 new CLAP plugins at once! :clap: :clap: :clap:

Fixing ProM also involved fixing some long-standing bugs in DPF when using OpenGL3 mode, among other details. (a few things were broken on WIndows and I didnt notice, as I rarely use that)

Since with VST3 and CLAP in DPF having some tiny details not yet implemented, I revised DPF's README to no longer say that all plugin implementations are complete. They are mostly complete, for what most devs care about anyway. Instead the README now links to https://github.com/DISTRHO/DPF/blob/main/FEATURES.md which I have updated to have CLAP as part of the feature table.

I was hoping to do some documentation related work this month, but the more slow times now need my attention for planning/preparations for a move. Going back to Berlin, land of u-he and bitwig among others :sunglasses: Plus there is also the Ubuntu Summit 2022 next week, another trip in between others :airplane:

In any case, will keep this thread updated for CLAP + DPF related things as usual, even if going slower in the next few weeks.

falkTX commented 1 year ago

Hey all, for those potentially interested in DPF I have created a plugin template at https://github.com/DISTRHO/imgui-template-plugin Uses cmake for build system and ImGui for the GUI, so hopefully some will be familiar to at least one of these.

It is not documentation, but can be helpful for easy experimentation. I only tested Linux builds for now, so let me know if something is broken.

image

falkTX commented 1 year ago

Oh for those curious about imgui, their project page at https://github.com/ocornut/imgui has quite some info.

falkTX commented 1 year ago

Some news, though not 100% related to CLAP.

Because documentation is super boring, and devs tend to not read it anyway, I am going in a slightly different approach for the time being - making project setup and builds as easy as possible.

With that in mind, here are 2 fancy github actions you can use on DPF-based plugins to automatically test, build and get release binaries.

https://github.com/DISTRHO/dpf-cmake-action https://github.com/DISTRHO/dpf-makefile-action

One for cmake, the other for makefiles.

I added it to the previously mentioned template repository. Which ends up being https://github.com/DISTRHO/imgui-template-plugin/blob/main/.github/workflows/build.yml Not too complicated, right? What you get with this is:

See https://github.com/DISTRHO/imgui-template-plugin/actions/runs/3501012211 for an example. Just a little file setup and you get all those builds!

Also helps me maintaining the different repositories, because copying over the yml file to every single repo everytime I wanted to do a small change was getting annoying. Now just need to update the actions related repo, and trigger a rebuild.

Related to template repositories, I began experimenting with the Elements library as a widget type for DPF. The example project at https://github.com/DISTRHO/elements-template-plugin can serve as base for such. Due to it using cairo, freetype and fontconfig (which needs to be built statically, as this is a plugin after all) I did not yet setup automatic builds. So for now it is more of a testing grounds for another kind of widget.

image

Finally sorta related to CLAP, I have added a "IR Convolution Reverb" plugin to the WIP https://github.com/DISTRHO/OneKnob-Series collection. Related to CLAP because this is the first non-example DPF-based plugin that uses files. Verified to work on LV2, known to NOT work under CLAP because I did not implement this part yet. I will use this as a real test case for handling files integrated with a CLAP host.

(not sure yet how to handle these for non LV2/CLAP formats that do not have such a concept, will deal with that later)

image

michaelquigley commented 1 year ago

image

I managed to get the DPF+ImGui example plugin running on Windows with CMake and MSVC++ without too much trouble.

I targeted both CLAP and VST3, and both plugins seem fine in REAPER.

I've been developing some really interesting drum programming software for the last 15 years or so... I'm looking to develop a bridge plugin that let's me easily integrate my stuff into traditional DAW environments. Looking at using DPF to get into it.

I'm already using Dear ImGui extensively, so this seems like a pretty solid entrance point.

image