DISTRHO / Cardinal

Virtual modular synthesizer plugin
https://cardinal.kx.studio/
GNU General Public License v3.0
2.07k stars 141 forks source link

Project related news (was: Gathering interested people) #1

Closed falkTX closed 2 years ago

falkTX commented 2 years ago

Leave a comment if you want to help. This does not do anything yet besides building VCV sources, I need to do some experiments for it first to see what is the best approach. Seems that we only need to create a variant of https://github.com/VCVRack/Rack/blob/v2/adapters/standalone.cpp for plugins, and then add in some hardcoded module for IO (audio, midi and transport sync)

falkTX commented 2 years ago

Update: the makefile builds now. You get a black screen if you try to run it, as there is no real code on the plugin side yet.

unfa commented 2 years ago

Being able to use VCV Rack as an LV2 plug-in would put it on my map. I could actually start using it in my work. It'd be something very unique, especially if it'd allow putting external audio in.

unfa commented 2 years ago

Also: "CVC" = "Control Voltage Craze"? ;)

trummerschlunk commented 2 years ago

highly interested ;) thanks for your work!

falkTX commented 2 years ago

CVCRack reads as "CV Crack", for those addicts on CV. Hopefully everyone finds it funny and not problematic :sweat_smile:

One initial question is knowing which plugin IO variants are useful, because not all hosts are alike and allow placing FX on sequence tracks or synths on the mixer. So I am thinking:

  1. base synth version - no audio ins, MIDI input, 2 audio outs
  2. base FX version - 2 audio ins, 2 audio outs, midi input and output
  3. CV port version (only possible in LV2 and VST3, not in VST2) maybe with like 8 cv ins and outs, opinions welcome
  4. ???

At least for FL Studio and Renoise we need a basic synth and fx versions. The CV version wont work on most hosts, but useful for placing it on Carla and other modular things. I dont think JUCE hosting supports CV, so no support for Bespoke :/

unfa commented 2 years ago

CV Crack Rack takes the cake for me :D

I think the variants listed make perfect sense. If there's someeon who'll need an insane thig like 32x32 audio ports then it's probably not a huge deal todo it. I doubt anyone will want it though.

x42 commented 2 years ago

The VCV Rack code to run as plugin in sync with a host is not public.

Even in v2, there is only code available for the GUI version that renders async, not rt-safe (using locks) and uses modules for I/O:

https://github.com/VCVRack/Rack/blob/042a9ce026d253700ea14e340182900162ab4653/src/engine/Engine.cpp#L404 https://github.com/VCVRack/Rack/blob/042a9ce026d253700ea14e340182900162ab4653/src/engine/Engine.cpp#L578

A plugin version processing must run in sync (with the host). This is a major task and will require a complete engine rewrite... Which is what Andrew has been busy with over the last years.

So you will have to re-implement the engine in a rt-safe way (without locks and globals), notably Engine_stepFrame: process all cables, then all modules. and every N samples check if connections or modules have changed, and swap the lists in a rt-safe way. GUI synchronization will be another task.

x42 commented 2 years ago

Tech issues aside, have you considered that upstream might not like this, and stop releasing any GPL code in the future?

falkTX commented 2 years ago

Yeah, this has always been the case. I wonder if the closed plugin has custom code for this or just reuses the engine as-is. we will never know perhaps.

But anyway, getting this to build correctly is a good first challenge already :joy: VCV is very peculiar in wanting specific versions of libraries. One step at a time.

falkTX commented 2 years ago

Tech issues aside, have you considered that upstream might not like this, and stop releasing any GPL code in the future?

That is a good question... But also, it sucks that if for that reason we cannot try to make a plugin version ourselves.. IIUC they only plan to release a VST2 version at first.

x42 commented 2 years ago

PS. check out VeeSeeVSTRack. That has a vst2-process-callback: https://github.com/bsp2/VeeSeeVSTRack/blob/81e054be2dcc0c5d93d2f38288257cc6564ad878/src/engine.cpp#L498

as well as VST2 and VSTi wrappers. It is not entirely rt-safe, but a lot better than upstream, based on Rack 0.6 though.

Be-ing commented 2 years ago

One initial question is knowing which plugin IO variants are useful

