A language for writing synths and effects.

You write how a sound is made, in a few lines of code. Pole turns that into fast machine code that goes straight into your plugin, with nothing extra to install and no compiler inside. It also runs in a web page, which is how the patch below plays.

Pole powers every block in Patchhaus, and it works on its own too, in your own plugin code. It will be open source.

Made by Sinuslabs, for Patchhaus

A plucked string — press Run, then the keysPlayground
processor Pluck
{
    input  stream float pitch;
    input  stream float gate;
    output stream float out;

    param  float decay = 0.4f [0.05f, 2.0f];
    param  float tone  = 0.4f [0.05f, 0.95f];

    float phase = 0.0f;
    float env   = 0.0f;
    float lp    = 0.0f;

    void main()
    {
        loop
        {
            if (gate > 0.5f) { env = 1.0f; }
            else { env = env * (1.0f - 1.0f / (decay * 48000.0f)); }

            let saw = phase * 2.0f - 1.0f;
            lp = lp + tone * (saw - lp);

            out <- lp * env * 0.3f;

            phase = phase + pitch / 48000.0f;
            if (phase >= 1.0f) { phase = phase - 1.0f; }
            advance();
        }
    }
}

One patch, two places to run it.

reverb.pole
92 lines of Pole
polec
--emit=export
reverb.o
1,944 bytes
reverb.h
4,318 bytes
Linked into your plugin
--emit=web
reverb.o
2,273 bytes, wasm32
reverb.json
2,468 bytes
wasm-ld
reverb.wasm
2,760 bytes
Run by a browser

In your plugin

Pole compiles the patch into machine code for your computer's processor. It goes into your plugin as two small files, and nothing else has to come along: no compiler, no Pole library.

In a web page

The same patch compiles to WebAssembly, the code format browsers run. That is how every example on this page plays, with nothing to install.

The same sound

The plugin runs the exact code you heard while you wrote the patch, not a rewrite of it. A test compares the two, sample for sample.

Press play.

Eight Patchhaus blocks wired into one Pole DSP patch, compiled to WebAssembly for this page. Drag them around, turn them, rewire them: every cable you can draw is already in the patch, and drawing it switches that route on.

Patchhaus›Block Synth
Sequencer
Run
Rate
Sync
Steps
GateLen
Oct
Root
Scale
Mode
Density
Seed
A3
A3
A4
A3
E4
A3
G4
A4
A3
A3
C5
A4
E4
D4
C4
A3
ADSR
A
D
S
R
050100150200250300ms343 ms +S
LFO
Rate
Sync
Tri
Oscillator
SAW
PW
Octave
0
Semi
0ST
Detune
0¢
Unison
Spread
Filter
Cutoff
Res
LP
VCA
Gain
L
R
Delay
Time
Sync
Feedback
Mix
Output
Gain
L
R

two fingers move · tap a port, then another

The same blocks, knobs and displays as the app. To write a block of your own in Pole DSP, open the playground.

How it runs in a plugin.

The browser is where Pole is easiest to try. The native object is what ends up in your plugin, and this is how it behaves there.

$ polec home-modules.pole --emit=export --out=home-modulespolec: wrote home-modules.o (7 functions, target arm64-apple-darwin25.0.0)polec: wrote home-modules.h$ wc -c home-modules.o   24904 home-modules.o$ nm -u home-modules.o_expf_sinf_tanf_tanhf$ export-check home-modules.pole  OK    identity: 1500 blocks of 64 frames, 3 side channels, 33 MIDI events, 24 parameter writes -- 0 block(s) differ, largest difference 0export-check: the plugin sounds like the editor

A real session, 2026-09-17 · export-check trimmed to its last two lines

Compiled before it ships

The patch becomes machine code for the processor before the plugin is built. Nothing compiles while it plays.

--emit=export → an object file and a C header

Nothing but math

The compiled code does arithmetic and calls a few math functions. While audio runs it never asks for memory, waits for another thread, or calls the operating system, the things that usually cause clicks in audio code.

all 30 examples: libm only, three import nothing

State in one block

Everything the patch remembers lives in one block of memory of a known size. The plugin sets it aside once, when it loads, so nothing grows while it plays.

reverb.h: POLE_REVERB_STATE = 10253 floats

What you heard is what ships

On every patch we test, the exported plugin plays exactly the samples the editor played. A test plays both with chords, retriggered and released notes, and knob moves, and compares every block.

30 graph patches, 0 blocks differ

Sixteen voices on 0.6% of one core.

Faster than real time, by this much. These are exported Pole objects, the same code a plugin ships, each timed on one core of an Apple M1 Pro.

Sixteen voices

167×

Each voice is a saw, a filter its envelope sweeps, and tanh drive. A second of audio takes 6 ms.

A wavetable oscillator

7,389×

A 1,024-point table, read every sample with linear interpolation.

A feedback delay

6,422×

A 16,384-sample line with one-pole damping inside the loop.

tools/webbench/native.mjs · 48 kHz · 128-frame blocks · best of 9 runs

Measured, not estimated.

Every figure here was produced by running the thing that produces it, on the commit this page was written from.

1,944 bytes

a reverb, compiled.

polec --emit=export on examples/reverb.pole. The header beside it is 4.3 KB.

One

function it borrows from the system.

_expf, from the C math library the operating system already has. The compiled code needs nothing else to run.

21–27 ms

to compile a patch.

Median of eleven runs each for gain, filter, synth, and reverb, to an object and a header.

24 of 29

examples sound exactly the same in the browser, sample for sample.

check_wasm.py · 4,096 frames · 48 kHz

  • adsr
  • bounded_search
  • delay
  • filter
  • fuzz
  • gain
  • modmatrix
  • octave_up
  • poly_graph
  • poly_simple
  • poly_synth
  • poly_voices
  • reverb
  • saw_gate
  • shaper
  • sine
  • soft_clip
  • stereo_chorus
  • stereo_width
  • synth
  • wavefolder
  • wavetable
  • wt_load
  • wt_synth
  • fft93 of 4,096 samples differ, by −150.5 dBFS at most
  • fx_chain2 of 4,096 samples differ, by −156.5 dBFS at most
  • spectral923 of 4,096 samples differ, by −138.5 dBFS at most
  • wt_osc532 of 4,096 samples differ, by −138.5 dBFS at most
  • feedback_lfoa feedback graph, which cannot run in a browser yet
  • poly_eventsneeds notes, which the check does not play

Every example is rendered as native code and in the browser, then compared sample for sample by scripts/check_wasm.py. The four that differ all use sin, cos, exp, pow, or log, which macOS and the browser each calculate with their own math library.

Where it runs.

  • Compile, render, export

    macOS
    Verified
    Linux
    Verified
    Windows
    Not built
  • WebAssembly output

    macOS
    Verified
    Linux
    Verified
    Windows
    Not built
  • Live audio and MIDI

    macOS
    Verified
    Linux
    No backend
    Windows
    No backend

“Not built” means exactly that: the compiler core has no platform headers and no reason not to build on Windows, but nobody has built it, so this table does not say it works. The platforms page has the detail.

Start anywhere.

Write your first patch.

Start in the playground, with nothing to install and the same compiler. Then take the patch wherever you need it.