The language

Program structure

Processors, main, advance, and the one rule that decides what a frame is.

Everyone. This page is the spine the rest hangs off.

A Pole file contains processors, and optionally graphs that wire them together. Nothing else lives at the top level — not a function, not a constant. A stray declaration is POLE0207.

A whole programPlayground
processor Gain
{
    input  stream float in;
    output stream float out;

    void main()
    {
        loop
        {
            out <- in * 0.5f;
            advance();
        }
    }
}

main runs once per sample#

Not once per block. Once per sample.

That single decision is why there is no modulation system in this language and no "control rate" to be coarser than the audio: anything you compute in main is per-sample by construction, so modulating a cutoff is multiplication rather than a feature you route through.

advance() ends the frame#

advance() is the frame boundary. Code after it in the same pass is unreachable and is reported (POLE0601).

A loop with no advance() in it is rejected (POLE0405). It would otherwise be an infinite loop, and quietly compiling it as "the body runs once" would make it mean something the person who wrote it did not write.

Rejected: a loop that never advances
processor NeverAdvances
{
    input  stream float in;
    output stream float out;

    void main()
    {
        loop { out <- in; }
    }
}

Every output starts each frame at zero#

An output the frame does not write reads 0 that frame — not the previous frame's value.

Playground
input stream float gate;

// On a frame where gate is 0, `out` is 0. It does not hold its last value.
if (gate > 0.5f) { out <- in; }

A value that should persist between writes belongs in processor state. This is the same on every path a program can run on — one node at a time, a whole block at a time, a fused graph, an exported object — because the generated frame function does the zeroing itself rather than leaving it to a caller.

What a processor may contain#

input / output streamits endpoints
paraman endpoint with a name, default and range
externala buffer the host owns — a wavetable, a sample, an impulse response
state declarationsfloat phase = 0.0f;, float line[2048];
functionspure helpers, inlined at the call site
initstate built once, before the first frame
on <endpoint>an event handler, run between samples
void main()the frame loop

What is deliberately absent#

No dynamic allocation. No recursion (POLE0603). No pointers, no structs, no strings, no generics. Every loop has a bound the compiler can see.

That last one is not austerity for its own sake — it is what makes a patch written by a stranger safe to compile and run, which is what lets the playground exist at all.