VST vs Rewire

DSP, Plugin and Host development discussion.
RELATED
PRODUCTS

Post

You may want to wait and see if VST 3 is a less "crappy" design. Though you may be waiting forever it seems...

And by the looks of this thread you intend to make it windows only?

Post

here is an idea:

1) create your own plugin spec with your ideas
2) create wrappers for other specs to work in your spec
3) create "downgrading" wrappers to make a common lowest denominator feature sub-set of your spec work in other specs.

this would become a universal wrapper, and potentially if your spec were good enough, plugin authors would start using it instead making it the primary spec out there.

Post

@aciddose: Yeah, that would be a good idea but also one that takes the most time to execute. I have no experience with (writing for) any type of music plugin standard so just doing a little restructering and making the jump to managed code is more than enough for me at this moment. Usually once I start coding I will encounter all sorts of 'sub-optimal' situation in the plugin/host interface. Building your own spec from experience is better, right?

@asomers: VST 3? You make it sound as if this version will never ship :). Like I said: I just need a starting point with VST (any version). When a version 3 arrives I will adapt and adopt.
Although .NET was born on the windows platform other platforms are supported by the Mono framework. So if I (and your plugin) don't use any features that are not supported in Mono, you should be able to write a managed plugin for linux and mac as well (that's the theory anyway).

@bradr:
Yep shouldn't be too bad, though you're going to need special handling for each message type to "marshal" strings/pointers correctly.
That is sort of how I look at the problem now: as marshalling messages back and forth. I will look into .NET remoting to get some inspiration and to learn what the support is for marshalling these structures (should be pretty good). My idea now is to have a chain (or a pipeline) with message processing components. I will make a proxy for each VST version that calls into my framework/interfaces. Unrecognized messages are just passed through to proxy objects for newer versions. So, if a new version is introduced I just write a new proxy that calls into the new interfaces. A chain or pipeline could look somthing like this:

Code: Select all

C++ Handler -> To .NET transformer -> VST 2.0   -> VST 2.1 ....   VST 2.4
                                         |             |              |
                                      IVstPlugIn20  IVstPlugin21   IVstPlugin24
After the C++ message is transformed to managed .NET the version-proxies pick out the message that belong to their version and call the appropriate interface. Something like this...

What do you think of the QueryInterface solution to dynamically implement interfaces? So if you would like to check for support of some feature you call the QueryInterface (either on the plug-in or the host) and it will return you a reference to it when its implemented or null when its not. For the plug-in, the decission to return a reference or not can be driven by any criteria or the call is just forwarded to a contained (sub)plug-in. I think this would probably be the best choice, because I really like to be able to signal in interfaces what features are supported, both for host and the plug-in.
Wouldn't .NETs assembly versioning and side by side assemblies resolve all this for you. So you'd have an interop dll for VST 2.4 and when a new VST spec comes out, just build a new interop dll with the interfaces updated?
Yes it would (sort of). But I regard a published interface as cast in stone (same as in COM). So the only way to extend a published interface is to derive from it and what will you call that derived interface? I suggest to name it the same as the base interface but with a version specific postfix to it. So IVstPlugin would be version 1.0 and IVstPlugin24 would be for VST version 2.4.

Thanx everybody!

PS: I will go on holiday in a few days for 2 weeks, but keep the comments coming. I will pick this up again once I'm back.
Grtx, Marc Jacobi.
VST.NET | MIDI.NET

Post

"Yeah, that would be a good idea but also one that takes the most time to execute. I have no experience with (writing for) any type of music plugin standard so just doing a little restructuring and making the jump to managed code is more than enough for me at this moment."

well, this means probably that you wont be able to do anything practical. like i said in my first post, you're probably applying way too much effort. you're creating an issue out of a non-issue. the best way to do what you want to do is to write your own code (plugins, hosts, so on) with your own interfaces, then wrap those to whatever plugin format you're supporting.

the main things i dislike about vst are:

1) messages and audio are not handled in a uniform manner - the spec started out as something only to process small chunks of audio and 'evolved' in a completely unregulated manner. there is very little engineering applied to this spec - it has no solid foundation and it is surprising it has not yet crumbled.

2) there is significant bloat in the spec. many features have been added which could easily have been implemented using the messaging protocols. vendor specific.. should be named 'extensions' combined with canDo(), so on. the core of the spec should be kept minimal, the L.c.d. interfaces.

3) the encoded message 'opcode' switch calling method is acceptable, however it should be available in addition to a method based upon function pointers. function pointers should be handled through accessor functions like "canDo()" and data should be passed as structs like in xlib. the current calling method and data handling is not type safe at all, and becomes ugly very quickly.

4) objects can be accessed directly rather than through abstract interfaces. big mistake.

so, my ideal spec would be a hacked up and reformed version of vst, sharing some of the same fundamental design ideas, yet engineered from the beginning to have an optimum L.c.d. core.

the basic spec would require only the implementation of the interfacing functions:

initialize() ('main' in vst), canDo()/access().

Post

After the C++ message is transformed to managed .NET the version-proxies pick out the message that belong to their version and call the appropriate interface. Something like this...
I suspect .NET is difficult to use in real-time because of the just-in-time-compiling (causes unpredictable code execution timing) and the heavy use of memory allocation (also causes varying time delays). .NET would be great for User Interface building though.
Perhaps a hybrid solution would be cool... A nice .NET interface combined with a small C++ audio engine.

What do you think of the QueryInterface solution to dynamically implement interfaces? So if you would like to check for support of some feature you call the QueryInterface (either on the plug-in or the host) and it will return you a reference to it when its implemented or null when its not.
That's how the new SEM plugins work. Makes it easy to add extensions without affecting existing code. The interfaces are easy to use from both C++ (where they look like a pure virtual class) and from C (where they resemble a list of function pointers).

Jeff

Post

obiwanjacobi wrote:I will look into .NET remoting to get some inspiration and to learn what the support is for marshalling these structures (should be pretty good).
I don't think .NET remoting is not what you want - its about packaging parameters and marshalling to another thread or process and involves serialization and stuff (I think). What you really need is just "interop" and C++/CLI will handle this easily for you. I guess my point was that I don't think you can just pass the messages directly across that interop - because sometimes parameters are integers, sometimes they're in-buffers, sometimes they're out-buffers etc...

For unmanaged to managed I'd probably suggest having a pure virtual class declared in unmanaged code, but implemented in managed code with methods for each variation of dispatcher message parameter types.
What do you think of the QueryInterface solution to dynamically implement interfaces? So if you would like to check for support of some feature you call the QueryInterface (either on the plug-in or the host) and it will return you a reference to it when its implemented or null when its not. For the plug-in, the decission to return a reference or not can be driven by any criteria or the call is just forwarded to a contained (sub)plug-in. I think this would probably be the best choice, because I really like to be able to signal in interfaces what features are supported, both for host and the plug-in.
How about this. Given that most devs won't need dynamic capabilities have the presence of the interface signal the capability of the plugin (ie: like what you originally suggested and opposite of what I suggested). This will be naturaal and easy for typical plugin development. Then for the other case have a different interface - IQueryCapability - which provides the opportunity to dynamically disable a capability even if the plugin supports the associated interface.
Wouldn't .NETs assembly versioning and side by side assemblies resolve all this for you. So you'd have an interop dll for VST 2.4 and when a new VST spec comes out, just build a new interop dll with the interfaces updated?
Yes it would (sort of). But I regard a published interface as cast in stone (same as in COM). So the only way to extend a published interface is to derive from it and what will you call that derived interface? I suggest to name it the same as the base interface but with a version specific postfix to it. So IVstPlugin would be version 1.0 and IVstPlugin24 would be for VST version 2.4.
Fair enough... or why not just use a different namespace for each VST version?

Brad

Post

Hi Jeff,
Jeff McClintock wrote:I suspect .NET is difficult to use in real-time because of the just-in-time-compiling (causes unpredictable code execution timing)
Yes, unless you "ngen" it which precompiles for the target machine - and also generally improves performance.
and the heavy use of memory allocation (also causes varying time delays).
Its more the garbage collector isn't. Memory allocation is supposed to be extremely fast under .NET. But when gc runs all threads are suspended. That's got to be bad.
.NET would be great for User Interface building though.
Do you think? I generally find .NET apps to be more erm... clunky (like a VB6 app) than a properly developed native app. WPF is supposed to allow for building really funky UI's and would be nice for VST gui's but... what I've seen so far seems very slow and very memory hungry.
Brad

Post

bradr wrote:
and the heavy use of memory allocation (also causes varying time delays).
Its more the garbage collector isn't. Memory allocation is supposed to be extremely fast under .NET. But when gc runs all threads are suspended. That's got to be bad.
From my investigation with another GC language, the GC in that only pauses the threads created by it's runtime. Foriegn threads like interupt driven services are invisible to it. So real time code can still run even if the GC has paused everything else. You just have to make sure the foreign thread doesnt do anything that can mess up the GC if its in the middle of a collection. So the foreign thread cant be the sole reference to block of memory, and it mustn't do anything that causes allocation or freeing of memory. Which isnt that hard to work with tbh.

