Skip to content
🚧 Under active construction — content being developed and verified.

8. Minimalism: Phase, Drift, and Gradual Process

When two identical patterns move at slightly different rates, the interference between them generates far more complexity than either pattern contains alone (Cohn 1992). Steve Reich called it “music as a gradual process.” Poly calls it the Drift parameter.

Reich framed his own discovery as arriving at something West African and Indonesian musicians already knew, and that framing has carried into most writing about minimalism since. It is worth holding loosely: Agawu (Agawu 2003) questions who gets to describe African music and on whose terms, which is the prior question to whether the comparison holds. Scherzinger 2010 takes up the comparison itself and is more critical of it than Reich was. West African ensembles stack fixed independent cycles; gamelan nests fixed cycles hierarchically. Neither drifts deliberately, and neither is doing what Piano Phase does — the resemblance is in the resulting texture, not in the technique.

Reich uses three distinct techniques across three works, and it matters which is which. In Piano Phase (1967) — and its companion Violin Phase the same year — two performers play the same twelve-note figure in unison; one then accelerates almost imperceptibly until they are exactly one sixteenth ahead, and they lock in there before the process repeats. That continuous, sliding shift through every phase relationship is Reich’s phase-shifting technique in its pure form35. Drumming (1971) is a different process: it holds a single twelve-beat pattern fixed and builds it up beat by beat and then reduces it back, an exhaustive exploration of one pattern’s construction and reduction rather than of its rotational space34. Clapping Music (1972) discretises the Piano Phase idea — instead of sliding, one performer jumps forward by exactly one position every twelve bars, then holds.

The core pattern of Clapping Music is x x x . x x . x . x x . — eight claps distributed across twelve pulses in the inter-onset gap sequence 1-1-2-1-2-2-1-2. One performer holds steady while the other shifts by one position after every twelve bars. Twelve shifts later, they are back in unison.

Reich’s pattern is close to but not E(8,12). The Euclidean distribution of eight onsets across twelve pulses is x . x x . x x . x x . x (gap sequence 2-1-2-1-2-1-2-1) — a strict alternation of 1s and 2s that no arrangement of Bjorklund can pull out of order. Reich’s version uses the same gap-value palette (1s and 2s) but breaks the alternation at the opening with three consecutive claps (positions 0, 1, 2) — a run that no E(k,n) family with n=12 produces at any rotation. That opening cluster is a small but structural difference and it is what makes Reich’s pattern feel authored rather than generated.

E(5,12)

E(5,12) is a sparser variant suitable for demonstrating the phasing effect in Poly. With five onsets across twelve positions, the pattern is open enough that each rotational phase produces an audibly distinct composite rhythm.

Poly’s Drift parameter rotates a lane’s pattern by a specified number of steps per bar. Set two lanes to identical step counts and hit patterns, leave one with Drift at 0, and give the other a small positive value. The second lane’s pattern slowly rotates against the first, passing through every phase relationship.

At Drift = +0.25 steps/bar, the pattern completes one full rotation every steps / 0.25 bars. For a 12-step pattern, that is 48 bars — roughly two minutes at 120 BPM. At Drift = +1.0, the full rotation takes only 12 bars. The slower the drift, the more time you spend in each phase relationship, and the closer the effect gets to the continuous phase-shifting Reich set out in Piano Phase (1967)35 — not the additive construction of Drumming.

Reich Phasing SetupReich Phase Process
Lane Role Steps Hits Rotation Subdivision Drift Velocity
1 Fixed pattern 12 5 0 1/8 0 90
2 Drifting copy 12 5 0 1/8 +0.25 85
3 Low anchor 4 4 0 1/4 0 70
Reich Phase ProcessAccelerated phase-shifting preview — all six phases in ~15 seconds

Lane 3 provides a steady quarter-note anchor so you can hear the phasing against a fixed reference. Without it, the composite rhythm drifts as a whole and the phasing effect is harder to perceive.

Terry Riley’s In C (1964) takes a different approach: fifty-three short melodic phrases, performed by any number of players who move through them at their own pace (Potter 2000). The texture at any moment depends on which phrases are active and how they overlap.

Poly’s phrase gating models this layered-entry structure. Each lane can have its own phrase Length, Gap, and Offset. Set five lanes to different Euclidean patterns with staggered Offsets, and voices enter and exit the texture at different points in the cycle — the same gradual accumulation and thinning that defines In C.

Riley-Inspired Layered StructureRiley Layered Entry
Lane Role Steps Hits Subdivision Offset Length Gap Velocity
1 Foundation 8 5 1/8 0 0 0 95
2 Voice A 12 7 1/8 4 16 8 80
3 Voice B 10 6 1/8 12 12 12 75
4 Voice C 7 4 1/8 20 8 16 70
5 Voice D 9 3 1/4 32 24 8 65
Riley Layered EntryStaggered voice entries with phrase gating — foundation plus four gated layers

Lane 1 runs continuously as the foundation. Lanes 2 through 5 enter at different Offsets, play for their phrase Length, rest for the Gap, and repeat. The result is a slowly evolving texture where the number of active voices is always changing — sometimes sparse, sometimes dense, never quite the same twice.

