[LV2] Buffersize, Options and Externtion-Data

Robin Gareus robin at gareus.org
Wed Sep 9 12:00:01 PDT 2015


Hi Filipe, LV2ers,

(cutting some parts here, please see the original email for references)

Executive summary: There are two separate issues here:

1) Semantics of "maxBuffersize"

 Is bufsz:maxBlockLength an "all time max" while the plugin is
 instantiated?

 Proposed answer is "yes" and we need a new "bufsz:nominalBlockLength"
 which can change dynamically.


2) Options API clarification:

 Is there a difference if the Option is passed during instantiate vs
 Pption is passed as extension-data.

Robin says "yes", during instantiation it's const data.
Filipe says "no" both are identical.

If Filipe is right, Robin wants to know why there are two APIs to do the
same :)



Now for the long version:

On 09/09/2015 05:48 PM, Filipe Coelho wrote:
[..]
> Note that Carla has always supported reporting buffer size changes to
> the plugins (similar to a JACK buffersize callback)
> 
> This is done by using the Options interface, which is provided by the
> plugin and called by the host.
> Carla calls options->set() during JACK buffersize callbacks.

Since Carla reports the current jack-period as "max", a plugin that uses
this "max" during *instantiation* to pre-allocate buffers will crash, if
the buffersize is later increased (jack_bufsize).

Plugins that pre-alloccate buffers are a lot more common than plugins
that need to know the expected "current" (temporary-maximum until
further notice) buffersize for optimization.

Hence requiring all plugins to implement dynamic buffer-size changes
(re-allocate on demand, any time) is the wrong approach.



[..]

> I think talked with David about this, if options could be used for
> this or not. I got the idea that yes, that was one of the actual
> intentions for the Options extension.

Yeah, Options extension used as extentionData. I'm all for it. Alike the
plugin in
https://github.com/DISTRHO/DPF/blob/master/distrho/src/DistrhoPluginLV2.cpp#L660
does.

Yet, for the case at hand, we need a new property:
"nextBlockLength" or "nominalBlockLenght" or "currentBlockLength"
and not re-use min/max.



IMHO the maxBlockLength specification should be amended:

http://lv2plug.in/ns/ext/buf-size/#maxBlockLength

"The maximum block length the host will ever request the plugin to
process at once, that is, the maximum sample_count parameter that will
ever be passed to LV2_Descriptor::run()."

Proposal to amend:

"This value will be valid for complete lifetime of the plugin after
instantiation and not change dynamically."

[..]

> For example, in Ardour running JACK in realtime at 1024 buffer size the
> maximum the engine can do (while realtime) is 1024.
> Correct me if I'm wrong, but Ardour will never call run() on plugins
> with more than 1024 frames, will it? (*realtime*)

Not usually, but Ardour may indeed do so. Plugin analysis (spectrum
display) is done on rt-data in larger chunks.

Seamless loops in some host implementations may also "over-read" (finish
current cycle, throw away data and continue at the beginning of the loop).

[..]

> So Ardour is not doing anything wrong, technically.
> It's still indeed its maximum value, just one that is fixed at all times.
> That's why I still think this needs a new property.

Agreed.

I may sound repetative, but the current "max" is very useful to
pre-allocate buffers and not useful at all for some other cases e.g.
optimize current convolution kernel size.

[..]

> What I want to make sure we agree on, is that this "current" value we're
> after it's the "engine realtime maximum"

yes.

To further clarify:  It's the "expected" value, and most of the time
this value will also be passed as n_samples to run().

Still, run() can be called with any other buffer-sizes occasionally (as
long as those are between min and max).


> PS: Anyone got a suggestion for a "engine realtime maximum" property name?

see above. I propose: "nominalBlockLength"


>> Specs Clarification
>> -------------------

[..]

> When the spec says:
> "There are two facilities for passing options to an instance:
> opts:options allows passing options at instantiation time,
> and the opts:interface interface allows options to be dynamically set
> and retrieved after instantiation."
> 
> Seems to me that options:interface and instantiate-time feature serve
> the same purpose.
> Giving special meaning to one of them seems wrong.

Why provide 2 different ways for the same thing then?

The only reason In can think of would be variable-scope when using pointers.

The reference passed as Instantiation Option is only valid during
instantiate. The actual value may be on the stack of the host and leave
scope after instantiation.  This further implies that all values are
constant during instantiate (because the value may only change in the
instantiation thread).


Extension-data on the other hand is valid for the lifetime of a plugin
and allows dynamic opts:interface get/set.


If both facilities are indeed 100% identical, one of them should be
deprecated.


[..]

>> One possible solution would be to require a host to activate/deactivate
>> plugins to dynamically set the buffersize (2,3) or to re-instantiate the
>> plugin (1). This could be tied in with fixedBlockLength [3] without any
>> changes to the spec, but will render some plugins useless.
>>
> I think for buffer size changes deactivate/activate should be required
> in between.
> It's just a few lines added to the spec. :)

For the min/max buffersize I disagree. They should be instantiation
parameters and constant.

Proposal:

"A plugins with or lv2:requiredFeature bufSiz:maxBlockLength MUST be
re-instantiated if the max blocksize changes."


"If the nominalBuffersize changes a host may deactivate/activate the
plugin but is not required to do so."

Since get()/set() must not be called concurrently with run(), not
re-activating the plugin is fine.

This depends on the host/engine. To explain: some audio-systems announce
buffer-size changes asynchronously without interrupting the actual
audio-processing (sliding buffers). The LV2-host must in this case
assure synchronous threading and prevent calling run until the plugin is
informed (or re-instantiated).



> Imagine a plugin that requires fixedBlockLength
> When the buffer size changes via JACK (or something else) the plugin
> will no longer work.
> The host has to either inform the plugin about the change or
> re-instantiate it.

correct.

If the /new/ nominalBufferLength (here jack buffer-size) is below
bufSiz:maxBlockLength just informing the plugin about the change is fine.

Most plugins will just see n_samples change in run(.., n_samples),
Plugins with an opts:interface can be informed out-of-band.


Comments, corrections and criticism is very appreciated.
Speak now of forever remain silent :)


Cheers!
robin


More information about the Devel mailing list