Mixxx would need just a stereo input and stereo output. This would be good motivation to implement LV2 GUI support in Mixxx.

This is a major task and will require a complete engine rewrite... Which is what Andrew has been busy with over the last years.

My understanding was that Andrew was going to publish the code of that complete engine rewrite. I see the v2 branch in the VCV Rack repository which has recent commits but no 2.0 version has been released as far as I can tell. It may be wise to wait for Andrew to release 2.0 before doing much work on this. I have not been following VCV Rack closely and have no idea how far that branch is from a release.

I recall an old GitHub Issue on the VCV Rack repo several years ago discussing this which @falkTX participated in as well. Unfortunately VCV Rack no longer has a public bug tracker and archive.org did not archive that issue. My understanding from that conversation was that @AndrewBelt planned to do a major rewrite to support running VCV Rack as a plugin with the core code published with a GPL license but the VST part would be proprietary. He said he was not interested enough to work on LV2 support himself and would not accept a pull request for that but we could implement LV2 support in a fork.

AndrewBelt commented 2 years ago

We haven't gotten many requests for an LV2 version of VCV Rack Studio Edition, but I can add it to our feature request list!

Be-ing commented 2 years ago

Thanks for chiming in @AndrewBelt. Could you clarify if that LV2 support would be published with the GPL source code? If not, I don't know if it would satisfy anyone who has shown interest here (speaking for myself, I wouldn't use it). As long as the GPL source code doesn't require a major rewrite, I think there's sufficient interest here to maintain a fork for a GPL LV2 plugin version. AFAIK there is only one proprietary DAW that supports LV2 (Reaper) so I don't think the availability of a free GPL LV2 plugin would have much if any of an impact on sales of the proprietary VST (and AU? not sure if you're planning to support that plugin format) version.

falkTX commented 2 years ago

My understanding was that Andrew was going to publish the code of that complete engine rewrite. I see the v2 branch in the VCV Rack repository which has recent commits but no 2.0 version has been released as far as I can tell

The v2 code is already public, but no release is official yet. This was the motivation behind the initial work here, checking if the new code can work for a plugin or not, going with the assumption that yes since there is one announced.

We haven't gotten many requests for an LV2 version of VCV Rack Studio Edition, but I can add it to our feature request list!

As great as that sounds, my main issue is that such a plugin is not going to be open-source. Did I understood this wrong?

For one, VCV still only officially supports 1 single architecture on Linux. For ARM builds we need to build it ourselves, and there is no access to the online store since it also only has the more typical intel/amd 64bit binaries. If the official VCV plugin is not opensource, we cannot use it on linux ARM devices.

And not just ARM, RISC-V is slowly rising in popularity. I would love to have this working on HaikuOS too at some point. This is just not possible without it being open-source in the first place..

Perhaps a special license deal could be possible to those who buy a commercial license, so we get access to code for personal use but under very limited conditions or something..?

AndrewBelt commented 2 years ago

We've gotten many feature requests for ARM on Mac/Windows/Linux, so it is definitely on our feature request list. If you have other questions/requests, our most reliable channel is https://vcvrack.com/support.

Be-ing commented 2 years ago

The v2 code is already public, but no release is official yet. This was the motivation behind the initial work here, checking if the new code can work for a plugin or not, going with the assumption that yes since there is one announced.

@AndrewBelt can you clarify what is the state of the v2 branch and what your plans are for it? I see now that you published a promotional teaser video a few weeks ago but I didn't see any indication how close the v2 branch is to completion. Is there still a lot of work you plan to do before is usable for a plugin? Or is the current state of the v2 branch close to release ready?

falkTX commented 2 years ago

First test: can we get the VCV window embed into the host? Answer is no, not easily anyway. VCV relies on GLFW for all its window and event handling, which does not yet support such a feature. That said, we can replace it by Overriding the Window.cpp file with a custom one, driven by DPF and its pugl backend. The DPF stuff needs to be converted to GLFW (mouse presses, keyboard, etc) so that VCV understands them (that is, without a whole event system rewrite on the part of VCV) The alternative would be to allow to keep VCV as external window while the embed view is a dummy/minified one.

