OvertoneDSP plugins

@calimerox: My slightly colourful metaphor was intended as a lighthearted illustration of the complexities of the software design… (which I imagine anyone who has ever encountered XLib / X11 in this context, and lived to tell the tale, will likely find uncomfortably familiar)

I vaguely remember seeing something like that happen when the video timeline was introduced into ardour, the viewer window was spawned in another process (incorrectly) and it caused some file descriptor confusion and trampled all over my plug-ins in a similar way.

Yep. Ardour used fork and didn’t close file-descriptors. If the fork happened after opening the plugin GUI, the GUI’s file-descriptors were duplicated as well.
I still would like to understand why only LinuxDSP plugins were ever affected by this. Other Linux/X11 VSTs and LV2s (incl pianoteq) don’t have/haven’t had no such issues.

Trying to make reliable plug-in UIs on linux is fraught with problems [...]

No one said it would be easy :slight_smile:
Rather than pointing out how complicated it is, it’d be great if we could identify the issue and document it for future plugin devs.
The key here may be the “_XEventProc” X11/Atom. see https://github.com/Ardour/ardour/blob/master/gtk2_ardour/linux_vst_gui_support.cc#L242 and line 289… but that’s just a guess. There is too little information.

I guess overtoneDSP’s VSTs GUIs use a custom thread like JUCE, and since JUCE is freely available, that would be something to compare against.
Since other commercial vendors (e.g u-he, loomer,…) manage just fine there must be a subtle difference somewhere.

The only way I could open the Ardour project was to change the VST .so file names.

The session-open dialog has a “Safe-mode” checkbox (equivalent to starting Ardour with the --disable-plugins option), if enabled, the .so won’t be loaded to begin with (the plugin-state will be kept as-is). That should work as well to load the session and allow to investigate or remove plugins.

PS. gcc4/5 is only relevant if a plugin or plugin GUI is wrtten in C++ and depends on a C++ library which provided by the distro uses mismatching C++11 symbols (most common: glibmm)

@x42: Our / My X11 toolkit opens a connection to X when the plugin shared library (.so) is first loaded, and closes it when the plug-in shared library is removed e.g. when the last instance of a plug-in is deleted. The UI toolkit runs a single thread, connected to X via that connection, the UI toolkit manages all the windows associated with individual plug-in instances, and directs X events to callbacks in the correct plug-in instances etc. It also guards as much as possible against any thread related nastiness that might occur from outside the plug-in. So there is effectively one connection to X per plug-in species, (as opposed to one connection to X per plug-in instance).

I still would like to understand why only LinuxDSP plugins were ever affected by this. Other Linux/X11 VSTs and LV2s (incl pianoteq) don't have/haven't had no such issues.
Just luck. Sometimes it didn't crash my plug-ins either - it purely depends on which file descriptor got squashed, and that depends on things like what order the plug-ins are opened etc.
No one said it would be easy :)
No, but there is no point in making something unreliable by design. XWindow has existed for a long time, and been added to over time. X itself is not really the issue but some mad decisions about the implementation of XLib lead to a problematic situations which should not even exist. For example:

The default XError handler behaviour is to quit the application. You can’t change this reliably, especially in a plug-in / host environment or where there are multiple connections to X. This wouldn’t be a disaster, but, if you do anything which references a non-existent window, it causes an XError (which quits the program). A plug-in with its UI embedded in the host, cannot know, if the user closes the plug-in window, whether the host will destroy the plug-in window (as a child of its own) or whether it already has destroyed the window etc (because, testing if the window still exists will cause an error if it’s already been destroyed, which, quits the program). So you no longer have any control over the lifetime of the plug-in UI (from within the plug-in) without risking an XError / Crash.
Since the window ref is only an index (not a pointer for example), and (because targetting a non-existent window can cause an error, rather than e.g. a segfault etc) its obvious that the X server knows if a window ref is no longer valid, so logically the default - safe - behaviour, would just be to do nothing for an invalid window. Instead, XLib quits the program (which is not ideal if you’ve just closed a plug-in UI in the middle of a session)

