Our Community Plugin Format

DSP, Plugin and Host development discussion.
Locked New Topic

Poll 1 - Let's give it a name (Acronym)

HOT Plugins
0
No votes
WAR Plugins
0
No votes
TOP Plugins
0
No votes
OUR Plugins
0
No votes
PRO Plugins +1 Point
1
3%
EVE Plugins
3
10%
ION Plugins
3
10%
IVY Plugins
2
7%
MAN Plugins +1 Point
0
No votes
WTF Plugins +2 Points
1
3%
KVR Plugins (permission issue?)
2
7%
DIY Plugins
1
3%
COP Plugins
1
3%
API Plugins (Amazing Plugin Interface)
0
No votes
TPIA Plugins (This Plugin is Amazing)
0
No votes
OPI Plugins (Open Plugin Interface)
8
27%
OPS Plugins (Open Plugin Standard)
8
27%
 
Total votes: 30

RELATED
PRODUCTS

Post

After thinking about it some more, since calls into a DLL are indirect already, may not be much of an advantage as I first thought. But a dispatcher does introduce another layer of indirection, and a branch. Ideally this dispatcher would be stateless, and the only purpose it would serve is to call some function, without side effects.

Post

+1 for a dispatcher. Simple and extensible is ideal IMHO.

@Music Engineer, I agree automation and also, presumably, parameter changes should be passed in process call. This way you can have a sample accurate array, time stamped events or similar. The only thing is to have a solution for passing the data when audio isn't running, (not a big deal, but I recall when Steinberg hosts ignored the VST3 SDK solution to this and dropped events in such cases)

Post

Also, I guess, controllers should be handled in the same way. Like VST3, I think, it should be platform agnostic. However channel information would be useful to avoid the need for thousands of extra parameters to handle every cc/channel combination. Plus it should handle controller polyphony etc

Post

I don't particularly like the dispatching approach used in VST2 since the parameters of all opcodes have to be fit into the generic void pointer / int signature using reinterpret_casts on both ends. As a consequence, all type information and semantics is lost and only found in doc strings, so no compiler-enforced correctness. Also, if you need to pass one more parameter than whats provided by the generic signature, you need to introduce an auxilliary struct just for that.

So, I would favor if the interface provides function pointers per "opcode". I don't mind if the number of these grows with time and don't see technical issues with it.
mystran wrote: Mon Jul 06, 2020 7:40 pmBecause having a bunch of functions is more copy-pasta than using a dispatcher.
Do you mean you would have to copy the function signature into your code? Sure, but on the other hand, there would be no need casting the generic parameters and the code would be more readable and type checked by the compiler.
Music Engineer wrote: Mon Jul 06, 2020 6:32 pm because we don't want a proliferation of various different callback functions for the open-ended number of all the different possible kinds of requests.
Why is that a problem? If these are mandatory, than it's good that they are explicitely listed there and the compiler would probably warn you if you forgot to define any of them. If we want optional callbacks, we can introduce a simple extension mechanism via some get_extension() callback, which returns another struct of callbacks, like it's done in the "clap" proposal I mentioned in the other thread.

Post

karrikuh wrote: Tue Jul 07, 2020 6:55 am I don't particularly like the dispatching approach used in VST2 since the parameters of all opcodes have to be fit into the generic void pointer / int signature using reinterpret_casts on both ends. As a consequence, all type information and semantics is lost and only found in doc strings, so no compiler-enforced correctness. Also, if you need to pass one more parameter than whats provided by the generic signature, you need to introduce an auxilliary struct just for that.
Couldn't have said it in a better way :tu:
www.solostuff.net
Advice is heavy. So don’t send it like a mountain.

Post

camsr wrote: Sat Jul 04, 2020 5:36 pm Too vague, okay. What if a plugin requested to allocate 24GB for all of it's sample data? Would you want to implement all the code in your plugin to make sure this doesnt crash/slowdown your DAW? Or let the host figure it out for the plugin?
Memory allocation is a single line of code. Where is the boilerplate? You can't crash DAW by allocation itself. Even if you could, how could it be avoided in the code?
camsr wrote: Sat Jul 04, 2020 5:36 pm The plugins should be able to get some kind of data without having to have the same boilerplate code in every one of them.
Like what?
camsr wrote: Sat Jul 04, 2020 5:36 pm Another example is running the CPUID instruction, to check for supported instructions. Why should every plugin be concerned about runing this instruction, when the host can run it once, and relay the relevant information to the plugin? The results of CPUID do not change much, afaik.
Are you aware that CPUID is platform specific and not every plugin uses it? Maybe let's add filters and convolution to the plugin format too?

