7.10.4. STRUDEL-04 — Time Manipulation
So far every Pattern played at one cycle per cycle, in forward order.
This tutorial introduces the time algebra: four functions that take
a Pattern and return a new Pattern by rewriting the query timeline.
fast and slow change density, rev mirrors per-cycle, and
hurry couples speed with pitch. They all compose freely, and they
work on any Pattern — mini-notation, pure, or signals.
The mental model: a combinator wraps a Pattern with a function that
rewrites the query span on the way in and rewrites the result
haps on the way out. fast(2) queries the inner pattern with
span * 2, then divides every returned hap’s timestamps by 2.
slow(N) is exactly fast(1/N). rev mirrors the span within
each cycle and mirrors the haps back. That is the entire framework.
7.10.4.1. Part A: fast(N)
fast(N) repeats the pattern N times per cycle:
let pat <- s("c4 e4 g4 c5") |> fast(2.0lf)
play(pat, 4.0)
The four-note arpeggio plays twice per cycle. N is a double,
so non-integer values work — fast(1.5lf) gives 3 repetitions every
2 cycles, useful for polyrhythms (covered in tutorial 05).
7.10.4.2. Part B: slow(N)
slow(N) stretches one pass of the pattern over N cycles. It is
defined as fast(1.0lf / n):
let pat <- s("bd sd hh cp") |> slow(2.0lf)
play(pat, 6.0)
The four hits now span two cycles instead of one. Use this to stretch melodies, make pad-style sustains, or build a slow LFO out of a signal pattern.
7.10.4.3. Part C: rev
rev reverses event positions within each cycle:
let pat <- note("c4 e4 g4 c5", "sine") |> sustain(0.4) |> rev
play(pat, 4.0)
The arpeggio plays backward as c5 g4 e4 c4. This is per-cycle
mirroring — not a global reverse. Each cycle stands alone, so
rev |> rev is the identity. Combine it with jux to get instant
stereo widening (tutorial 06 covers combinators).
rev is callable bare or with parentheses: pat |> rev and
pat |> rev() are equivalent.
7.10.4.4. Part D: hurry(N)
hurry(N) speeds time up by N and multiplies the per-event
playback speed by N. For sample-based sounds (drum hits,
field-recordings), speed scales playback rate, which means pitch goes
up by log2(N) octaves:
let pat <- s("c3 e3 g3 c4") |> hurry(2.0lf)
play(pat, 4.0)
The pattern plays twice as fast and an octave higher. This is a single
function call away from the classic chipmunk effect. For synth voices
(sine, sawtooth, supersaw), hurry and fast differ
only in the speed field — pitch comes from note, not speed.
7.10.4.5. Part E: Composition
The four functions all return Patterns, so they compose with the pipe operator like any other transform:
let pat <- note("c4 e4 g4 b4", "sine")
|> sustain(0.4)
|> rev
|> slow(2.0lf)
play(pat, 6.0)
Order matters — rev |> slow(2) reverses then stretches; slow(2) |>
rev stretches then reverses (and the two produce different rhythms in
general because rev operates per-cycle).
7.10.4.6. A note on early and late
You may have seen early(N) / late(N) in other Tidal/Strudel
documentation — they shift the pattern earlier or later by N cycles.
In this build they exist but are private to the strudel module
(used internally by off, the canon-style overlay combinator). To
shift a pattern, the public route is to chain slow and cat, or
to wait for them to be exported in a future release.
7.10.4.7. Where next
Tutorial 05 covers Euclidean rhythms — the euclid(pat, k, n)
combinator that distributes k events evenly across n steps and
produces traditional drum patterns from many cultures with a single
line.
See also
Full source: tutorials/daStrudel/daStrudel_04_time_manipulation.das
Previous tutorial: STRUDEL-03 — Mini-Notation Advanced
Next tutorial: STRUDEL-05 — Euclidean Rhythms
Related: Lambdas and Closures — Patterns are lambdas, and so are the wrappers fast/slow/rev build
Related: Functions — pipe operator |> is just function call syntax