I dont think it would work with a compacting collector though.
.NET would be great for User Interface building though.
Do you think? I generally find .NET apps to be more erm... clunky (like a VB6 app) than a properly developed native app. WPF is supposed to allow for building really funky UI's and would be nice for VST gui's but... what I've seen so far seems very slow and very memory hungry.
Brad
Yeah my experience of .NET is that it tends, even fairly simple apps, to be slow resource hogs.

Post

Marc,

Was thinking about this some more and wondering how you're going to handle the plugin entry point? If you're using C++/CLI to build the wrapper/bridge won't VSTPluginMain need to be in that dll? If so, does that imply you need to rebuild/or ship a different version of the bridge code for every plugin? Sorry, no answers here, but curious whether you've thought about this and how you're going to handle it.

Brad

Post

Brad,

No, there will be only one bridge/farmework dll containing the entry point for the snap-in. The managed code of the actual plugin will be in a different assembly. The entry point code (main) will have to know what assembly to load. I haven't worked out yet how to get multiple managed snapins to register with the host as unique snapins. I don't know how that registration process goes exactly, yet...
Grtx, Marc Jacobi.
VST.NET | MIDI.NET

Post

obiwanjacobi wrote:No, there will be only one bridge/farmework dll containing the entry point for the snap-in. The managed code of the actual plugin will be in a different assembly. The entry point code (main) will have to know what assembly to load. I haven't worked out yet how to get multiple managed snapins to register with the host as unique snapins. I don't know how that registration process goes exactly, yet...
It's unfortunate that C#/VB.NET can't export a dll function as this would solve this issue. As it stands I can't see how you can avoid having a separate bridge DLL for each .NET module. VST loading relies on having one plugin per DLL and each DLL has one entry point for that plugin.

Half the problem is having your bridge code know which .NET assembly to load, the other half is how to fool the host into realising that one DLL is actually multiple plugins. Other problems include the fact that some hosts use the DLL name as the plugin name (ignoring the plugin name string) and some hosts will refuse to load a plugin of the same dll name from two different locations - so you can't just put each plugin/bridge in a different directory.

The other thing you might like to investigate are shell plugins - these are plugins that serve as a container for other plugins but I don't think they are widely supported by hosts (I could be wrong). Check out kPlugCategShell and effShellGetNextPlugin in the VST SDK.

Of course if you're only trying to build one plugin in .NET this is all moot. If however you're trying to build a reusable bridging mechanism I'm sure you're going to need separate bridge dll instances for each plugin that uses it.

Brad

Post

Though about this some more...

What if you were to implement a small "bootstrap" dll in C++/CLI whose only point is to provide the entry point and loading of the target assembly. So suppose you have a .NET plugin "myplug.net.dll", it would work like this:

* Copy the bootstrap dll to the same folder as the .net assembly and rename it "myplug.dll"
* The host locates "myplug.dll", sees the entry point VSTPluginMain (recognizing it as a plugin) and calls it
* myplug.dll then dynamically loads "myplug.net.dll" which it determines by manipulating its own path (eg: insert ".net" or any similar scheme)
* Once loaded it uses reflection to create an instance of the plugin instance class - again a simple strategy involving the dll name would probably suffice (eg: a case insensitive search for a class named "MyPlug"), or perhaps some sort of meta data on the plugin class, or even just the first class it sees that derives from the bridge class.
* The .net class would derive from a base class defined in the bridge assembly which provides the AEffect structure.
* Private interfaces could be used between the bootstrap and the bridge to convert from .NET class back to AEffect* which is returned to the host.

Not sure I've explained that clearly, but you get the idea...

This way, you're not duplicating the bridging code for every plugin, you solve the problem of the bridge code needing to determine which plugin to load, the host sees a different dll for each plugin and it's a simple procedure for the plugin developer (copy/rename one dll)

Brad

Post

Thanks Brad. I think you're probably right about having to duplicate (and rename) the framework dll for every snapin.

I like your idea of a small bootstrap dll. But that would introduce yet another dll. bootstrap.dll, vst.net.dll (framework) and mymanagedsnapin.dll.

Another option might be to merge the framework/bridge dll with the managed assembly after they're compiled. I know ILmerge (MS research) will merge managed assemblies, just don't know if it supports C++/CLI? However, we'd still be duplicating the framework code. Which will force you to redeploy the entire merged snapin dll, even when only the framework code is updated (bug fixes).

"Nothing is ever easy"
Grtx, Marc Jacobi.
VST.NET | MIDI.NET

Post Reply

Return to “DSP and Plugin Development”