An embeddable implementation of SuperCollider's scsynth audio synthesis engine.
An scsynth-compatible synthesis core that can be driven by any pure-Rust audio backend (e.g. cpal, bevy_audio, etc) preserving scsynth's hard realtime performance - no locks, blocking, heap allocation or I/O on the audio thread. Named after this.
- Embedded targets and
wasm32-unknown-unknown- plyphon is a#![no_std]Rust crate, making it compatible with a lot of embedded device targets, including the web. C++ bindings are typically hard to wrangle for Rust's most common web target. An attempt has been made inscsynth-rs, but the approach requires many small patches to supercollider itself, and teasing out the raw state machines for the RT and NRT threads while providing a reliably safe API is non-trivial. A pure-Rust implementation simplifies this a lot. - Library-first, OSC optional - plyphon is a library you embed and drive through a typed Controller API. The OSC layer is an optional front-end on top. In-process users can skip OSC entirely (no serialization, no socket) while still getting scsynth-compatible OSC when they want it.
- Custom storage - plyphon makes no assumptions about the availability of a filesystem. Storage is abstracted away with traits, allowing implementations to fetch sounds however they like (filesystem, web storage, network fetch, etc).
- No global state, many engines per process - scsynth keeps its UGen library, interface table, and audio arena in process-global statics, so a process is effectively a single server. plyphon owns all of that in an engine value passed by argument, so multiple independent engines can coexist in one process - useful for tests, multi-tenant/embedded hosts, plugin hosts, or per-voice sandboxing.
Listed in reverse-topological order - dependents first, their dependencies below.
| Crate | Description |
|---|---|
plyphon-cli |
The plyphon binary - an scsynth-compatible OSC synthesis server (UDP/TCP) and offline renderer, built on the crates below. |
plyphon-osc |
SuperCollider-compatible OSC command front-end. |
plyphon-buffers |
Async BufferSource traits for loading sample data, the app-provided I/O seam. |
plyphon |
Control-side facade - the Controller, SynthDef authoring and compilation, and the engine() builder. Re-exports the three crates below. |
plyphon-rt |
Real-time audio driver - the World engine, node tree, command protocol, and NRT cleanup. |
plyphon-unit |
Unit-generator abstraction - the Unit trait, the built-in units, and the compiled GraphDef. |
plyphon-dsp |
Shared DSP primitives - rates, RNG, wavetables, buses, buffers, and streams. |
rt-alloc |
Safe, no_std real-time memory pool - a port of scsynth's AllocPool. |
scgf |
Parser and encoder for SuperCollider's binary SynthDef format (SCgf). |
| Example | Description |
|---|---|
motif |
A looping motif of self-freeing notes via cpal. |
sine |
The simplest example: a continuous sine. |
custom-unit |
Implement a custom unit generator (a tanh saturator) and register it alongside the base set. |
routing |
Bus routing: an LFO-swept filter on noise, wired through audio and control buses. |
control |
Host-driven control buses: an arpeggio steered by /n_map + /c_set. |
scgf |
Loads a SuperCollider SCgf-compiled SynthDef and plays it. |
sampler |
Implements a BufferSource that loads a checked-in WAV (filesystem natively, fetch on the web) and loops it with PlayBuf. |
stream |
Streams a WAV from storage in chunks via a BufferStream/StreamFeeder and plays it with DiskIn. |
waveforms |
Cycles through the oscillators (Saw/Pulse/LFSaw/LFPulse/Impulse) through a filter. |
operators |
A ring-modulated, soft-clipped bell tone built from BinaryOpUGen/UnaryOpUGen math operators (midicps, midiratio, ring modulation, softclip). |
filters |
A classic resonant low-pass sweep: a saw through an LFO-swept RLPF (one of the resonant biquads RLPF/RHPF/BPF/BRF/Resonz/Ringz). |
moog |
A resonant acid bassline: a saw through a MoogFF Moog-ladder filter with an LFO-swept cutoff and high feedback resonance (the filter additions MoogFF/Formlet/MidEQ/SOS/Median/Lag2/Hilbert/FreqShift). |
noise |
Metallic rain: Dust2 impulses ring a Ringz resonator over a quiet PinkNoise bed (the noise family WhiteNoise/ClipNoise/GrayNoise/PinkNoise/BrownNoise/Dust/Dust2). |
wandering |
A generative burble driven by the low-frequency/dynamic noise family: LFNoise1 wanders the pitch, LFNoise2 sweeps the filter, LFDNoise3 shimmers the amplitude (LFNoise0/1/2/LFClipNoise/LFDNoise0/1/3/LFDClipNoise). |
sample-hold |
A self-playing sample-and-hold sequence: an Impulse clock latches a pitch contour with Latch into a Decay2-plucked saw (the in-graph trigger units Trig/Latch/Gate/ToggleFF/Stepper/Phasor/...). |
auto-wah |
An envelope-following auto-wah: a PeakFollower tracks a plucked source's amplitude and drives an RLPF cutoff (the signal-measurement units Peak/RunningMin/RunningMax/PeakFollower/MostChange/LeastChange/LastValue). |
scale-walk |
A scale-quantised melodic walk: an LFNoise1 indexes a scale buffer through Index, so a smooth wander always lands on in-scale notes (the selection/lookup units Select/Index/IndexL/WrapIndex/FoldIndex). |
bell |
Modal bell synthesis: an Impulse strikes a Klank bank of inharmonic resonators (tubular-bell ratios), ringing a struck-metal bell (the additive/modal banks Klang/Klank). |
wavetable |
A morphing wavetable drone: a VOsc sweeps its position through a bank of increasingly-bright wavetables, crossfading the timbre from a pure sine to a rich saw (the wavetable oscillators Osc/OscN/COsc/VOsc/VOsc3). |
vowel |
A synthesized sung vowel: three Formant oscillators voice the formants of an "ah" over a vibrato'd fundamental, forming a vocal-like drone (Formant, alongside the batch's SinOscFB/Blip/LFGauss). |
granular |
A granular time-stretch: Warp1 smears a short synthesized arpeggio into a slowly-morphing stereo pad, holding pitch while a slow pointer stretches time (the granular family GrainSin/GrainFM/GrainIn/GrainBuf/TGrains/Warp1). |
reverb |
A cavernous space: two Karplus-Strong plucked strings on drifting clocks smear through a large GVerb FDN reverb (the delay/reverb family BufDelay*/BufComb*/BufAllpass*/DelTapWr/DelTapRd/Pluck/PitchShift/FreeVerb/FreeVerb2/GVerb). |
waveshaping |
A wavefolder: a sine driven hard through Fold with an LFO-swept drive (the range shapers Clip/Wrap/Fold/LinExp/...). |
chaos |
A chaotic drone: a CuspN oscillator through a resonant filter swept by a slow LatoocarfianN map (the chaotic generators CuspN/QuadN/GbmanN/StandardN/LatoocarfianN/LinCongN). |
hard-sync |
A hard-sync lead: a SyncSaw whose saw frequency is swept by an LFO over a fixed pitch (the oscillators LFTri/LFPar/LFCub/VarSaw/SyncSaw/FSinOsc). |
bouncing-ball |
Physical-model percussion: a TBall bouncing on an oscillating floor rings a Ringz resonator (the physical models Spring/Ball/TBall). |
comb-string |
Karplus-Strong plucked strings: periodic noise bursts excite a tuned CombL resonator (delay = one pitch period), diffused by an AllpassC (the recirculating delays CombN/L/C/AllpassN/L/C and interpolating DelayL/C). |
drunk-melody |
A self-driving drunk-walk melody: Duty.kr clocks a Dibrown integer random walk over MIDI notes (midicps + Lag glide), showcasing the generator demand sources Dgeom/Diwhite/Dbrown/Dibrown. |
pan |
A tone auto-panned across the stereo field with Pan2. |
envelope |
Percussive plucks shaped by multi-segment EnvGen envelopes that free their own synths. |
osc |
Drives the engine through encoded SuperCollider OSC packets (no sockets) and prints the control commands and the replies/notifications that flow back. |
schedule |
Sample-accurate rhythm: schedules time-tagged OSC bundles up front, each note onsetting on its exact sample via the engine's drift-corrected scheduler and OffsetOut. |
render |
Offline (non-real-time) rendering: reads a binary OSC score and renders it to a WAV faster than real time and deterministically - plyphon's scsynth -N. |
All dependencies (the Rust toolchain, alsa/pkg-config for the native cpal backend, and the
wasm tooling) are provided by the Nix flake:
nix develop # or `direnv allow` (uses ./.envrc)
cargo build
cargo test
cargo run --release -p example-sine # the simplest demo: a continuous sineEach example is a cargo run -p <name> away - see the Examples table for the full set.
Every example also runs in the browser - the same engine, compiled to wasm32-unknown-unknown. The
web build is one site: a landing page linking to a page per example, each running that example's
wasm. It is built by nix build .#plyphon-website and auto-deployed to
GitHub Pages on every push to main.
nix run .#serve-plyphon-website # build the whole site and serve it on localhost:8088
# or, for live-reloading a single example during development (the nightly WASM-threads shell,
# since every page is the AudioWorklet build):
nix develop .#plyphon-web -c trunk serve web/<name>.htmlOpen localhost:8088 and click once to start audio (browsers hold audio until a user gesture).
cpal is the audio backend on both targets: natively via ALSA/CoreAudio/WASAPI, on the web via its
AudioWorklet backend (a real audio thread over WASM threads / SharedArrayBuffer). The plyphon
engine that feeds it is identical on both - only how the control plane is ticked differs by platform.
plyphon is an early-stage research engine. That said, internals and OSC support
should already be roughly on par with scsynth.
~1/3 UGens are yet to be ported (there's a LOT of them). See this issue for a living checklist.
plyphon does not yet have a story for .scx plugin compatibility, though it
would be great to have and proposals are welcome.
Licensed under GPL-3.0-or-later, matching SuperCollider's license.