Contents

Rhythm & Patterns

The clock

Everything in Akkado syncs to a global clock. The trigger function creates pulses:

// Trigger 4 times per beat (16th notes)
trigger(4)

Use triggers to control envelopes:

// Kick on quarter notes
sine(55) * ar(trigger(1), 0.01, 0.2) |> out(@)

Building a basic beat

Combine different trigger rates for drum patterns:

// Simple kick and hi-hat
kick = sine(55) * ar(trigger(1), 0.005, 0.15)
hat = noise() |> hp(@, 8000) * ar(trigger(4), 0.001, 0.03) * 0.3

kick + hat |> out(@)

Euclidean rhythms

The euclid function distributes hits evenly across a number of steps. The fourth argument dur (default 4) sets the pattern span in cycles, so euclid(3, 8) spans 1 bar at 4/4 by default:

// Tresillo (3 hits over 8 steps, spread across 1 bar)
sine(55) * ar(euclid(3, 8), 0.01, 0.15) |> out(@)

Classic Euclidean patterns:

  • euclid(3, 8) - Cuban tresillo
  • euclid(5, 8) - West African bell pattern
  • euclid(7, 16) - Brazilian samba

euclid is a signal-domain trigger generator. To slow or speed it, change dur directly — .fast() and .slow() are pattern transforms and don’t apply here. For pattern-style transforms over a Euclidean rhythm, use mini-notation Euclidean syntax instead: n"c4(3,8)".slow(2).

// Layered Euclidean rhythms
kick = sine(55) * ar(euclid(4, 16), 0.005, 0.15)
perc = noise()
    |> bp(@, 2000, 4)
    * ar(euclid(5, 16), 0.001, 0.05) * 0.4

kick + perc |> out(@)

Rotation

Rotate patterns to shift the accent:

// Rotated pattern - different feel, same hits
sine(55) * ar(euclid(3, 8, 1), 0.01, 0.15) |> out(@)

Step sequencing

Use n"…" mini-notation for melodic patterns:

// 4-note melodic pattern
n"c3 e3 g3 c4" |> ((f) ->
    saw(f) * ar(trigger(4)) |> lp(@, 800)
) |> out(@)

Combining rhythm and melody

A complete sequence:

// Bass line with rhythm
n"c2 g2 d#2 a#1" |> ((f) ->
    saw(f)
        |> moog(@, 400 + ar(trigger(2)) * 800, 2)
        * ar(trigger(2), 0.01, 0.2)
) |> out(@)

LFO for movement

Add motion with LFOs:

// Rhythmic with filter movement
saw(110)
    |> lp(@, 500 + lfo(0.25) * 1000)
    * ar(trigger(4))
    |> out(@)

A complete drum pattern

// Kick drum
kick = sine(55 * (1 + ar(trigger(1), 0.001, 0.02) * 2))
    * ar(trigger(1), 0.005, 0.2)

// Snare
snare = noise() |> bp(@, 1000, 2)
    * ar(euclid(2, 8, 4), 0.001, 0.1) * 0.5

// Hi-hat
hat = noise() |> hp(@, 8000)
    * ar(trigger(4), 0.001, 0.03) * 0.2

// Ride
ride = noise() |> bp(@, 6000, 8)
    * ar(euclid(3, 8), 0.001, 0.1) * 0.15

kick + snare + hat + ride |> out(@)

Polyrhythms

Layer two rhythms that don’t divide evenly into each other — 3 against 4 is the textbook example:

// 3 against 4
bass = saw(55) * ar(euclid(3, 12), 0.01, 0.15) |> lp(@, 400)
perc = noise()
    |> hp(@, 4000)
    * ar(euclid(4, 12), 0.001, 0.05) * 0.3

bass + perc |> out(@)

Mini-notation patterns

For melodic sequences, use mini-notation:

// Melodic pattern
n"c3 e3 g3 c4" |> ((f) ->
    saw(f) |> lp(@, 800) * ar(trigger(4))
) |> out(@)

Conditional triggers

So far every gate has come from a pattern function (trigger, euclid, pat). You can also build gates from conditionals: comparisons and logic operators that work sample-by-sample.

Threshold gates

Compare a continuous signal against a value to produce a 0.0 / 1.0 gate:

// Open the kick only on the louder half of an LFO
loud = lfo(0.5) > 0
sine(55) * ar(loud, 0.005, 0.15) |> out(@)

The > operator outputs 1.0 whenever its left-hand side is greater than its right-hand side, and 0.0 otherwise. Anything you can use as a trigger source you can build this way.

Selecting between two voices

select(cond, a, b) is a sample-rate ternary: it outputs a whenever cond > 0, otherwise b:

// Alternate timbre on every other beat
flip = n"1 0 1 0"
voice = select(flip, saw(110), sqr(110))
voice * ar(trigger(2), 0.005, 0.2) |> out(@)

There’s no ?: ternary in Akkado. select is the canonical form.

Combining gates with && and ||

Logical AND (&&) fires only when both inputs are truthy. Logical OR (||) fires when at least one is truthy.

// OR: layer two patterns into a single gate
g1 = n"1 0 0 0"
g2 = n"0 0 1 0"
combined = g1 || g2  // "1 0 1 0"
sine(55) * ar(combined, 0.005, 0.15) |> out(@)
// AND: accent only when a beat lines up with a slow LFO peak
loud = lfo(0.5) > 0.5
hit  = trigger(4)
accent = loud && hit
noise() * ar(accent, 0.001, 0.05) |> out(@)

The prefix ! operator inverts a gate, useful for “play during the rests”:

// A pad that fills the space between drum hits
gate = trigger(4)
sustain = !gate
sine(220) * sustain * 0.2 |> out(@)

For the full operator precedence table and the complete list of comparison/logic builtins, see Operators and Conditionals & Logic.

Next steps

  • Mini-Notation — the full pattern syntax.
  • Pattern Modulation — patterns as values: bend(notes, v"<0 0.5 -0.5>"), custom e.cutoff properties, scalar arithmetic.
  • Effects — reverbs and delays.
  • Dynamics — compression, gating, limiting.