Skip to main content

euclidean-rhythm

euclidean-rhythm logo

Generate Euclidean rhythms and analyze them with standard geometric measures, in pure Python with zero dependencies.

What are Euclidean rhythms?

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 .

Install

pip install euclidean-rhythm

Quick start

from 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]

CLI

euclidean-rhythm 3 8
# x..x..x.

euclidean-rhythm 5 8
# x.xx.xx.

API

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

Measures defined

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.

References

  • 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.

License

MIT. Copyright (c) 2026 Amaar Chughtai.

Metadata

Release files for euclidean-rhythm 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for euclidean-rhythm 0.3.0
File Size Uploaded
euclidean_rhythm-0.3.0.tar.gz 938.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for euclidean-rhythm 0.3.0
File Interpreter ABI Platform
euclidean_rhythm-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 953.3 kB

Release files / euclidean_rhythm-0.3.0.tar.gz

Download URL euclidean_rhythm-0.3.0.tar.gz
Size 938.7 kB
Tags Source
SHA-256 checksum
How to use checksums
152cde15e42b9f7de052a3cc8fe3ebe2562486aa1ee81763f0de967e54f66a75
BLAKE2b-256 checksum
How to use checksums
d69fd0764376328c6cdbe5b9ac1b9d50e677a93d4f0b87e6293bca9be112925b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.3

Release files / euclidean_rhythm-0.3.0-py3-none-any.whl

Download URL euclidean_rhythm-0.3.0-py3-none-any.whl
Size 14.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d77fa4dc5c2fb972f7d9a2759ec84f2e40a525792d1ce73293ecaaf82a239e4b
BLAKE2b-256 checksum
How to use checksums
b02aa634b02219f07e101490cf45984813b9ee6914eabf61607c04131829c602
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.3

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 release files

0.2.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page