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

5. Gamelan: Interlocking Patterns and Cyclic Time

In the gamelan traditions of Bali and Java, time is not a line — it is a circle (Tenzer 2000). A gong stroke marks a point on that circle, and when the cycle completes, the gong returns. Within the circle, smaller cycles nest inside larger ones: a kenong divides the gong cycle in half, a ketuk divides the kenong, and the rapid interlocking patterns of the gangsa metallophones fill every remaining space. The result is a temporal architecture of extraordinary depth, built entirely from the nesting and interlocking of simple periodic patterns.

Poly’s two most distinctive features — the Kotekan parameter and the ability to run lanes at independent cycle lengths — were designed with gamelan explicitly in mind.

Kotekan is the Balinese technique of rhythmic interlocking. Two musicians — called polos and sangsih — each play a pattern that is incomplete on its own. (Vitale 1990) Polos plays certain beats. Sangsih plays the complementary beats — exactly the ones polos leaves silent. Together they produce a single continuous melody at a speed no individual player could sustain.

The principle is mathematical: if polos plays hits at positions 7 within an 8-step cycle, sangsih plays at positions 8. The two patterns are complementary — their union covers every beat. Strict complementation like this is the textbook idealization; in practice the two players also strike together at structural tones — cadence points, phrase joins, and angsel breaks — and a pair that never overlaps sounds mechanical (see theory-gamelan Rule 4). Neither part makes musical sense alone. Together they are seamless.

E(5,8)

Consider E(5,8): five hits across eight steps. The complement of this pattern fills the remaining three positions — E(3,8). When polos plays E(5,8) and sangsih plays E(3,8), every step in the cycle is covered by exactly one player.

E(3,8)

This is precisely what Poly’s Kotekan parameter automates. When you set Lane 2’s Kotekan to L1, the engine examines Lane 1’s Euclidean pattern and generates its complement for Lane 2. You do not program the sangsih part — it is derived. Change Lane 1’s hits or rotation, and Lane 2’s complement updates automatically.

bool useKotekan = cfg.kotekanSourceLane >= 0 && cfg.kotekanSourceLane < state.activeLaneCount &&
                  cfg.kotekanSourceLane != lane;