Post

karrikuh wrote: Tue Jul 07, 2020 6:55 am I don't particularly like the dispatching approach used in VST2 since the parameters of all opcodes have to be fit into the generic void pointer / int signature using reinterpret_casts on both ends. As a consequence, all type information and semantics is lost and only found in doc strings, so no compiler-enforced correctness. Also, if you need to pass one more parameter than whats provided by the generic signature, you need to introduce an auxilliary struct just for that.
I feel like the real problem with the VST2 dispatcher is how it packs the parameters somewhat inconsistently into a generic set of parameters. A much cleaner approach (at the cost of tiny bit of indirection) is to define the callback function such that it only gets (1) a pointer to the plugin and (2) a generic void* to an opcode specific struct. It's true that you don't get compiler error-checks for the void* itself, but when you cast it into the actual type, you do get all the goodies when you access the struct.
mystran wrote: Mon Jul 06, 2020 7:40 pmBecause having a bunch of functions is more copy-pasta than using a dispatcher.
Do you mean you would have to copy the function signature into your code? Sure, but on the other hand, there would be no need casting the generic parameters and the code would be more readable and type checked by the compiler.
If one assumes that the raw ABI is not what the plugin wants to use internally, then usually there is a bunch of code that exists for the sole purpose of translating the ABI to the internal interface, whether that's just a C++ version of the raw interface, or something completely different. Assuming you always pass the parameters in a struct, then in terms of type checking, the only difference then is that rather than relying on the function prototypes matching for both the plugin and the host, you rely on the dispatcher casting to the correct type for the message and this is all together in one place so getting it right is not terribly difficult; the rest of your code still type-checks as usual. The only way you can get truly strong typechecks across the interface would be to rely on C++ name mangling and it should hopefully be obvious to everyone why this is not such a great idea.

Dispatchers also give you some debugging benefits. For example, tracing messages becomes trivial: you just need to log the calls to the dispatcher and now you get proper debug output even for messages (at least the opcodes) you have never heard of. If you want to do this with a function pointer style system, you have no option but to implement everything and the kitchen sink, including all extensions anyone ever came up with.

The one benefit I see with the type of scheme where you query for an interface and get a struct of function pointers is that it makes decentralized extensions easier, because anyone can just run uuidgen when they want to try a new private interface. This would probably have been the type of interface I might have suggested 5 years ago, but since then I've written a bunch more wrappers and come to the conclusion that ultimately dispatchers are just way less pain in general.

ps. I want to point out that I'm not totally against such "object oriented" interfaces, rather I just find that most of the time dispatchers are ultimately less painful, result in less total lines of wrapper code and the theoretical benefits of fancier schemes rarely materialize in practice.
Last edited by mystran on Tue Jul 07, 2020 10:30 am, edited 1 time in total.

Post

S0lo wrote: Mon Jul 06, 2020 8:18 pm using C++ with something similar to COM. The final design that I decided to go for is NO dispatcher.
C++ with something similar to COM does not need a dispatcher. It already has one (ones) in the form of vtables.

Post

Vokbuz wrote: Tue Jul 07, 2020 10:30 am
S0lo wrote: Mon Jul 06, 2020 8:18 pm using C++ with something similar to COM. The final design that I decided to go for is NO dispatcher.
C++ with something similar to COM does not need a dispatcher. It already has one (ones) in the form of vtables.
vtables are good only for virtual functions. In my particular case back then, I needed full C++ interaction between host and plugin including static, global and plugin to host calls without the plugin knowing too much about the host's class.
www.solostuff.net
Advice is heavy. So don’t send it like a mountain.

Post

