8. daslang strudel vs strudel.cc — Feature Comparison
This page compares the daslang strudel library
(modules/dasAudio/strudel/) to its inspiration, the strudel.cc
live-coding system. It is the only documentation page that names
strudel.cc explicitly — all other pages should reference this one for
anything comparative.
Read this before porting a strudel.cc pattern to daslang. The
Claude-assistant porting workflow lives in the repository at
skills/strudel_port.md. For the
generated reference of every strudel symbol, see
Strudel (Live Coding). For the tutorial series, see
daStrudel (Live-Coding) Tutorials.
8.1. Scope and philosophy
The daslang port is feature-focused, not code-ported. We implement the musical primitives of strudel.cc on top of daslang’s compiler, pattern matcher, and audio engine — but with no JavaScript runtime, no web UI, no REPL, and no external DSP graph. Everything runs in one daslang context, with a per-voice synthesis pipeline and per-orbit effect busses.
Two consequences of that design:
The core pattern algebra, mini-notation, scales, SF2/MIDI, and live-reload are first-class. For the vast majority of strudel.cc patterns you can rewrite the code almost verbatim — same names, same mini-notation, same combinators.
The synth engine and effect routing are daslang-native and sometimes diverge. Per-voice FX, orbit busses, and ADSR defaults all have specific semantics that do not match strudel.cc exactly. Those cases are enumerated below.
8.2. What we have
Parity or near-parity with strudel.cc:
Feature area |
daslang module |
Notes |
|---|---|---|
Mini-notation |
|
|
Pattern algebra |
|
|
Time combinators |
|
|
Per-voice combinators |
|
|
Choice combinators |
|
|
Euclidean rhythms |
|
|
Scales |
|
|
Signals |
|
|
Synthesis |
|
oscillators ( |
Samples |
|
WAV / MP3 / FLAC / OGG loading via |
SF2 soundfonts |
|
Full SF2 parser (format 0/1 meta-events, generators, modulators), per-voice envelope / LFO / biquad, GM drum map compatibility, expression and mod-wheel CCs |
MIDI playback |
|
Format 0/1 parser, merged-track playback, GM preset mapping, integration with synth or SF2 backend |
Live-reload |
|
Persistent state across source reload via
|
Effects (send busses) |
|
Per-orbit |
Effects (per-voice) |
|
Phaser, tremolo, compressor, waveshaper, DJ filter, bitcrush, sample-rate reduction — all applied per voice before the orbit mix |
8.3. What we don’t have (yet)
Features that are present in strudel.cc and absent in the daslang port:
``euclidRot`` — Euclidean rotation helper. Not implemented; compose
euclidwithrevorofffor a workaround.Mini-notation ``bd(3,8)`` form — tokens
(/)are lexed but not parsed into Euclidean rhythms. Use theeuclid(pat, 3, 8)function form instead.``jux_rev`` / ``chop`` / other convenience aliases — the parametric forms (
jux(pat, fn),stutter, etc.) are public; a few one-letter convenience wrappers were not ported.Web sample packs — strudel.cc streams sample packs from the web at runtime; daslang loads local samples from disk (via
strudel_load_sample_dir). Bring your own sample library.REPL UI — strudel.cc has a browser REPL with visualisation; daslang uses
daslang-livefor hot-reload and a separate visualiser example (examples/daStrudel/strudel_visualizer/).OSC / tidalcycles output — the daslang port renders audio directly. There is no equivalent of strudel.cc’s SuperDirt / OSC backend.
Hydra-style visual patterns — out of scope; daslang is audio-only.
Some mini-notation modifiers — a handful of exotic forms (e.g. some of the richer polymeter notations) may be missing; check
strudel_mini.dasfor the authoritative list of supported tokens.
8.4. Behavioural differences
Cases where a primitive with the same name behaves differently in the daslang port. Before porting a pattern that uses one of these, read the table — the output may differ even if the code looks identical.
8.4.1. ADSR defaults are tempo-aware
Divergence: daslang scales the default attack / decay / sustain / release values with the current CPS so that a default envelope feels right at any tempo. strudel.cc uses fixed-millisecond defaults.
Why: When you change tempo with strudel_set_cps mid-pattern,
you don’t want the envelope to suddenly overpower the note or shorten
to a click. The defaults are defined so that a whole-note envelope
fills one cycle at the current tempo.
How to apply:
For patterns that relied on strudel.cc’s fixed ADSR, pass explicit values:
pat |> attack(0.01) |> release(0.5).If you want the daslang behaviour in strudel.cc, multiply the attack / release by the period (1 / CPS).
See the adsr-defaults branch history for the full introduction.
8.4.2. Per-voice FX chain
Divergence: phaser, tremolo, compressor, shape,
crush, coarse, and djf are applied per voice, inside
the voice renderer, before the orbit mix. strudel.cc applies most
of these after the send-bus mix.
Why: Per-voice FX gives a cleaner sound for polyphonic patterns
(one voice’s compressor can’t duck another voice’s transient) and
integrates tightly with the VoiceFX struct, which the per-voice
synth engine already carries.
How to apply: for patterns that rely on strudel.cc’s post-bus
phaser, use room / delay bus routing (per-orbit) instead.
Per-voice combinators like jux interact with per-voice FX
differently — each transformed voice carries its own FX chain.
8.4.3. Orbit bus model
Divergence: daslang has an explicit OrbitBus per orbit
number. room sends to that orbit’s reverb; delay to that
orbit’s delay; chorus is per-voice, not per-orbit.
strudel.cc routes reverb/delay through SuperDirt differently.
How to apply: if your strudel.cc pattern mixes two orbits to
share a reverb, in daslang they need the same orbit number.
If you want independent reverbs per voice, split orbits.
8.4.4. Mini-notation parsing
Divergence: mini-notation strings are only parsed by
parse_pattern / s / n / note / seq — not by
any implicit string coercion. pat = "bd sd" is a string
literal, not a Pattern.
Why: daslang is statically typed; implicit coercion from
string to Pattern would require custom conversion at every
call site. Explicit constructors are clearer and play better with
type-dispatched combinators.
How to apply: always wrap mini-notation in s("bd sd"),
n("0 2 4"), note("c4 e4 g4"), or parse_pattern("...").
8.4.5. fast at non-integer ratios
Divergence: both engines allow fractional factors (fast(1.5)),
but the underlying hap-slicing uses floor-division in daslang’s
splitSpans helper. Edge cases where the speedup causes a hap to
straddle a cycle boundary are resolved by keeping the earlier half;
strudel.cc may keep the later half.
How to apply: for rhythms near integer factors, behaviour is
identical. For oddly fractional fast values, compare audibly
and adjust.
8.4.6. Scheduler and voice pool
Divergence: daslang has a fixed voice-pool size (set at
Scheduler init); when exceeded, the oldest voice is stolen.
strudel.cc allocates voices dynamically per hap.
How to apply: very dense polyphony may drop notes in daslang.
Raise the pool size at Scheduler construction or thin the
pattern.
8.5. Naming map (quick reference)
For porting at speed: the daslang name is the same as strudel.cc for ~95% of primitives. When it differs:
strudel.cc |
daslang |
Notes |
|---|---|---|
|
|
identical |
|
|
identical |
|
|
identical; for scale-degree use |
|
|
same name; pipe syntax preferred but method-chain also works |
|
|
daslang expects a typed fn; lambda literal is normal |
|
|
both aliases exist |
|
|
top-level function, not a method |
|
not available |
use |
|
|
mini-notation Euclid form not parsed |
For everything else, assume the name is identical. Use the MCP
list_module_api tool on strudel_pattern /
strudel_synth / strudel_scales to confirm.
See also
Strudel (Live Coding) — generated reference for every strudel symbol.
daStrudel (Live-Coding) Tutorials — 15-tutorial numbered series covering patterns, mini-notation, effects, synthesis, samples, MIDI, and live-reload.
STRUDEL-01 — Hello Pattern — start here for a tour.