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