A comprehensive music theory library built around algorithmic approaches
Project description
Chordelia
Chordelia is a Python toolkit for music theory, composition, notation, and playback. It focuses on theory-correct results, immutable value objects, and deterministic score conversion.
Why Chordelia
- Theory-correct spellings for scales, intervals, and chord construction.
- Immutable, copy-constructor style APIs that compose cleanly.
- Sequence to Score normalization for a single canonical timeline model.
- Built-in SVG sheet rendering plus optional LilyPond backend integration.
- Optional audio and MIDI workflows layered on top of the same score model.
Installation
pip install chordelia
Optional extras:
pip install chordelia[audio]
pip install chordelia[midi]
pip install chordelia[notebook]
pip install chordelia[all]
Python requirement: 3.10+
Tested in CI: 3.10-3.13. Preview support: 3.14 (non-blocking CI signal).
Quick Feature Tour
1) Build a song form from one motif
from fractions import Fraction
from chordelia import *
scale = Scale("E4", ScaleType.HARMONIC_MINOR)
set_global_scale_context(scale)
degrees = (1, 3, 4, 5, 4, 3, 2, 1)
half = Fraction(1, 2)
a = Sequence(tuple((scale.degree(d), half) for d in degrees))
chord_hit = scale.chord_for_degree("V")
b = a.shift(2)
c = Sequence(((chord_hit, half), a.shift(4)))
song = Sequence((a, b, c, a))
score = Score.from_sequenceable(song, tempo=120, time_signature=(4, 4), key_signature="E minor")
Movement contract quick check:
with with_global_scale_context(scale):
print(Note("E4").shift(2)) # G4 (diatonic)
print(Note("E4").transpose(1)) # F4 (one semitone)
Use shift(...) for diatonic scale-step movement and transpose(...) for chromatic semitone movement.
Seeded random workflow quick check:
rng = Random(seed=202606)
scale = rng.scale()
motif = MotifVariationSequenceAlgorithm(motif_beats=2)
phrase = rng.sequence(8, algorithm=motif, scale=scale)
progression = [rng.chord(scale=scale).name for _ in range(4)]
print(len(phrase.entries))
For weighted algorithm selection, stateful motif reuse, and global-singleton randomization recipes, see Cookbook.
For Random.sequence(...), pass algorithm-specific per-call tuning values as direct keyword arguments.
The resulting Score is the canonical shared boundary for both rendering and MIDI export.
2) Compose sequential and simultaneous parts explicitly
from chordelia import ParallelSequence, Sequence
lead = Sequence((("E4", 1), ("G4", 1), ("A4", 2)))
bass = Sequence((("E3", 4),))
arrangement = ParallelSequence(
(
("lead", lead, 0),
("bass", bass, 0),
),
name="song",
)
score = Score.from_parallel_sequences(arrangement, tempo=120, time_signature=(4, 4))
Sequence remains the canonical sequential model. Use ParallelSequence when
simultaneous layering and per-child offsets are the primary intent.
3) Target immutable deep updates with named paths
updated = arrangement.replace_child_by_path("lead", lead.transpose(12))
updated_score = Score.from_sequenceable(updated)
Named child paths are dot-separated and immutable replacement returns a new composition tree.
4) Render that same song as sheet music
# Continue from block 1 in the same Python session.
SheetMusic(score, scale=scale).to_file("song.svg")
SheetMusic(score, clef="bass", scale=scale).to_file("song_bass.svg")
SheetMusic(..., clef="auto") is the default and chooses clef from the median
of unique pitches: below middle C (MIDI 60) uses bass; middle C or higher uses treble.
5) Export and play that same song via MIDI
# Continue from block 1 in the same Python session.
MidiFile(score).to_file("song.mid")
playback = MidiPlayback()
playback.play_score(score, blocking=True)
# Optional: inspect outbound MIDI messages in real time.
monitor = MidiMonitorSession(playback=playback, max_events=200).start()
# ...run playback calls...
recent_events = monitor.snapshot(limit=20)
monitor.stop()
Note: immutable composition models (Sequence, ParallelSequence) are separate
from future runtime channel controls tracked in
Interactive Live Song Channels Plan.
Documentation
Start here:
In-depth tutorials:
Guides and reference:
- Cookbook
- Notes and Intervals
- Scales and Chords
- Rhythm and Timing
- Sequences and Score
- Immutability
- API Overview
- Development Guide
Additional runnable examples: examples
Contributing
Contributions are welcome. Include tests for behavior changes and keep docs aligned with final API behavior.
License
MIT License. See LICENSE for details.
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 chordelia-0.5.0.tar.gz.
File metadata
- Download URL: chordelia-0.5.0.tar.gz
- Upload date:
- Size: 105.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
38d4fc25ef04b48ecc05d53d44f933633193ef5a8b1ba4692a7735ae0b2cd550
|
|
| MD5 |
f2fe3f5789fe2986669df36e00be75d2
|
|
| BLAKE2b-256 |
22215834d18fda5f35169ac194bca0e81b9aa83814d0cca06af797e009a69756
|
Provenance
The following attestation bundles were made for chordelia-0.5.0.tar.gz:
Publisher:
python-publish.yml on lzulauf/chordelia
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
chordelia-0.5.0.tar.gz -
Subject digest:
38d4fc25ef04b48ecc05d53d44f933633193ef5a8b1ba4692a7735ae0b2cd550 - Sigstore transparency entry: 1873266183
- Sigstore integration time:
-
Permalink:
lzulauf/chordelia@c5bd4315dc79f7dcc8702fe1c5473a46dbfad862 -
Branch / Tag:
refs/tags/v0.5.0 - Owner: https://github.com/lzulauf
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@c5bd4315dc79f7dcc8702fe1c5473a46dbfad862 -
Trigger Event:
release
-
Statement type:
File details
Details for the file chordelia-0.5.0-py3-none-any.whl.
File metadata
- Download URL: chordelia-0.5.0-py3-none-any.whl
- Upload date:
- Size: 117.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9fb4e1a5d5568b4b26c216923b8ab6d34e0f98f8d9116f8efba9afd2ca346af0
|
|
| MD5 |
549f0d11762da228699638ed5c0c90cf
|
|
| BLAKE2b-256 |
0bf3a46798c33ee1fdf25ba966729ef48a69fddf14ea34a4b02e1ef3b7a7a9dc
|
Provenance
The following attestation bundles were made for chordelia-0.5.0-py3-none-any.whl:
Publisher:
python-publish.yml on lzulauf/chordelia
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
chordelia-0.5.0-py3-none-any.whl -
Subject digest:
9fb4e1a5d5568b4b26c216923b8ab6d34e0f98f8d9116f8efba9afd2ca346af0 - Sigstore transparency entry: 1873266299
- Sigstore integration time:
-
Permalink:
lzulauf/chordelia@c5bd4315dc79f7dcc8702fe1c5473a46dbfad862 -
Branch / Tag:
refs/tags/v0.5.0 - Owner: https://github.com/lzulauf
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@c5bd4315dc79f7dcc8702fe1c5473a46dbfad862 -
Trigger Event:
release
-
Statement type: