On Wed, 2007-05-09 at 15:41 +0200, Fons Adriaensen wrote:
On Wed, May 09, 2007 at 12:36:34PM +0200, Lars Luthman
wrote:
On Wed, 2007-05-09 at 12:21 +0200, Fons
Adriaensen wrote:
1, Only integer sample rates. This should be at
least a fraction
of two integers.
Given that JACK only supports integer sample rates I don't think that
this is a big deal. On the other hand I can't really see any
disadvantages with having it as a float or double, so if there are any
compelling reasons for doing that I think I agree.
There is no reason to assume that plugins will always be used in
a Jack client. Fractional rates are required because resample
ratios often can't be expressed as a float or double. It's a
problem with the libsamplerate API as well.
OK, then I agree. I see no reason to keep it a single integer.
2. Plugins are expected to have a fixed set of ports.
There are
cases where a plugin can only decide wich ports it will need
after being instantiated.
This can be done using an extension. I think Nedko Arnaudov has already
specified one for dynamically appearing and disappearing ports.
See his comments in this.
Right, his extension didn't do what I thought it did. You can still
write another extension that does.
3. Plugins may want to delegate some of the processing
to threads
running just below the audio thread priority, so this priority
is an essential initialisation parameter.
Can be done as a HostFeature.
So a plugin writer can't count on it.
A plugin writer can count on the host supporting that feature if it uses
the lv2:requiredHostFeature predicate. The host will then not attempt to
load the plugin unless it supports that feature.
4. There are 'audio rate' and 'control
rate' ports, but no 'init
time' ports. How are plugins supposed to discover initialisation
parameters ?
Can be done as a HostFeature.
Again, of no use it you can't count on it being present.
See above.
5. If a plugin is instantiated multiple times to
operate on
multi-channel data it may want to share control ports within
such a group, if only to optimise the (possibly complex and CPU
intensive) code that maps external control values to internal
data. I see no way to form such groups.
Can be done as a HostFeature.
Same remark as the two above, and I wonder how it can be done at all.
Part of the solution would be to have a period or frame counter as parameter
to each run(). It would at least allow a plugin to discover wich run() calls
to its instances belong to the same period, and which is the first one for a
period. Trivial to implement and there is no good reason why it shouldn't be
there by default. But it's only part of what is required, it doesn't define
which instances form a group in the first place. A single unique group ID
would do. Again very simple to implement as standard.
A basic way to do it would be to write an extension that adds a plugin
callback identical to DSSI's run_multiple(). If you need it for your
plugin to work you list it as a requiredHostFeature, if it works without
it but still supports it you list it as an optionalHostFeature.
6. The only way for plugins to discover if a control
port value
has changed is to keep a copy and compare all values during
each run(). See also (7).
This isn't all that expensive, but if a plugin really really needed a
new callback to be executed by the host when a control port value
changed it could be done as a HostFeature.
Again you can't count on it being implemented. And a callback for each
parameter change doesn't solve the problem - in many cases you want to
handle all changes together because they modify the same internal data
and you don't want to redo the possibly complex calculations each time.
What's so difficult about setting a flag when a parameter is modified ?
But the best solution is to do away with static control values and present
all control changes as timestamped events.
I was just giving an example - it would be just as easy to do a callback
that was called with a list of ports that has changed.
7. There is no fixed audio period. Host may call run()
for any
number of samples. This is probably meant as a way to allow
hosts to change control values at arbitrary points, but this
defeats the purpose of having control rate in the first place.
It's a typical 'let's be lazy' solution that does not solve
the original problem except in some simple cases.
Some algorithms can't be written to run efficiently - or at
all - in such circumstances. Plugins should be run() with
fixed block size.
Can be done as a HostFeature. In fact, there are two such extensions
already - see
http://tapas.affenbande.org/wordpress/?page_id=53
Again, if you can't count on it, it's not very useful.
See above.
If plugins are to know that certain things need to
happen at
particular offsets into a processing period then they should
be passed this info as a list of events (timestamed relative
to the start of the period), and be allowed to deal with that
in the most appropriate way, which may well be very different
to slicing up the audio period.
Some algorithms may even require that such events are presented
some number of samples ahead of their due time. This of course
forces the plugin to queue them internally, but in some cases
that's the only way to do it.
What is needed here is a generic way to pass a list of time-
stamped event to a plugin via a control rate port, and then
let the plugin deal with them as it sees fit.
Can be done as a port class. In fact, this is pretty much how the MIDI
extension works - see
http://ll-plugins.nongnu.org/lv2/ext/MidiPort
The core LV2 spec doesn't support much more than the LADSPA spec,
And that is the problem. It is much too easy both on hosts and plugins.
I really see no reason for not supplying an essential parameter such as
period size in the initialisation call. It's as fundamental as sample
rate. OK, some algos don't need it, but there are many that don't need
the sample rate either. Same for process priority and group ID.
All of this is trivial to ignore if you don't need it, but essential
in some cases.
*** These things should not be optional. ***
And why not present *all* control data as timestamped events from the
start ? In most cases there will be just one value for the start of the
period. Is this soooo difficult for a plugin writer to deal with ?
A plugin always has the simple option to ignore timestamps and just use
the last updates for the entire current period. You could even write a
simple wrapper library to present it with conventional control values
if it wants just those.
but that wasn't the intention. The point is
that it's easy to extend.
Optional support for fundament things is not a solution.
I think it is, if it is possible to implement the "fundamental" things
later when they are needed. Some of the things you've mentioned above
may be generally useful enough to go into the core spec, but on the
other hand LADSPA plugins have worked reasonably well without them, and
should a host that only wants LADSPA-type plugins have to implement lots
of functions that it doesn't really need? Isn't it better to have a
small core specification that all hosts and plugins use, and let hosts
and plugins that need more advanced features implement them as
extensions? Sure, all plugins will not work in all hosts, but there will
be clear mechanisms for a host to see which plugins it can use and which
it can't. DSSI plugins don't work in normal LADSPA hosts either.
--ll