The language

Arrays

Power-of-two sizes, an index that wraps instead of faulting, and why that is the whole safety story.

Anyone writing a delay line, a table or a buffer.

A state array holds float, int, or a vector of either:

Playground
float line[2048];            // a mono delay line
float<2> stereoLine[1024];   // a stereo one, as ONE array

float<2> buf[1024] is a stereo delay line that cannot drift out of step with itself, which two parallel arrays can. It occupies 2048 floats of state — the size is in elements, the storage is per lane.

Sizes must be a power of two (POLE0320).

Capacity and duration are different#

A buffer's size is measured in elements. Its duration depends on the rate at which you write those elements. A 2,048-element mono delay holds about 42.7 ms at 48 kHz, but only 21.3 ms at 96 kHz. Stereo elements contain two lanes, so a float<2>[2048] buffer holds the same number of frames and twice the data.

Choose a power-of-two capacity large enough for your longest delay at the highest supported sample rate. Then constrain the requested delay to that capacity. Wrapped indexing protects the memory access; it does not know that you intended a particular duration.

The index wraps; it does not fault#

An index into a sized array is masked (i & (size - 1)), not bounds-checked:

Playground
line[pos - 14000]      // negative wraps to the far end
line[999999]           // wraps; never reads outside the array

One instruction, no branch on the audio path, and no index a program can compute can reach memory outside its own array.

That is the whole reason arrays can exist in a language where a running patch must never be able to trap — and it is why a delay line is written by walking a write pointer forward and reading behind it, with no wrap arithmetic of your own:

A delay you can hear — the index does the wrappingPlayground
processor Delay
{
    input  stream float in;
    output stream float out;

    param  float time     = 0.25f [0.01f, 0.9f];
    param  float feedback = 0.45f [0.0f, 0.95f];

    float line[131072];
    int   pos = 0;

    void main()
    {
        loop
        {
            let taps = clamp(int(time * processor.frequency), 1, 131071);
            let old  = line[pos - taps];      // negative: wraps to the far end
            line[pos] = in + old * feedback;
            out <- in * 0.6f + old * 0.6f;
            pos = pos + 1;
            advance();
        }
    }
}

A sizeless external is the one exception: its length is not a power of two, so its index is clamped to [0, length − 1] instead. Both guarantees say the same thing — no index reaches memory outside the array.

Endpoint arrays index the same way#

Playground
input stream float voiceGate[8];

var held = 0.0f;
for (wrap<8> v) { held = held + voiceGate[v]; }
out <- held * 0.1f;

Same masking, same rule. That is what makes polyphony a loop rather than eight copies of everything.