Which one is better? IMO the embed view is better. With VST2 the hosts could not resize the plugin UI (not without custom extensions), but this has been added officially in VST3 and LV2 supports this too. So we don't have to deal with fixed size plugin UIs anymore.

I am testing high-dpi on macOS to make sure that is possible to work well too. You can see below how it looks:

image

The background is missing, but that is my fault quickly hacking around the code just to get this to build so I could test the embed approach.

So, still ask anyway... embed or external?

falkTX commented 2 years ago

Checking VeeSeeVSTRack it uses https://github.com/bsp2/lglw, which allows to embed its window into the host and follows the same API as glfw. Seems to be custom code by the same author. There is no support for macOS though. Not sure how good/bad the state of that project is, but seems kinda abandoned at the moment. Sticking with DPF/pugl might be best if going the embed way, it is more nicely integrated anyway.

falkTX commented 2 years ago

For the sake of transparency, I am quoting contents of an email I just received from Andrew:

Hello, The name you've chosen for your fork is very close to our trademark "VCV" (USPTO 87714461) which may lead to confusion. VCV Rack's own 250k+ users are extremely brutal/demanding for tech support, and the last thing I need is for a similar-looking product with a similar name creating more support due to confused users. I already get hundreds of complaints per year about other forks of VCV Rack (having much more different names than "CVC") and have to send them an automated template response explaining that we don't make that product and to contact who they obtained their version from. This makes many people angry toward VCV for not offering them the free support they think they deserve!

VCV releases open-source software so people can review and modify how the software works. We don't release software because we like providing support for free. I hope you can understand this and change the name of your fork to something that will cause fewer problems. Perhaps "falk Rack" would be better, as it suggests who users will assume is responsible for support?

And my reply:

Hi Andrew, that makes sense, sure.

Though you could have said the same thing on the github ticket where conversation is on-going, I dislike to keep such matters private.

It is only a research project at the moment, if anything comes of it I will rename it (likely even before that).

falkTX commented 2 years ago

A few more details, seem that passing events from DPF to VCV works well. Have a hacky way to pass-through mouse clicks, motion/hover and scroll. With a little resize handler at the bottom right the UI can become resizable even in VST2 format. Seeing in action as below: (Renoise and VST2 version)

image

The SVGs are not loading somehow, dont know why yet.

The way VCV manages the "active context" is a bit weird for plugin usage, but should still be doable. oui-blendish kinda works the same way and my testing for the one-knob series tells me it is not an issue as long as host GUI is single-threaded (which so far is always the case)

Since VeeSeeVSTRack had a working audio plugin engine, I assume this part is doable too. We can likely copy its plugin modules to serve as a base.

The hard part is going to be dealing with VCV plugins, VeeSeeVSTRack went a bit overboard with its approach even though long-term it is/was the more stable one. Audio plugins should be self-contained, in theory, but in practice VCV already fails due to its heavy use of global state. So perhaps not worth bothering too too much on this side of things...?

Oh and yes this needs a new name. I am often bad at those, so suggestions welcome.

x42 commented 2 years ago

Oh and yes this needs a new name. I am often bad at those, so suggestions welcome.

How about "Cardinal"?

falkTX commented 2 years ago

Oh and yes this needs a new name. I am often bad at those, so suggestions welcome.

How about "Cardinal"?

I am quite neutral about this one, what is the reason for it? Starts with a "C"...?

x42 commented 2 years ago

Thinking about "Rack", I associated Monty Python's Spanish Inquisition: "Cardinal, [bring forth] the Rack", and yes it starts with a C, like all your other projects.

falkTX commented 2 years ago

I dont see why not, thanks. It actually sounds cool but still generic and simple enough. We just got to see if there are no other plugins or big projects already with the same name

And not all projects start with C, you know DISTRHO itself is already an exception right? 😉

falkTX commented 2 years ago

The embed view works on Linux/X11, and tested win32 builds via wine as well.

Screenshot_20211008_154900

If we can figure out why svgs dont load correctly, I think then a cleanup for a proper UI can begin. The DSP I am assuming can just work, just a matter of setting up the engine properly. I was more doubtful of the UI because of GLFW, still am a bit because when using stock Window.cpp that uses GLFW, the svgs then load correctly: Screenshot_20211008_160325