I guess overtoneDSP's VSTs GUIs use a custom thread like JUCE, and since JUCE is freely available, that would be something to compare against. Since other commercial vendors (e.g u-he, loomer,...) manage just fine there must be a subtle difference somewhere.
As already mentioned. Yes I think its very similar to JUCE - I don't know what the other plug-ins use, or, whether they do actually have similar issues, but that just haven't come to light yet. All the evidence I have, from far too much time spent with XLib / X11 (see also the link I referenced) is that the best anyone can do is make the chances of a crash less likely, but it's impossible to prevent it completely. I notice ardour seems to work around one of the issues by unmapping / hiding the plug-in UI instead of closing it, which is not the correct behaviour either - it also fails to call 'editor close' on the plug-in. A crash is less likely, but it will likely leak memory like a sieve.
PS. gcc4/5 is only relevant if a plugin or plugin GUI is wrtten in C++ and depends on a C++ library which provided by the distro uses mismatching C++11 symbols (most common: glibmm)
Actually its really if you thow std::strings across the plug-in / host boundary (or more specifically the gcc - libstdc++ version boundary - the layout / size of the types changed in the later version, meaning for example that you might not unwind the right amount of data on or off the stack - once again, it might not get you straight away, or even at all, or, (most likely) it might cause someone elses plug-in to go beserk - and be blamed for the problem.. :) )

It is not just std::string. std::list is affected also. In addition, C++ libraries other than libstdc++ do not provide a dual ABI meaning that mismatching versions of plugin/host compile histories will result in missing symbols.You may also notice that actually almost no users blame plugins for the problem - they blame the host applications first. It is only host developers who end up digging in, figuring out the issue, and in the case of Ardour, offering both gcc4 and gcc5 nightly builds to address the problem.

Your complaints about X11/Xlib are really off-base. First of all, plugins have NO mandate to create their own connections to the X server, just as AudioUnit plugins have no mandate to create their own top level NSWindows, let alone talk to Quartz window/display (whose architecture is actually very similar to X11, except not network-enabled in its release form). Plugins have NEVER had control over the lifetime of any of their resources, on any platform with any plugin API. Your issues with window lifetime management stem from the VST specification, not from X11. If you look at the AU specification, it is extremely clear where the responsibility for managing NSViews and NSWindows lies, and thus there isn’t this silly confusion about using pointers to windows as proxies for “my GUI was destroyed”. This in turn is a reflection of the fact that the VST 2.4 API has never specified what the “parent window pointer” is on systems running X11. It is merely a convention among LinuxVST-supporting hosts that it is a handle on an XWindow. Not really suprising when neither VST 2.4 or even VST 3 actually supports Cocoa on OS X, despite Carbon’s deprecation for much more than a decade. It only in VST4 that there is an acknowledgement that the parent window pointer is an NSView, thus making it impossible to properly support VST’s on OS X unless you use an extension as Reaper has done or use some even cruder hack.

In addition, there is the problem that the VST specification also contains no information (pre VST-3, where it is still very sparse) regarding the use of threads inside the plugin. This extends to the GUI, and is particularly problematic because of the tendency for Windows programmers to use multiple threads (1 per window, typically, to deal with the message event loop) compared with the single-threaded semantics of X11 (Cocoa on OS X is multithread-safe, but recommends single-threading GUI code). Since the host has no idea whether the plugin will attempt GUI operations in its own thread(s), we are forced to create an additional connection to the X server. If we knew that all VST plugins were either constrained by the API or were simply well-behaved, we would not need to do this, and the plugin would simply piggy-back on the hosts own X server connection.

Summary: the VST specification, until VST4, is woefully inadequate at specifying what the parent window is and what its relationship is to the plugin’s own GUI resources. It also fails to describe the threading model to be used by either the DSP or GUI aspects of the plugin. It therefore is not suprising that on X11 as well as Cocoa/OSX, there are problems managing this.

We don’t “workaround” issues by unmapping/hiding; VST semantics do not specify that a user request to close the window should result in a call to the “editor close” callback (they don’t really specify anything at all). Since the plugin does not own the top level window, the WM_CLOSE message is never delivered to it under any circumstances. Steinberg do not make clear the intended relationship between “user closed window” and “plugin is being deleted”, and using effEditorClose for every “user closed window” implies, according to the VSTGUI source code, that ALL GUI resources should be deleted and recreated every time, which seems frankly insane. And the VST 2.4 SDK’s only comment on “close” is " Close editor (detach from parent window)." which is very strange way to define the semantics (and also has some potentially undefined implications on OS X where referencing counting may be used to handle NSViews).

In addition, our code does call EffEditorClose, during fst_destroy_editor() or vstfx_destroy_editor(), which is called when destroying a plugin, not when “user closing” the window, for the reasons outlined above.

