On Thu, 12 Dec 2002, David Olofson wrote:
Still, that does not prevent a gread deal of overlap,
although XAP
gets more and more expensive the more you "abuse" it - just like full
audio rate or blockless systems tend to be less efficient when used
more like "VSTi style" synths.
I thought XAP was intended to replace LADSPA (in addition to extending
it).
about
integrating audio data into event queues as well? These
events would contain a pointer to a buffer. There - a single
[...]
I mentioned in another mail that I did consider this for MAIA. I also
mentioned that it brings implementational issues for Plugins...
(Asynchronous buffer splitting is nasty to deal with.)
What is that? If a plugin got an audio port event it would just update a
pointer. Past samples should be kept in temporary variables and future
samples should not be looked at.
My conclusion has to be that for both complexity and
performance
reasons, you're better off with physical Audio Ports, that
effectively are nothing but buffer pointers, maintained by the Host.
(LADSPA style.) This is simple and effective, and avoids some
complexity in Plugins.
Point conceded, although some of your arguments apply to controls as well.
I don't see anything physical about audio ports in XAP, although it might
be better if they were actual objects.
Being that it started out as little more than a list
of "commands"
and arguments (as an alternative to a bunch of hardcoded C calls), it
is currently *very* imperative.
However, due to the nature of the underlying audio rendering API, it
would not be far off to interpret the scripts as net descriptions
instead of step by step instructions. Just add plugins instead of
running commands, and then run the result in real time.
I have seriously considered this approach, but I'm not sure I'll do
it that way - at least not as an implicit, only way of using the
language. (The language itself is indeed imperative; this is more a
matter of what the extension commands do.)
Okay, I can see how that would be useful. I have a graphical network
editor in GluttonAudio (I've just decided to name it that) but without any
scripting it's not flexible enough. When you start adding script plugins,
however...
I've considered something spline-like, with one
control point or
something, but you really need 5 arguments for something useful;
<duration, start, end, start_k, end_k>. (With just one control point,
you would still have transients in between curve sections.)
That said, if curves are *chained*, you need only three arguments
<duraction, end, end_k>. <start, start_k> of the next segment will be
taken directly from the end parameters of the previous segment. (When
you use "set" events, those will be set to the target value and 0,
respectively, so "set" followed by a chain of curve segments will
work right.)
Since the actual *value* is still in there, plugins may chose to pass
curve segment events to the same case as the "ramp" events, which
would effectively just mean that the end_k argument is ignored. Or
you can approximate the curve with N linear sections internally, or
whatever.
Logically, controls are like ports: they have a definite value at each
point in time. So it would make sense to have a XAP_control_variable type
or something whose value could be set (via a macro) from an event and
whose value could be updated (also via a macro) after each sample is
processed.
Whatever the sections end up being, spline calculations should be done by
the host. What the plugin would see are just polynomial coefficients. With
third-order sections you get continuity of first derivatives, etc.
Example (well this is just copy-pasting from your post):
struct XAP_control_variable {
double value, dvalue, ddvalue, dddvalue;
};
typedef struct XAP_control_variable XAP_control_variable;
#define XAP_SET_CTRL_VAR (var, event) (var).value = (event) -> value; \
(var).dvalue = (event) -> dvalue; \
(var).ddvalue = (event) -> ddvalue; \
(var).dddvalue = (event) -> dddvalue;
#define XAP_UPDATE_CTRL_VAR (var) (var).value += (var).dvalue; \
(var).dvalue += (var).ddvalue; \
(var).ddvalue += (var).dddvalue;
It is
difficult to optimize your DSP calculations with respect to more
complex functions than linear
The *major* advantage though, is when you have filters and other
algorithms for which the input -> coefficient transform is expensive.
With audio rate control input, you have to do this for every sample.
With events, you can do it once per event or so, and then internally
ramp the coefficients instead. If linear ramping is not sufficient,
extend the transform (or do it for a center point as well) so you can
use polynomial "ramping" instead.
This is what I meant with optimizations. If you have a biquad with a
linearly changing cutoff frequency, for instance, you can optimize away
calls to trigonometric functions inside the inner loop without resorting
to approximation; just use the old "spinning point on the unit circle"
trick. Hmm, I realize now that the same can be done with a polynomial of
any degree but the computational benefit gets smaller and smaller. For
this reason it might make sense to just stick to constant values and
linear ramps. You could then have plugins that generated piece-wise linear
approximations of splines and the like with any accuracy desired.
So: I vote for constant and linear controls.
--
Sami Perttu "Flower chase the sunshine"
Sami.Perttu(a)hiit.fi
http://www.cs.helsinki.fi/u/perttu