My guess would be at some OpenGL setup/state not being quite as needed when using DPF/pugl

falkTX commented 2 years ago

Success! Embed view and SVG loading, UI interaction seems to work fine from what I can tell. I was looking all over the place, but turns out the culprit was this little piece of code on VCV Svg class:

    // It's more important to not lag the frame than to draw the framebuffer
    if (dirty && APP->window->getFrameDurationRemaining() > 0.0) {
        render(scale, offsetF, args.clipBox);
    }

My custom Window class didnt have a lot of things that GLFW provides, such as frame duration information.. for now putting some dummy values makes the check pass and SVGs are finally drawn on screen :tada:

Screenshot_20211009_030440

falkTX commented 2 years ago

Multiple instance seems to work, at least for UI stuff. Some barebones keyboard input too, still need to handle special keys so we can do stuff like backspace for deleting characters.

image

This is showing how great it is to build good infrastructure. Most of the work is just glueing stuff together, tying the DPF things into what VCV expects. It goes rather smoothly, so fingers crossed...

The next big item I guess is getting the engine to do something, likely I will need help on this. But for that the build needs to work cleanly, so others can start to run it too and not just me. Since we have CI tests already in place from other DPF plugins it should be clear when the build and plugin runtime is working well enough. This might take some time now though...

Be-ing commented 2 years ago

Is or will there be a means for an LV2 host to tell the plugin to load a particular patch separate from other instances? My hope is that I can save patches and create effect chain presets in Mixxx which load specific patches, then manipulate them with a single knob on my controller: image

Are modules' knobs exposed as LV2 parameters? IIUC LV2 plugins can't dynamically add and remove parameters, so I suppose it would need a hack similar to audio I/O with a fixed number of LV2 parameters which could bind to modules' knobs within the plugin.

falkTX commented 2 years ago

Is or will there be a means for an LV2 host to tell the plugin to load a particular patch separate from other instances?

Yes of course, each instance of Cardinal is supposed to be self-contained in its own engine, patch and gui. And state should be preserved in the host as long as the host saves it and restores it the usual way. For LV2 and Mixxx just make sure to support the LV2 state extension,

Are modules' knobs exposed as LV2 parameters?

This is up to discussion.

IIUC LV2 plugins can't dynamically add and remove parameters, so I suppose it would need a hack similar to audio I/O with a fixed number of LV2 parameters which could bind to modules' knobs within the plugin.

That is correct. Though VST3 supports this dynamic parameter stuff, it is not something I am interested on adding to DPF. The complexity around it is too much for very little gain, and almost no plugins need this in practice.

Hosts dont typically support CV as a form of automation, so we will need some special parameter mapping. What I have done in Carla (and zynaddsubfx for example does something similar) is to expose a static 100 parameters to the host. In Carla these will be auto-assigned to the first plugins loaded in the rack, in zynaddsubfx you can map as you wish through a dedicated dialog. For VCV as plugin I think the static parameters are the best choice. We can have a dedicated module to convert from plugin parameters to VCV internal CV, probably with some options to control its behaviour (sudden changes vs smooth interpolation, threshold for smoothness etc)

Nothing about this is done yet, so for now it is just discussion. Opinions always welcome, specially before any real implementation begins.

x42 commented 2 years ago

so I suppose it would need a hack similar to audio I/O with a fixed number of LV2 parameters which could bind to modules' knobs within the plugin.