While we’re ranting, the actual failure is the plugin-standard allowing this kind of idiocy.
While not without issues, Audio Units is by far the most sensible: A GUI factory method mandating separate views per instance and single-threaded UI.
LV2 also encourages this and it’s a pity it can’t be enforced there.

Anyway, what is the motivation for using a custom threads and a single X11 connection per shared object (not one per plugin instance)?
Frankly, in my experience this is a major design mistake which in turn requires all kind of workarounds that no plugin GUI should ever be concerned with.

[..] So you no longer have any control over the lifetime of the plug-in UI (from within the plug-in)

Why would a plugin GUI want control over itself to begin with? The user controls the UI (via the host).

From far too much time spent with XLib / X11 (see also the link I referenced) is that the best anyone can do is make the chances of a crash less likely,

You apparently know about the specific shortcomings of xlib and then go down that exact road, anyway. Why are you complaining, again?
But since you mention it and again and gain. That whole article can be summed up with “Doctor, it hurts when I do this.”
Besides, the headline alone makes a few FUD alarms go off: Don’t listen to people who hate and encourage other do so.
Yes X11 sucks, so does Cocoa and HWND. Each in their own way. C’est la vie. Try to avoid the pitfalls and learn to love x11.

Error handling is the host’s job. A plugin has no business to set up X error handlers. If a code-path in a plugin GUI can trigger a X-error, that’s a design mistake in the plugin.
Also a plugin (GUI and DSP) should never ever fork or launch threads by its own. A plugin simply has insufficient context for doing so reliably (in particular scheduler priorities).

