Functions
Give an idea a name, pass its inputs explicitly, and reuse it — with signatures, arguments and worked calls.
Anyone who wants to turn a repeated expression into a readable DSP helper.
Suppose your patch blends two values in several places: a dry and wet sample,
two table entries, perhaps two modulation sources. You could repeat
a + (b - a) * t each time. A function lets you name that operation once and
make the rest of the patch read in terms of what it does.
In Pole a helper belongs inside a processor, beside main(). The helper
receives values, computes a result and returns it. It does not run on its own:
you choose when to call it.
Read a function signature#
Here is the reference form of a linear interpolation helper:
float lerp(float a, float b, float t)Read it from left to right: “return a float; the function is named lerp;
it takes three float arguments called a, b and t.” The types belong in
the definition. At the call site, supply only the values:
lerp(0.2f, 0.8f, 0.5f) → 0.5f| Parameter | Meaning |
|---|---|
a | Start value. Returned when t is 0. |
b | End value. Returned when t is 1. |
t | Blend position. 0.5 is halfway; values outside 0…1 extrapolate beyond the endpoints. |
Returns: a + (b - a) * t, as a float. This version does not clamp t.
There is no built-in lerp; the definition below creates it for this processor.
A function parameter is the name in its definition. An argument is the
value you pass when calling it. These are different from a processor's
param, which is a control the host can move.
Define it, then call it#
processor Blend
{
input stream float in;
output stream float out;
param float mix = 0.5f [0.0f, 1.0f] smooth 20.0f;
float lerp(float a, float b, float t)
{
return a + (b - a) * t;
}
void main()
{
loop
{
let dry = in;
let wet = tanh(in * 3.0f) * 0.5f;
out <- lerp(dry, wet, mix);
advance();
}
}
}The call lerp(dry, wet, mix) binds dry to a, wet to b and mix to
t. Pole evaluates the helper's expression and uses the returned sample as
the output. You can pass literals, local variables, endpoints or other
expressions; the helper sees their values.
At mix = 0, you hear the original input. At mix = 1, you hear the soft-clipped signal. Between them you hear a blend. This is a linear crossfade, so it does not promise constant perceived loudness for unrelated signals.
Try it: change the wet expression to in * -1.0f. Halfway through the
blend, the original and inverted signals cancel. The helper has not changed;
you changed what its arguments mean.
Calls are positional and explicitly typed#
Supply every argument in the order shown in the signature. Pole does not have named arguments or default argument values for helpers.
| Call | What happens |
|---|---|
lerp(0.0f, 1.0f, 0.25f) | Returns 0.25f. |
lerp(1.0f, 0.0f, 0.25f) | Returns 0.75f; swapping the endpoints changes the direction. |
lerp(0.0f, 1.0f) | Rejected: an argument is missing (POLE0326). |
lerp(0, 1, 0.25f) | Rejected: the first two arguments are ints (POLE0327). |
Use float(value) when a value is an int and the helper expects a float.
The compiler checks user-defined helper arguments against their exact declared
types. In particular, the scalar broadcasting supported by maths builtins does
not make a scalar argument satisfy a helper's float<2> parameter.
Pure helpers and persistent state#
A Pole helper is pure: it reads its arguments and returns a value. It
cannot read or write a processor's state or endpoints directly. It also cannot
advance the audio frame. Pass the values it needs, and assign its result in
main().
This distinction matters for a filter. The arithmetic for one update can be a helper, while the previous sample remains state owned by the processor:
processor GentleLowpass
{
input stream float in;
output stream float out;
param float amount = 0.1f [0.001f, 1.0f] smooth 20.0f;
float previous = 0.0f;
float follow(float sample, float history, float coefficient)
{
return history + coefficient * (sample - history);
}
void main()
{
loop
{
previous = follow(in, previous, amount);
out <- previous;
advance();
}
}
}history is a copy of the previous output. The assignment to previous
happens after the call returns, preserving the new result for the next frame.
A small coefficient makes the output follow the input slowly, reducing high
frequencies; at 1 it follows immediately. The coefficient is dimensionless,
not a cutoff in Hz.
For a reusable effect that owns several state variables, use a processor in a graph. A helper is a good home for arithmetic; a processor is a good home for an oscillator, envelope or filter.
Return on every path#
A typed helper must return a result whichever branch it takes. A final
return is often the clearest way to express the ordinary case:
float clip(float x)
{
if (x > 1.0f) { return 1.0f; }
if (x < -1.0f) { return -1.0f; }
return x;
}The two early returns handle out-of-range values. The final return handles
all values inside the range. A missing return is POLE0351.
return is for helpers. In main(), end the frame with advance();
returning from main() is POLE0352.
Vector arguments and results#
A helper can take and return a stereo value:
processor SwapChannels
{
input stream float<2> in;
output stream float<2> out;
float<2> swap(float<2> sample)
{
return float<2>(sample[1], sample[0]);
}
void main()
{
loop { out <- swap(in); advance(); }
}
}sample[0] is the left lane and sample[1] the right. The constructor creates
a new pair in the opposite order. No array or separate channel state is needed.
How calls compile#
Pole inlines helpers: the compiler places their arithmetic where each call appears. There is no runtime function-call overhead, but calling an expensive helper many times still repeats its work.
A helper can call another helper. clip(clip(in)) is also valid: the inner
call returns before the outer one uses its value. Recursion is different:
a helper that calls itself, directly or indirectly, is rejected (POLE0603).
You also cannot redefine a builtin such as sin or clamp (POLE0350).
Next: maths in a patch explains vector calls and common DSP conversions. For exact argument lists, open the built-in function reference.