VeeSeeVSTRack solved this by just exposing 10000 control ports to the host. When adding modules inside Rack they are mapped to their controls. VST allows to have dynamic labels per parameter (LV2 doesn't). It is somewhat ugly, since you have a lot of automatable controls that by default do nothing and you only get the first 10k controls.

It would be nicer to have some fixed "macro" controls. Say, 24. They could show up in a dedicated "Control" module as CV source to connect wires to. The same module could also provide host-clock, MIDI etc.

Alternatively only generate VST3 and AudioUnit Plugins. Those do allow for dynamic parameters and could expose everything,

Be-ing commented 2 years ago

It would be nicer to have some fixed "macro" controls. Say, 24. They could show up in a dedicated "Control" module as CV source to connect wires to. The same module could also provide host-clock, MIDI etc.

This seems like a good idea and likely more practical than exposing every knob of every module.

dromer commented 2 years ago

@AndrewBelt if you would use DPF you could have vst2/3 without steinberg (and juce?) commercial license restrictions. ISC would give you the freedom to develop your vcv products your way.

falkTX commented 2 years ago

VST2 without steinberg and closed-source is not possible. see https://github.com/DISTRHO/DPF/blob/develop/LICENSING.md VST3 is though, because it is a full API reimplementation, no SDK parts are used.

dromer commented 2 years ago

yes noted, but @AndrewBelt seems to have a vst2 license already, so potentially any distribution under that format would be covered by his license? vst2 could be default off. only for the commercial vcv builds applied

falkTX commented 2 years ago

Right yes good point. The VST2 is on by default assuming vestige header, as typically so far everything built with DPF is GPL compatible. See the link above where I have written already about this

You can alternatively build DPF-based VST2 plugins using the official Steinberg VST2 SDK, simply set the VESTIGE_HEADER compiler macro to 0 during build. You will need to provide your own VST2 SDK files then, as DPF does not ship with them.

dromer commented 2 years ago

But even if steinberg where to claim that vestige is bound by vst2 licensing a valid vst2 license could allow commercial use by vcv.

AndrewBelt commented 2 years ago

Have no worries. We are thousands of hours and tens of thousands of $ into developing and testing the plugin version of VCV Rack on 20 DAWs on 3 OS's while maintaining stability and compatibility with all plugins and patches. We are on-target for a November release of VCV Rack 2 Community and Studio Edition, and pre-release versions will be available for plugin developers in a few days.

falkTX commented 2 years ago

So that means a plugin version is known to work well, good stuff :)

Some news on the build setup, finally all the CI stuff passes. From linux to macos to windows (via mingw) See https://github.com/DISTRHO/Cardinal/actions/runs/1324743342

macOS was the trickiest one to deal with, but we have x64+arm64 universal builds. the linux stuff includes armhf, aarch64, x86 and x86_64.

These automated builds are not useful yet, because I do not have in place a way to detect the plugin bundle folder (we need something that works for all formats, discussion follows on https://github.com/DISTRHO/DPF/issues/332 for this)

For now at least you should be able to build and run it. The VCV "system" directory is just going to be the build-time source code directory. Still need to do a couple more things and start the tests regarding the engine and multi-threading, but we are not too far off from something where I can distribute some tasks to those that want to help.

Be-ing commented 2 years ago

The way you are structuring this repository using upstream Rack as a Git submodule is interesting. I was thinking you'd have to modify the Rack code directly, but I suppose this approach will be easier to maintain.

I am interested to get this working in Mixxx but there is a lot of work to do in Mixxx first, so I probably won't be helping much with the plugin code before that.

falkTX commented 2 years ago

The way you are structuring this repository using upstream Rack as a Git submodule is interesting. I was thinking you'd have to modify the Rack code directly, but I suppose this approach will be easier to maintain.

So far I have not have the need to edit header files, so it still works. For C++ files we can just build/ship our custom implementation, as it is the case with the Window.cpp already for the integration with DPF UI stuff.

Still not optimal IMO, some code has to be duplicated in those files (I mean, the same code is present on VCV and we only need to modify parts of it).

I wonder about the file menus we need to hide, in theory should be possible to access them through the Window methods, going deeper into the widgets until it reaches the menu items and then call ->hide() on them. For example the file->quit is one that doesnt work if the UI is embed, needs to be hidden away then

there is a lot of work to do in Mixxx first, so I probably won't be helping much with the plugin code before that.

Just make sure LV2 plugins work as good as possible, then you get these and many others for free :)

falkTX commented 2 years ago

I got distracted with a little new test project https://github.com/DISTRHO/Ildaeil/ as someone is adding (REAPER's) JSFX plugin support in Carla and I wanted it to be usable for other hosts that are not Carla. It served as motivation for a super stripped-down mini-host based on Carla.

Anyway, continuing with the updates...

I am skipping the engine + plugin process sync a bit, and went directly to the biggest challenge - plugins. The engine provides its own sets of challenges, but it is more about understanding and studying the VCV code rather than overcoming a challenge.

