Generate Euclidean rhythms and analyze them with standard geometric measures, in pure Python with zero dependencies.
Euclidean rhythms distribute k onsets as evenly as possible over n time steps using
Bjorklund's algorithm - the same Euclidean GCD logic that underlies many traditional
musical patterns worldwide.
The son clave (3 onsets, 8 steps): x . . x . . x .
The bossa nova clave (5 onsets, 8 steps): x . x x . x x .
pip install euclidean-rhythmfrom euclidean_rhythm import (
complement,
euclidean,
evenness,
inter_onset_intervals,
ioi_histogram,
is_euclidean,
necklace,
offbeatness,
onset_positions,
pattern_from_onsets,
rhythmic_oddity,
rotate,
syncopation,
)
# Generate rhythms
son = euclidean(pulses=3, steps=8)
# [1, 0, 0, 1, 0, 0, 1, 0]
bossa = euclidean(pulses=5, steps=8)
# [1, 0, 1, 1, 0, 1, 1, 0]
# Rotate
rotate(son, steps=2)
# [0, 1, 0, 0, 1, 0, 1, 0]
# Canonical necklace form (rotation-invariant)
necklace(son) == necklace(rotate(son, steps=3))
# True
# Recognize Euclidean rhythms (any rotation of E(k, n))
is_euclidean(son)
# True
is_euclidean(rotate(son, steps=2))
# True
is_euclidean([1, 1, 1, 0, 0, 0, 0, 0]) # clustered, not even
# False
# Rhythmic complement (swap onsets and rests)
complement(son)
# [0, 1, 1, 0, 1, 1, 0, 1]
# Evenness (1.0 = maximally even)
evenness(euclidean(pulses=4, steps=8))
# 1.0
# Keith syncopation (0 = no syncopation)
syncopation(euclidean(pulses=4, steps=8))
# 0
# Pressing rhythmic oddity
rhythmic_oddity(son)
# True
# Off-beat onset count (Toussaint offbeatness)
offbeatness(son)
# 1 -- onset at position 3 is off-beat in n=8; 0 and 6 are on-beat
# Inter-onset intervals (gaps in pulses, wrapping)
inter_onset_intervals(son)
# [3, 3, 2] -- sums to 8
# Histogram of inter-onset intervals
ioi_histogram(son)
# {3: 2, 2: 1}
# Convert between 0/1 pattern and onset-position list
onset_positions(son)
# [0, 3, 6]
pattern_from_onsets(positions=[0, 3, 6], steps=8)
# [1, 0, 0, 1, 0, 0, 1, 0]euclidean-rhythm 3 8
# x..x..x.
euclidean-rhythm 5 8
# x.xx.xx.All parameters are keyword-only.
| Function | Description |
|---|---|
euclidean(*, pulses, steps) |
Generate Euclidean rhythm (Bjorklund's algorithm) |
rotate(rhythm, *, steps) |
Rotate left by steps (mod len) |
necklace(rhythm) |
Lexicographically minimal rotation (canonical form) |
complement(rhythm) |
Swap onsets and rests (1 <-> 0), preserving length |
is_euclidean(rhythm) |
True iff the rhythm is a rotation of E(k, n) |
evenness(rhythm) |
Toussaint geometric evenness in (0, 1] |
syncopation(rhythm) |
Keith (1991) syncopation count |
rhythmic_oddity(rhythm) |
Pressing (1983) rhythmic oddity property |
offbeatness(rhythm) |
Count of onsets on off-beat positions (gcd-coprime to n) |
inter_onset_intervals(rhythm) |
Gaps in pulses between consecutive onsets, wrapping |
ioi_histogram(rhythm) |
Histogram of inter-onset interval lengths |
onset_positions(rhythm) |
Indices of onsets in a 0/1 pattern |
pattern_from_onsets(*, positions, steps) |
Build 0/1 pattern from onset indices |
Evenness (Toussaint 2005): Place onsets on a unit circle; sum all pairwise chord lengths; normalize by the maximum (equally spaced onsets). Score 1.0 means maximally even.
Syncopation (Keith 1991): Metric weight of position i is n for the downbeat
(i=0) and the largest power of 2 dividing i for i>0. A syncopation occurs when
an onset at a weak beat is followed by a rest at a stronger beat; the score accumulates
the weight difference.
Rhythmic oddity (Pressing 1983): True if no two onsets are diametrically opposite on the rhythm circle (no pair partitions the cycle into two equal halves).
Offbeatness (Toussaint): For a cycle of n pulses, position p is off-beat iff gcd(p, n) == 1 -- equivalently, p is not covered by any regular subdivision of the cycle (union of {k*n/d} for proper divisors d of n). Offbeatness is the count of onsets at such positions. Both characterizations produce identical off-beat sets, verified for n in 2..64.
Inter-onset intervals: The sequence of gaps (in pulses) between consecutive onsets around the cycle, wrapping from the last onset back to the first. Always sums to n.
Is-Euclidean: A rhythm is Euclidean if it equals some rotation of the canonical
Euclidean rhythm E(k, n) for its own onset count k and length n. Equivalently,
necklace(rhythm) == necklace(euclidean(pulses=k, steps=n)). This is a test for maximal
evenness up to rotation; the all-rest (k=0) and all-onset (k=n) rhythms are trivially
Euclidean.
Complement: Swap every onset and rest (1 <-> 0), preserving length. The complement of a rhythm with k onsets over n steps has n - k onsets, and applying it twice returns the original (an involution). The complement of E(k, n) is generally not E(n - k, n), since swapping onsets and rests does not in general preserve maximal evenness.
- Bjorklund, E. (2003). The theory of rep-rate pattern generation in the SNS timing system.
- Toussaint, G. (2005). The Euclidean algorithm generates traditional musical rhythms. BRIDGES.
- Keith, M. (1991). From Polychords to Polya: Adventures in Musical Combinatorics.
- Pressing, J. (1983). Cognitive isomorphisms between pitch and rhythm in world musics. Studies in Music.
MIT. Copyright (c) 2026 Amaar Chughtai.