matt42 wrote: Tue Jul 07, 2020 5:59 am @Music Engineer, I agree automation and also, presumably, parameter changes should be passed in process call. This way you can have a sample accurate array, time stamped events or similar. The only thing is to have a solution for passing the data when audio isn't running, (not a big deal, but I recall when Steinberg hosts ignored the VST3 SDK solution to this and dropped events in such cases)
+1 on passing automation as events into the processing call.

I'd probably still keep a separate "setParameter" function that could be used in all the situations (with just the restriction that it must not be called concurrently with a process call) where passing events isn't possible or is highly inconvenient for one reason or another.

Post

Here's a question: what is the general opinion with regards to patch management?

Right now, I guess most plugins with any amount of complexity tend to just implement their own patch management. From the point of view of the host or a simple plugin, this isn't necessarily the ideal approach, but given the variety of schemes with plugins with potentially thousands of patches it doesn't seem like there is ever going to be a "one size fits all" approach and I can't help but wonder whether a new plugin interface should basically just ignore the concept of patch management, except as far as saving and loading the current state with the project file (or otherwise as a loose file) and notifying the host of preset changes?

Post

For what it's worth, internally I actually use a scheme where plugins mostly just describe themselves in a "properties" struct (eg. name, number of I/O, whether they are instruments, how much latency) and get a configuration struct from a wrapper, with a call to "reconfigure()" any time something like sampling rate or blocksize changes (with filtering to avoid redundant calls).

Beyond that I have reset(), process(), saveChunk(), loadChunk() and a bunch of stuff for dealing with parameters plus a callback to notify the host about preset name changes. The process() call gets I/O buffers, timing info (eg. tempo, ppq/sample positions, whether transport is playing) and a list of events. The wrappers also know how to open and close the editor and there's a callback for resize.

I guess having functionality for resume() and suspend() might be useful for some people, but for the most part I personally just don't care, except as far as showing the current status in the editor goes. With VST2 wrapper I trigger a reset() in resume(), but that's about it. If I wanted to support something other than stereo busses, then that would need a few extra things in the interface, but from my point of view, even VST2 is kinda bloated.

Post

mystran wrote:I can't help but wonder whether a new plugin interface should basically just ignore the concept of patch management, except as far as saving and loading the current state with the project file (or otherwise as a loose file) and notifying the host of preset changes?
i think so, yes. the c-interface should just provide a means to set and get the state from a plugin as amorphous binary blob. imposing any sort of structure on the data should be the job of the application framework - like juce, iplug, selfmade or whatever. for convenience in simple plugins, the c++ wrapper class could provide functionality for converting the binary data back and forth from/to simple parameter lists, though - but not the c interface. i actually even wonder, why the host would want to be notified about preset changes at all. what if the state of the plugin is no preset state anymore, because the user has turned some knobs? imho, from the host's perspective, a plugin just has a state that the host must be able to get and set - it doesn't need to know or care about how the state data is structured or whether the state is a preset or not (and *if* it's a preset, what name that preset has - vst had things like get/setProgram and get/setProgramName - i never used them)

in my plugins, a "preset" is just an xml file that can be loaded from the gui to set up the state of the plugin and the name of the preset is the filename of the xml file. the host has nothing to do with it. a "bank" of presets is just a folder of such xml files. (btw.: for state recall by host, i use the same xml data-structure and juce::AudioProcessor's copyXmlToBinary/getXmlFromBinary - btw. i actually think, this functionality should be located in the XmlElement class and not in AudioProcessor but whatever)
Last edited by Music Engineer on Wed Jul 08, 2020 1:11 pm, edited 1 time in total.
My website: rs-met.com, My presences on: YouTube, GitHub, Facebook

Post

Music Engineer wrote: Tue Jul 07, 2020 5:31 pm i actually even wonder, why the host would want to be notified about preset changes at all.
Mostly because it means it should refresh all the parameters and the name of the current preset (which is nice to show on a track, especially for instruments) and possibly some other such state that might be cached, even though there was no automation to be recorded.

I happen to think that an interface for getting/setting the current patch name is potentially useful, even if you don't otherwise have any concept of presets beyond "the current plugin state."

Post

I wonder how sampling rate changes might be handled. Would plugins have to be reloaded, or could it be done with minimal interference.

Locked

Return to “DSP and Plugin Development”