So I began trying to add plugin support. The build setup was getting quite messy with the plugins inside VCV as plugin, so I just reorganized the whole thing. Now it is more clearly separated between "deps", "plugins" (ie, vcv based plugins included as submodules) and "src" for the main VCV as plugin stuff.

Added AudibleInstruments, Befaco and Fundamental so far. The AudibleInstruments is more complex than the other 2, due it needing many more source files. Checkout https://github.com/DISTRHO/Cardinal/commit/c1233ab66e4fc6fb6e4ea3bc6e7c7b5dd4d5b748 for get an idea of how much work (or not) it is to add new vcv plugins to the build. TL;DR we basically add a repo as submodule and adjust the Makefile and plugins.cpp files based on the original code.

And before you ask, it is all built statically into the Cardinal plugin binary. With these 3 plugin sets the optimized binary is at 6.8Mb.

And to keep up with the tradition, here is yet another screenshot. Cardinal inside Carla in macOS, loading a few vcv plugins.

image
Be-ing commented 2 years ago

And before you ask, it is all built statically into the Cardinal plugin binary.

Is this a technical requirement? Is it feasible to load other Rack plugins (to be clear, inside the Cardinal plugin) dynamically?

falkTX commented 2 years ago

And before you ask, it is all built statically into the Cardinal plugin binary.

Is this a technical requirement? Is it feasible to load other Rack plugins (to be clear, inside the Cardinal plugin) dynamically?

in theory, yes.. but complicates things too quickly for a plugin. it would be unpredictable loading random plugins and expecting everything to work 100%. it is much safer to use a well-known list of working plugins. plus I only have interest on the opensource ones, and those we can just compile in. the commercial plugins only provide linux 64bit binaries, that is not very nice (this will change in the future, but it will take a while)

the alternative would be to run VCV in a separate process and communicate over shared memory and semaphores, alike JACK and typical plugin bridges. this does not scale, but perhaps it does not have to. a couple VCV instances already provide a lot. but that would be a different project, not this, it is not what I am trying to do.

Be-ing commented 2 years ago

Okay, seems reasonable to just statically link all the Rack plugins you can, especially considering how small the binary is.

zezic commented 2 years ago

Got the 5efc37e15caa06bb3b8feaa90b6af9d7ea192fc9 working on Linux, but it has a large empty black area for some reason before actual background starts: image I can pan the area with BG into view with middle mouse button though.

falkTX commented 2 years ago

First time I see this. Do others DPF based plugins work? DPF itself provides a few examples/tests.

What DE are you using? this is with high-dpi right? What scaling?

zezic commented 2 years ago

I have not checked other DPF plugins yet, but yes, you guessed it correctly, this is HiDPI system at 150% scaling, KDE.

zezic commented 2 years ago

Just built and checked the latest DPF plugins and they are all rendered correctly. @falkTX as you can see, the top (blendish) menubar of Rack is placed where it should be and only the main workspace has that strange offset of black color. I'm able to zoom in and move that working area to make it fill the whole window.

falkTX commented 2 years ago

Try with latest, I didnt yet have setup a way to show the current patch when opening the GUI. Still dont quite understand how we can do this properly, if a patch is loaded before the UI is visible, the UI elements are simply not created. So we need to save and reload the current patch when showing up the UI...

Anyway, more news. Digging into VCV engine/audio stuff, I am not sure if we really need the approach started by VeeSeeVSTRack. The v2 VCV code (not sure if it was the same in v1 or it is v2 only) has calls for setting a module master that will drive the audio. This seems to be done automatically from what I can see, with a background thread in case there are no audio devices selected.

In any case, I implemented the first bits for working audio. Using a VCV driver instead of a plugin module (still need to try to do one of those myself). With a little trick to associate the engine context with a plugin pointer, all seems to work as far as I can tell. I verified it to work across different/multiple contexts too (ie, 2 instances in parallel)

https://user-images.githubusercontent.com/1334853/137665540-a5309c3e-f7b1-4492-9e29-5a6db1c1f54b.mp4

The project is a bit more usable now too, I added a custom Core.json for skipping the incompatible modules we dont need, and a custom template.vcv that starts up with the audio driver enabled.

There is no MIDI yet, or state save/load, will give those a try later.