I’d extrapolate “If you don’t know how long it will take, don’t do it.” (from http://www.rossbencina.com/code/real-time-audio-programming-101-time-waits-for-nothing ) to plugin UIs: “Unless you know the code-path is reliable, don’t do it.”

Actually its really if you thow std::strings across the plug-in / host boundary [..] the layout / size of the types changed in the later version

Throwing std::strings? Literally throwing them as C++ as exceptions and doing that across a stack that spans host and plugin frames?
Host -> VST plugin-process -> VST audioMasterCallback -> dispatch -> plugin -> throw exception (caught in plugin-process) ?

Then again it should work fine, regardless. libstdc++ symbols are versioned and the library has a dual ABI:
https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_dual_abi.html

@paul: almost everything about your reply is wrong. Let me help you understand this better:

It is not just std::string. std::list is affected also..
Because std::list relies on std::string
And it doesn't matter whether the host passes them across the boundary or not: if the plugin was compiled with the new gcc 5.1 ABI and the host with the older one (or vice versa), the wrong thing will happen.
That's what I actually said. If you pass the affected object across a boundary between two different versions of the ABI it will go wrong. The most common instance of this is typically what happens when a plug-in is compiled with one version of gcc and the host with another.
Your complaints about X11/Xlib are really off-base. First of all, plugins have NO mandate to create their own connections to the X server,
They have to create their own connection, because they can't get access to the runloop / X connection used by the host. This has everything to do with the linux graphics stack / toolkit host architecture - its a well known problem which has been "debated" forever - its a fundamental shortcoming of the linux graphics stack which makes it uniquely difficult to make embedded plug-in UIs.
Your issues with window lifetime management stem from the VST specification, not from X11...
BS. But even if it wasn't, the default behaviour makes X11 crash in a way which would be competely avoidable in a more robust design. It is outside of the plug-in / host developers control.
This extends to the GUI, and is particularly problematic because of the tendency for Windows programmers to use multiple threads (1 per window, typically, to deal with the message event loop...
Er- I don't know where you got that idea from, the Windows graphics API is single threaded, precisely to avoid the kind of problems you get with multiple threaded solutions. what you describe is not common practice at all. Summary: tl;dr - I know more about this than you do, and I'm not prepared to get into meaningless debates about, or be lectured to about, who's fault various issues are, especially based on your own misconceptions of how plug-ins work. There are problems that make the linux graphics stack badly suited to plug-in UIs, this is accepted knowledge (see the link I referenced earlier in the thread). It has nothing to do with VST vs any other format.

@x42: I simply don’t know where to begin trying to explain this to you - its not a design mistake to use a single thread per plug-in type for the UI engine, it makes much more sense (think of the plug-in like a miniature application, with many windows, if it was a stand alone application you wouldn’t be advocating a seperate UI thread for each window the user opened - you’d have one runloop, which handled them all - just like e.g. GTK / Windows etc. That’s what we do with a plugin. It just happens to run in the host application’s process space. Otherwise the design pattern is broadly similar to any other - stand alone - application)
Please don’t blame the plug-in format. This has nothing to do with VST vs anything else. The same problems can (and do) happen with solutions based on seperate UI / DSP code - a bad Cocoa UI on Mac can bring down the application, as can a bad X11 (or gtkmm for example) UI in LV2. It has nothing to do with them living in a separate shared library from the DSP.

They have to create their own connection, because they can't get access to the runloop / X connection used by the host.
Correct, you're not supposed to. Isn't that what "effIdle" and "effEditIdle" are for?
Correct, you're not supposed to.
Which is exactly why you need to create a separate connection to X11
Isn't that what "effIdle" and "effEditIdle" are for?
No, that's for updating the UI in the background (e.g. meters etc) - its not for handling e.g. user input or X-events. It also doesn't get called at all by some host applications (remember, we don't just make plug-ins for ardour). - and it also gets called with arbitary frequency, making it almost useless for anything that needs consistent update rate. The standard practice (especially with e.g. openGL UIs ) is to manage the UI outside of VST (or VSTGUI) as much as possible, and just use the VST API to pass parameters values etc.
*idle -- [..] its not for handling e.g. user input or X-events.

You don’t need a thread for that. Events are delivered as callback.

Animations are the main reason why some devs prefer threads, wrongly IMHO, those should only be active during idle.

think of the plug-in like a miniature application, with many window

I don’t because that’s not what a plugin is, can’t be, nor what it should be.
The plugin is always at the liberty of the host and has insufficient context to behave like an application. Trying to make it behave like an application will fail one way or another in the vast majority of cases.

remember, we don't just make plug-ins for ardour

That’s even more reason to do less special casing.

Here’s some excerpt from Apple’s “Optimizing Audio Unit User Experience in Logic Studio”


For even better user interface integration, custom Audio Unit Views should
refrain from using overlay windows and from opening sheets or auxiliary
windows other than for file browsing. All user interface elements should be
presented inside the root Audio Unit View by laying out its content
dynamically and resizing as necessary. The host window listens to size
change notifications and will adapt automatically."

Otherwise the design pattern is broadly similar to any other - stand alone - application

I think we’ll have to agree to disagree on that.

[..] a bad Cocoa UI on Mac can bring down the application, as can a bad X11 [..] UI in LV2

indeed but in this case it’s a badly written plugin and not a fundamental problem with Cocoa or X11 as you made it sound initially.

This is why I want to understand how and why it fails and notify the party involved or fix the issue.

Our goal should be to provide the best user-experience and make it work.
End-user’s don’t care who or what is to responsible. Yes, shit happens, but apologizing or blaming libs does not get us any further, does it?

Anyway, JUCE managed to somehow work their way around it, and by experience so far I cannot second you earlier assertion that there are undiscovered sleeping dragons. Apart from the aforementioned commercial products, DISTHO Plugin Framework also uses JUCE and there are a lot Linux users using DPF/VSTs on daily basis.

Unless you know already what the issue is, I’d be great if we could investigate how OvertoneDSP’s framework/toolkit differs which in turn results in the reported incompatibility. It may well turn out to be an issue elsewhere.

@x42: As far as I know, JUCE uses the same approach of e.g. one X11 connection / thread per plugin type (e.g. when you load the .so it opens the connection, and uses it to handle all windows created by the plug-in e.g - for the avoidance of confusion which seems prevalent here - any windows created by the code contained in that plugin.so)

Here's some excerpt from Apple's "Optimizing Audio Unit User Experience in Logic Studio"...
That's talking about an individual plug-in UI instance spawing multiple windows, that's not what I'm talking about. Here's the simplified version for the hard of thinking:

In a standalone application, you normally create one connection to X. Each window which the application creates is handled via that connection, there isn’t a separate X11 connection / thread per window. GTK (and actually therefore, ardour) use exactly the same method.

What I’m saying is, consider the design pattern to be similar to a standalone applicaton, in which the plug-in.so makes a connection to X, and then each window which that shared library code creates - not multiple windowed UIs - but each window for each instance of the plug-in UI is handled via that connection. A GTK plug-in embedded in ardour, would, by necessity operate in the same way. FYI on Mac / Windows we don’t use anything like the same code we do on linux. We just have a version of our graphics engine which presents the same API to our higher level plugin code, which means the bulk of what we deal with day to day in the plug-in can be portable, even if the underlying UI is very OS specific by necessity.

You don't need a thread for that. Events are delivered as callback.
Not in X11 they aren't. With X11 (forget VSTGUI or any other abstraction) you create a connection to X, then you poll the event queue in a runloop, and in response to the events you get, you can then implement some callback mechanism, and build it up into a conventional event driven toolkit - that's the main purpose of our X11 UI engine)
Unless you know already what the issue is, I'd be great if we could investigate how OvertoneDSP's framework/toolkit differs which in turn results in the reported incompatibility. It may well turn out to be an issue elsewhere.

I don’t know what the issue is - or even if there really is one - (its possible its not directly X11 related - we’ve gone down this route because of an assumption based on the limited backtrace, and its turned into a massive argument because people fundamentally aren’t understanding some very simple things I’m trying to explain, and instead have taken to ranting about plug-in APIs, and semantics of ABI compatibilities etc).

One of the reasons I don’t normally discuss how our code works, is because, for most users its irrelevant, its far more relevant that it does work, and, because it inevitably invites people with a naive or limited understanding of the issues to throw around misconceived or flawed notions about what they think the issues to be based on supposition, or just plain wrong information.

...then you poll the event queue in a runloop

…except you should not do that in your plugin’s own thread. The host calls the plugin’s " _XEventProc" the plugin processes pending x events and returns.
like on OSX, there should only be a single runloop (which is provided by the main application).

PS. I just checked JUCE, it uses a global x11 connection only for messaging and as far as I read so far only for applications (not plugins) and otherwise relies on _XEventProc.
You don’t have to take it from me, either: http://www.kvraudio.com/forum/viewtopic.php?f=33&t=387924 (renoise).
…and if you check the linux_vst_gui_support.cc (see link above) you’ll find that Ardour calls it for every x-event (and expects the plugin to return).

So, I got an answer from the Renoise team and after some eMails, this here can be used (with one of the next Renoise updates) to set the _XEventProc for 64 bit:
The key point here is "with one of the next Renoise updates"... It may work now if you use _XEvent proc, but during development of our UI toolkit, it didn't work reliably with all host applications. _XEvent proc was not suitable at the time. There is and I don't know how to put this more clearly, nothing wrong with the way our UI toolkit works and it certainly doesn't justify wild and unfounded accusations such as "a major design mistake" - especially without having ever seen the code. This code has been developed over a long period of time, with many host applications, and proved to be reliable (remember we don't know if, assuming there really is an issue here, that it relates to the UI code specifically) I work on this stuff all the time, I've seen (and resolved) just about every combination of host / plugin problem that you can think of (and many I'm sure you can't) during my time. I also reiterate,
we don't just make plug-ins for Ardour.
and as far as I read so far only for applications (not plugins)
In that case I think you've misunderstood the JUCE code, because I could clearly see an X11 connection get opened when loading a JUCE plugin last time I looked at this.
we don't just make plug-ins for Ardour.

Which VST/X11 hosts out there don’t support _XEvent and require to use a custom thread/runloop?

It seems I started a fire storm. I have a little more information: I bought the FC70 license. It ran fine on Ubuntu 14.04 alongside Pianoteq. On Ubuntu 16.04 the same issues as described earlier remained. However, updating to the latest version of Pianoteq fixed the incompatibility under 16.04.

I notice that most references to Linux plugin versions have been removed for the OvertoneDSP Web site and I wonder if this is the beginning of the end for them? If so it will be a great pity.

Crap!
The mastering bundle was on my list of ‘things to buy once i get paid at the end of this month’!

I love my Calf plugins too, but I figured it was time to get some other tools in the box since I’m spending more and more time doing this.

Hopefully it’s a temporary measure while the plugins are updated?

Not a dangerous fire at least.

LinuxDSP does awesome engineering in general, and hence I’m curious why it follows in libX11’s footsteps (X11 threading is flaky at best, adding more threads won’t make it better – that’s what I referred to as design-mistake, which is arguably in X11 already). Ardour’s current implementation goes back to FST and also uses a custom thread . The plan is to eventually clean this mess up and use the gdk provided one like Ardour already does for LV2 x11_in_gtk via libsuil.

I’d also still like to know which VST/X11 hosts don’t support _XEvent and require plugins to use a custom thread/runloop, though.

Not even an announcement as to why on the site. Sad.