Philip Glass’s signature technique is additive rhythm: a short cell that gradually grows by one note, then contracts. A pattern might progress from 1-2, 1-2, 1-2 to 1-2-3, 1-2-3 to 1-2-3-4, 1-2-3-4 and back. The listener perceives the cell expanding and contracting, breathing.

Poly’s Complexity and Density macros offer an analogous process. Sweeping either macro changes each lane’s effective hit count by units — onsets are added to or removed from the Euclidean pattern one at a time — so the pattern breathes, growing denser then thinning, exactly as an additive cell grows and contracts. The change is deterministic: the same transport position always yields the same hit count, which is what makes it an additive process rather than noise (theory-minimalism Rule 6: approximate additive process with Complexity/Density hit-count change, unit by unit).

This is why Mutation is deliberately not the tool for the additive effect. Process music forswears both improvisation and randomness — given the material and the rule, the piece is fixed. Mutation and probability have no role in a strict process patch (theory-minimalism Rule 8); their controlled unpredictability belongs to the conversational traditions. Sweep Complexity from 0.0 to 1.0 during a performance and you get the additive-rhythm effect across the entire ensemble simultaneously, without surrendering the determinism the idiom depends on.

Conlon Nancarrow spent decades composing for player piano because no human performer could execute his central idea: simultaneous independent tempi. In Study No. 36 (1970), four voices play at tempo ratios of 17:18:19:20 — each voice in its own temporal world, the composite rhythm impossibly dense and constantly shifting.

Poly’s Tempo Mult parameter brings Nancarrow’s concept to the polymetric engine. Each lane has an independent tempo multiplier (0.25x to 4.0x) that scales its step grid relative to the host tempo. At 2.0x, a lane plays its Euclidean pattern at double speed — hits arrive at half the PPQ spacing. At 0.5x, the pattern stretches to double length. The host tempo remains unchanged; only the lane’s internal clock speeds up or slows down.

Nancarrow-Style Independent TempiCustom: Metric Modulation
Lane Role Steps Hits Subdivision Tempo Mult Velocity
1 Anchor 4 4 1/4 1.0x 100
2 Double-time hat 8 5 1/8 2.0x 70
3 Half-time pulse 3 2 1/4 0.5x 85
4 Hemiola voice 6 4 1/8 1.5x 75
Nancarrow TempiIndependent tempo multipliers — anchor, double-time, half-time, and hemiola voices

Lane 1 anchors the groove at the host tempo. Lane 2 runs at 2.0x — its 8-step pattern cycles in half the time, creating a busy double-time texture. Lane 3 at 0.5x stretches its 3-step pattern across twice the normal duration, providing a slow-moving foundation beneath the surface activity. Lane 4 at 1.5x creates a 3:2 hemiola against the anchor — the fundamental polymetric relationship in West African and Cuban music, here produced by tempo scaling rather than step-count ratios.

The interaction between tempo multiplier and drift is particularly powerful. A lane at 1.5x tempo with a slow drift rate produces a phasing effect that operates across two dimensions simultaneously — the pattern rotates and the tempo relationship creates its own cycle of alignment and divergence.

Phrase gating intentionally stays in absolute PPQ regardless of tempo multiplier. A lane gated to play for 8 beats and rest for 4 will always gate at bar-aligned boundaries, even at 2.0x tempo. This means the structural phrasing stays locked to the song form while the internal pattern runs at its own speed — the musical equivalent of a soloist who plays double-time fills but still respects the 4-bar phrase structure.

There is an important philosophical alignment between minimalism and Poly’s engine. Reich insisted that his phasing process should be audible — the listener should be able to hear the system at work, not just its results. Poly’s determinism guarantee serves the same principle: given the same patch and transport position, the output is identical every time. The process is transparent and repeatable.

This is not the randomness of aleatoric music. It is the controlled inevitability of a system whose rules are simple but whose emergent behaviour is rich. Two identical patterns drifting apart at a quarter-step per bar will produce exactly the same sequence of composite rhythms every time you press play. The complexity is real, but it is derived, not random.

static int64_t computeDriftedCycleStep(const LaneConfig& cfg, const LaneRenderContext& ctx, int64_t absStep,
                                       double ppq) {
    int stepsInCycle = ctx.stepsInCycle;
    int64_t cycleStep = ((absStep % stepsInCycle) + stepsInCycle) % stepsInCycle;
    if (cfg.driftRate != 0.0f) {
        double barPos = ppq / kPpqPerBar;
        auto driftSteps = static_cast<int64_t>(std::floor(barPos * static_cast<double>(cfg.driftRate)));
        cycleStep = ((cycleStep + driftSteps) % stepsInCycle + stepsInCycle) % stepsInCycle;
    }
    return cycleStep;
}
Drift accumulates fractional rotation from absolute PPQ position — no state between calls

Preview audio uses CC0 and CC-BY drum samples. Every sample is credited on theCredits & Licenses page.