[LAD] Plugin buffer size restrictions

David Robillard d at drobilla.net
Wed May 30 21:09:37 UTC 2012

On Thu, 2012-05-31 at 06:59 +1200, Jeff McClintock wrote:
> > From: David Robillard <d at drobilla.net>
> > 
> > I'm a modular head, I remain convinced that control ports are nothing
> > but a pain in the ass and CV for everything would be a wonderful
> > fantasy land :)
> It's called "SynthEdit land" *everything* is CV ;)  (not on Linux sorry).
> > As it happens, I am currently porting the blop plugins to LV2, and
> > making a new extension in order to drop the many plugin variants (which
> > are a nightmare from the user POV).  This simple extension lets you
> > switch a port from its default type (e.g. Control) to another type
> > (e.g.
> > CV).  The pattern looks something like this:
> > 
> > /* plugin->frequency_is_cv is 1 if a CV buffer, 0 if a single float */
> > for (uint32_t i = 0; i < sample_count; ++i) {
> >     const float freq = frequency[s * plugin->frequency_is_cv];
> >     if (freq != plugin->last_frequency) {
> >         recalculate_something(freq);
> >         plugin->last_frequency = freq;
> >     }
> > 
> >     /* Do stuff */
> > }
> That's smart. In a simple example this doesn't seem like much of a win.
> Because A 1 port plugin has only two possible variants (frequency as
> single-float/ buffer). But..
> * A 2-port plugin has 4 varients.
> * A 3-port plugin has 8 varients.
> * A 10 port plugin has 1024 varients!
> So you're avoiding that combinatorial nightmare.
> I do something similar. The port is flagged as either 'streaming' (use the
> entire buffer) or 'static' use a single float. My point of difference is -
> the entire buffer is provided either way. So you have the option of writing
> the plugin like..
>      const float freq = frequency[s];
> ..OR...
>      const float freq = frequency[s * plugin->frequency_is_cv];
> .. and it works transparently either way. So the extension is backward
> compatible with 'dumb' plugins, or 'dumb' plugin standards like VST (I can
> interface VST plugins with modular components).
> > Doing those comparisons to see if the value actually changed since the
> > last sample in order to recalculate is not so great (branching).
> I don't know if you can implement what I do. Once I know which ports are
> single floats I 'switch' processing functions. i.e. use a function pointer
> to select 1 of several optimised functions.  So you write a general purpose
> loop like the one above, this is your fallback. Then you write an optimised
> one that assumes 'frequency' is a single float - This one has no branching
> and no extra multiplication, it's super efficient. You get the best of both
> worlds.  Note I don't write loops optimised for every possible combination,
> just pick a few key ones. The function pointer is one extra level of
> indirection, but it's much faster than branching, esp when there's several
> ports involved in the decision.

That's essentially the "variants" I am trying to avoid, with the
combinatorial explosion and all that.  Might be worth it for
optimization in some cases, but probably not significant in most.
Probably only when branching can be avoided, and vectorization can only
be achieved in the optimized version.

(I actually think vectorization is a better argument for block size
restrictions than the previously mentioned things.  That stuff (e.g.
SSE) is literally designed for audio and makes a massive difference, but
plugins can't make the best use of it without certain guarantees)

You can do all the above things mentioned in a host, especially if the
module API is internal and you can do whatever you want, but if a 'dumb'
plugin only reads a single float, well, it only reads a single float.

I guess you could say I'm trying to drag LV2 out of the "dumb plugin"
category :)

That said, I don't know if "CV everywhere" is really the best solution.
For some parameters, the ability to do audio rate modulation is
definitely key, and much more of that in 'standard' plugins would be
great.  However, for other things, not so much, and it does make for a
severe increase in memory consumption.  In modular environments a more
clever buffer allocation scheme could make that less of an issue.  Mine
is currently admittedly quite dumb :)

I am tending towards the conclusion that *both* CV and events (i.e.
sending changes) are needed, but single floats just plain suck.

> > personally my interest in a solution here is very real.  More people
> > care about normal high level parameters and being able to interpolate
> > than low-level modular synth CV stuff, but to me it's telling that (it
> > seems...) one solution can solve both problems nicely.
> <high five> ;)

Go team! :)


More information about the Linux-audio-dev mailing list