if (useKotekan) {
    const auto& src = state.lanes[cfg.kotekanSourceLane];
    if (src.kotekanSourceLane == lane)
        useKotekan = false;
}
if (useKotekan) {
    const auto& src = state.lanes[cfg.kotekanSourceLane];
    std::array<bool, kMaxSteps> srcPattern{};
    euclidean(src.hitCount, src.cycle.steps, src.rotation, srcPattern);
    // M002 S01 (EC06). The mode picks which index of the source is
    // complemented. NyogCag reads the source step for step -- the
    // pre-M002 behaviour, byte-identical. Telu and Empat read it modulo
    // a cell length, so the interlock repeats on a three- or four-pulse
    // cell instead of tracking the source across the whole cycle.
    int cell = 0;
    if (cfg.kotekanMode == KotekanMode::Telu)
        cell = 3;
    else if (cfg.kotekanMode == KotekanMode::Empat)
        cell = 4;
    int complementHits = 0;
    for (int s = 0; s < cfg.cycle.steps && s < src.cycle.steps; ++s) {
        const int srcStep = cell > 0 ? (s % cell) : s;
        pattern[s] = !srcPattern[srcStep];
        if (pattern[s])
            ++complementHits;
    }
    for (int s = src.cycle.steps; s < cfg.cycle.steps; ++s) {
        pattern[s] = true;
        ++complementHits;
    }
    // M002 S01 task 6. theory-gamelan Rule 1: "the composite must be
    // continuous … gaps in the composite are errors". A cell mode reads
    // the source modulo the cell length, so it can leave a pulse that
    // neither part strikes — Empat did, at pulses 4 and 7 of the
    // Balinese Kotekan patch. Real kotekan figures are composed as a
    // pair and are continuous by construction; a periodic complement of
    // an unrelated Euclidean source is not. Fill those pulses so the
    // composite is continuous whatever the mode. NyogCag is already the
    // exact complement and has no gaps to fill.
    if (cell > 0) {
        for (int s = 0; s < cfg.cycle.steps && s < src.cycle.steps; ++s) {
            if (!srcPattern[s] && !pattern[s]) {
                pattern[s] = true;
                ++complementHits;
            }
        }
    }
    // MEM095 / M070 "Kotekan Interlock": a macro-saturated source
    // (hitCount == cycle.steps, reachable dynamically via the complexity/
    // density macros) makes srcPattern all-true, so !srcPattern is
    // all-false and the sangsih complement goes entirely silent — the
    // interlocking pair collapses to a single line. When the derived
    // complement is fully silent, fall back to the lane's own Euclidean
    // pattern so the complement keeps at least one interlocking hit. This
    // only fires when complementHits == 0, so every non-saturated pattern
    // stays byte-identical (determinism golden tests unaffected).
    if (complementHits == 0)
        euclidean(cfg.hitCount, cfg.cycle.steps, cfg.rotation, pattern);
    // M002 S01 (EC06). Structural overlap: the points at which both
    // parts strike, which Rule 4 says mark cadences, phrase joins and
    // angsel figures. Forced on rather than toggled -- the point is a
    // shared strike, so the step must sound in both parts whatever the
    // complement said. Overlap 0 leaves the strict complement
    // untouched, which is why every pre-M002 preset is byte-identical.
    if (cfg.kotekanOverlap > 0 && cfg.cycle.steps > 0) {
        const int mid = cfg.cycle.steps / 2;
        const int phrase = cfg.phraseLength > 0.0f ? 1 : mid;
        const int points[3] = {0, phrase, mid};
        for (int i = 0; i < 3 && i < cfg.kotekanOverlap; ++i) {
            const int step = points[i];
            if (step >= 0 && step < cfg.cycle.steps)
                pattern[step] = srcPattern[cell > 0 ? (step % cell) : step] ? true : pattern[step];
        }
    }
Complement generation — sangsih pattern derived from polos
Balinese Kotekan InterlockingBalinese Kotekan
Lane Role Steps Hits Rotation Subdivision Note Velocity Ghost Kotekan Interlock Overlap
1 Pokok melody 8 4 0 1/4 60 85 0 off 0
2 Polos 8 5 0 1/16 72 90 40 off 0
3 Sangsih 8 5 0 1/16 74 85 40 L2 empat 1
4 Jegogan bass 8 2 0 1/4 48 100 0 off 0
5 Reyong accent 16 5 3 1/16 67 75 50 off 0
Balinese KotekanBalinese kotekan interlocking — polos and sangsih with colotomic bass punctuation

Lane 2’s hit count and pattern content are overridden by the Kotekan L1 setting — the engine generates whatever complement Lane 1 requires. Lanes 3 and 4 provide bass punctuation and a reyong-style accent pattern that weaves around the interlocking pair.

Where Balinese kotekan operates at the level of individual beats, Javanese gamelan organises time at a much larger scale through colotomic structure.18 The word comes from the Greek kolon (member) — it describes how a long temporal cycle is divided into nested, hierarchical parts by different instruments.

In a Javanese gendhing (composition), the structure might work like this:

  • The gong ageng (large gong) strikes once every 64 beats, marking the largest cycle.
  • The kenong divides that cycle into four, striking every 16 beats.
  • The kempul subdivides further, every 8 beats.
  • The ketuk plays every 4 beats within that subdivision.

No individual instrument plays a complex pattern. Each plays an extremely simple one — a single hit at a regular interval. The complexity emerges from the nesting. When the gong strikes, it coincides with the kenong, the kempul, and the ketuk. That convergence point has enormous structural weight. Between gong strokes, the listener hears only the smaller cycles, creating a sense of gradual building toward the next convergence.

In Poly, you model colotomic structure by setting lanes to different step counts that are powers of two (or other integer multiples). A lane with 4 steps plays four times for every one time a lane with 16 steps completes its cycle. The convergence points — where all lanes hit simultaneously — become the deep structural markers of the groove. Calling them gong strokes is this guide’s shorthand: in the gamelan the gong marks the completion of a fixed nested hierarchy, not the coincidence of lanes whose cycle lengths are independent.

Javanese Colotomic NestingJavanese Colotomic
Lane Role Steps Hits Rotation Subdivision Note Velocity Ghost
1 Ketuk (fast) 4 1 0 1/4 76 70 0
2 Kempul 8 1 0 1/4 60 85 0
3 Kenong 16 1 0 1/4 55 95 0
4 Gong ageng 32 1 0 1/4 48 110 0
Javanese ColotomicJavanese colotomic nesting — ketuk, kempul, kenong, and gong at 4:8:16:32 cycle ratios

Each lane plays exactly one hit per cycle, but the cycles are nested 4:8:16:32. The ketuk strikes every beat. The kempul strikes every other ketuk. The kenong every fourth. The gong every eighth. The hierarchy is audible immediately — each deeper gong carries more weight because it coincides with all the shallower cycles.

The most powerful gamelan-inspired patches in Poly combine both principles. Use the kotekan lanes (1-2) for the rapid interlocking surface, and add colotomic lanes (3-4) for structural depth. The kotekan pair fills every beat with detail. The gong cycle punctuates from below with widely spaced markers. The listener’s attention oscillates between the micro-level interlock and the macro-level structure — exactly as it does in a live gamelan performance.

Western music typically treats time as directional — a piece moves from beginning to end, through development and resolution. Gamelan treats time as cyclical — the gong marks a return to the beginning, not an arrival at the end. Each cycle may be ornamented differently, but the underlying structure repeats.

Poly’s engine is inherently cyclical. Each lane loops its Euclidean pattern indefinitely. There is no “verse” or “chorus” unless you impose one through phrase gating. For gamelan-inspired patches, this default behaviour is exactly right. Set the lanes, start the transport, and let the cycles turn. The convergence points will come and go with the inevitability of tides, and the interlocking surface will shimmer over them without ever quite repeating, because the interaction of independent cycle lengths guarantees perpetual variation within a stable frame.

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