Holonomy-based chord progression analyzer โ proves harmonic movement = cycle consistency
Project description
holonomy-harmony
๐ผ Chord progression analysis via holonomy โ detect modulations, modal interchange, and cycle violations in harmony.
Holonomy-harmony proves that harmonic movement = cycle consistency. A chord progression has zero holonomy when it returns to its tonal center. When it doesn't, you've detected a modulation. This is constraint theory applied to music theory: the circle of fifths is a topological space, and chord progressions trace paths through it.
Why it exists
Music theory has always had an implicit spatial structure โ the circle of fifths, the line of fifths, voice-leading spaces. But the connection between harmonic motion and topological holonomy (the "did you end up where you started?" invariant) hasn't been made explicit in a tool. This library makes that connection executable: every chord progression gets a holonomy number, and that number tells you exactly how "far from home" the harmony wandered.
The math in plain English
Holonomy measures whether a closed loop through a space returns you to the same orientation you started with. On the circle of fifths, each chord transition moves you clockwise (dominant direction) or counter-clockwise (subdominant direction). If you sum all those movements and get zero, the progression is tonally consistent โ it returned home. If the sum is non-zero, you modulated.
Winding number counts how many full rotations around the circle of fifths the progression makes. A I-IV-V-I progression winds zero times. Coltrane's Giant Steps winds multiple times due to its major-third cycles.
Stability score (0โ1) measures how "safe" a progression is: 1.0 = entirely diatonic, zero holonomy. 0.0 = highly chromatic with multiple modulations.
Quick start
pip install holonomy-harmony
from holonomy_harmony import analyze_progression, PROGRESSIONS
# Analyze the Pachelbel Canon progression in D major
symbols, tonic, mode = PROGRESSIONS["pachelbel_canon"]
result = analyze_progression(symbols, key_tonic=tonic, mode=mode)
print(f"Holonomy: {result.holonomy.holonomy}") # -5
print(f"Winding: {result.holonomy.winding_number}") # 0.0833
print(f"Type: {result.holonomy.progression_type}") # ProgressionType.MODULATION
print(f"Stability: {result.stability_score}") # 0.35
# Analyze Giant Steps โ much more adventurous
symbols, tonic, mode = PROGRESSIONS["giant_steps"]
result = analyze_progression(symbols, key_tonic=tonic, mode=mode)
print(f"Type: {result.holonomy.progression_type}") # ProgressionType.CHROMATIC
print(f"Stability: {result.stability_score}") # lower
Output:
Holonomy: -5
Winding: 0.08333333333333333
Type: ProgressionType.MODULATION
Stability: 0.35
Type: ProgressionType.CHROMATIC_MEDIANT
Stability: 0.377
API overview
High-level: analyze_progression
from holonomy_harmony import analyze_progression
result = analyze_progression(
symbols=["I", "vi", "IV", "V"], # Roman numerals
key_tonic=0, # C
mode="major", # major or minor
wrap=False, # treat as closed cycle?
)
# result.chords -> List[Chord]
# result.holonomy -> HolonomyResult
# result.graph -> TonalGraph
# result.modulations -> List[(index, description)]
# result.modal_interchanges -> List[(index, description)]
# result.stability_score -> float (0.0-1.0)
Holonomy computation
from holonomy_harmony import compute_holonomy, winding_number, classify_progression
roots = [0, 7, 9, 5, 0] # C, G, A, F, C
h = compute_holonomy(roots, wrap=True)
print(h.holonomy) # net circle-of-fifths displacement
print(h.winding_number) # full rotations
print(h.max_deviation) # furthest wander from tonic
print(h.is_consistent())# True if holonomy == 0
print(winding_number(roots)) # shortcut
print(classify_progression(roots)) # ProgressionType enum
Roman numeral parsing
from holonomy_harmony import parse_roman
chord = parse_roman("V7/vi", key_tonic=0, mode="major")
# Chord(root=10, quality='7', function='V7/vi',
# is_secondary_dominant=True, implied_key=(9, 'major'))
Tonal graph
from holonomy_harmony import TonalGraph
g = TonalGraph()
g.build_from_progression([0, 7, 9, 5, 0])
print(g) # <TonalGraph nodes=12 edges=4 total_weight=4.0>
print(g.adjacency_matrix()) # 12ร12 transition matrix
print(g.transition_probability(0, 7)) # P(G|C)
Built-in progressions
20 famous progressions included:
from holonomy_harmony import PROGRESSIONS
for name in PROGRESSIONS:
symbols, tonic, mode = PROGRESSIONS[name]
print(f"{name}: {' '.join(symbols)}")
Includes: pachelbel_canon, blues_12_bar, giant_steps, chopin_em_prelude, axis_progression, autumn_leaves, coltrane_changes, rhythm_changes, hey_jude, creep, take_five, and more.
Architecture
โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ
โ analyzer.pyโโโโ>โ cycle_checker โโโโ>โ tonal_graph โ
โ โ โ โ โ โ
โ parse_roman โ โ compute_ โ โ TonalGraph โ
โ analyze_ โ โ holonomy โ โ Transition โ
โ progression โ โ winding_ โ โ Direction โ
โ detect_ โ โ number โ โ adjacency โ
โ modulations โ โ classify_ โ โ matrix โ
โ score_ โ โ progression โ โ โ
โ stability โ โ HolonomyResultโ โ โ
โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ
Input: Roman numerals โ Chord objects โ pitch-class roots
Process: roots โ circle-of-fifths steps โ holonomy signature
Output: HolonomyResult + stability score + modulation list
Documentation
- User Guide โ Complete usage documentation
- Developer Guide โ Contributing and internals
- Examples โ Working code examples
Related repos
- spline-midi-smooth โ Spline interpolation for MIDI automation
- plato-room-musician โ PLATO rooms โ MIDI music
- tensor-midi โ INT8-saturated MIDI for neural synthesis
Requirements
- Python 3.10+
- No external dependencies (pure Python)
Install
pip install holonomy-harmony
Or from source:
git clone https://github.com/SuperInstance/holonomy-harmony.git
cd holonomy-harmony
pip install -e .
License
Apache License 2.0
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file holonomy_harmony-0.1.0.tar.gz.
File metadata
- Download URL: holonomy_harmony-0.1.0.tar.gz
- Upload date:
- Size: 19.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
84310414c9ec2a15f6a8cc4576a44a5841484eaeee6e1edb6d844eb2b2c18fc7
|
|
| MD5 |
b8f46f4d1f7be64127e154ac8171b7a4
|
|
| BLAKE2b-256 |
b6cfcbde5f92b217fb23f64d418edc777a406805e7eac03c8d51865374e35d66
|
File details
Details for the file holonomy_harmony-0.1.0-py3-none-any.whl.
File metadata
- Download URL: holonomy_harmony-0.1.0-py3-none-any.whl
- Upload date:
- Size: 14.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
800acca77b4f3a480acb01318e08739b267a2117411afeea438d68163054af96
|
|
| MD5 |
f802aadd027735ac0eabe5d34b018b2c
|
|
| BLAKE2b-256 |
a719a2e75daa7f1b34aedeca945e3cb948d0221259b96c6845bb858f2b6d9cf2
|