- Duration enum (whole through sixteenth, dotted, triplet)
- TimeSignature with string parsing (4/4, 3/4, 6/8, 12/8)
- Score class with fluent .add()/.rest() chaining
- Measure-aware MIDI export with time signature meta events
- Rhythm guide documentation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Chord.close_voicing(), open_voicing(), drop2(), drop3()
- Key.modulation_path() for pivot-chord modulation paths
- Scale.degree_name() for traditional function names
- Chord.extensions() for available 9th/11th/13th suggestions
- Tone.solfege for fixed-Do solfege syllables
- CLI identify and midi commands
- Comprehensive docs update covering all v0.9.0–v0.11.0 features
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add Envelope enum with 8 ADSR presets (piano, organ, pluck, pad, strings, bell, staccato, none)
- Add Chord.from_symbol() to parse any standard chord symbol without lookup tables
- Add Key.pivot_chords() for finding modulation pivot chords between keys
- Add Scale.parallel_modes() to show all modes sharing the same notes
- Add Tone.cents_difference() for fine pitch comparison in cents
- Add --envelope flag to CLI play command
- Extract C_INDEX constant, removing hardcoded magic number
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add Chord.symbol property for standard shorthand notation (Cmaj7, Dm, G7)
- Add Key.common_progressions() to realize all named progressions in a key
- Add CLI commands: modes, circle, progressions
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
NamedChord.acceptable_tones now uses prefer_flats based on circle-of-fifths
conventions. Cm7 shows (C, Eb, G, Bb) instead of (C, D#, G, A#).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Flat keys now display flats (Bb, Eb, Ab) instead of sharps (A#, D#, G#).
Uses the "no duplicate letter names" rule: if building a scale with
sharps produces two notes with the same letter (e.g. C and C# in C minor),
the scale is rebuilt with flat spellings instead.
- Tone.add() and Tone.from_index() accept prefer_flats parameter
- TonedScale detects flat vs sharp per-scale automatically
- F major: Bb (not A#), Eb major: Ab Bb (not G# A#), etc.
- All tests and docs updated to match
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fretboard["G"] shorthand via __getitem__
- Chord repr now shows <Chord C major> format
- Scale = TonedScale and Note = Tone aliases
- GUITAR_OVERRIDES dict with 15 curated standard chord shapes
(F barre 133211, B barre x24442, etc.)
- Bounded caches (max 1024 entries) for fingerings and possible_fingerings
- @pytest.mark.slow on 4 chart-generation tests; fast suite runs in 2s
- Highlights section moved above CLI examples on docs homepage
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fretboard.chord(), .tab(), .chart() convenience methods
- Fingering.tab() for rendering ASCII tablature
- Fingering algorithm now considers muting, fret span, root-in-bass,
and contiguous bass-side muting for idiomatic voicings
- All docs converted from code-block:: python to pycon with >>> prompts
- All doc outputs verified against actual library output
- Tests for new methods; version test no longer checks exact string
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
14 tests covering: flat tone creation, frequency matching with sharp
equivalents, all enharmonic pairs, arithmetic, intervals, exists
property, index resolution, chords built from flats, and
System.resolve_name().
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fretboard:
- Fretboard.guitar(capo=2) — capo as constructor parameter
- fretboard.capo(fret) — apply capo to any instrument
Chord:
- chord1 + chord2 — merge/layer two chords
- chord.tritone_sub() — jazz tritone substitution (transpose by 6)
Key:
- key.secondary_dominant(5) → V/V (e.g. D7 in C major)
- Key.all_keys() → all 24 major and minor keys
Progressions (14 total, up from 8):
- Pachelbel (Canon in D)
- Andalusian cadence (flamenco)
- Rhythm changes A section
- Jazz turnaround (iii-vi-ii-V)
- Dorian vamp, Mixolydian vamp
Also: py.typed marker for type checkers. 428 tests.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- full_name used 'if self.octave' which is falsy for octave 0,
so A0 displayed as "A" instead of "A0"
- pitch() used 'self.octave or 4' which defaulted octave 0 to 4,
so A0 returned 440 Hz instead of 27.5 Hz
Both now use 'is not None' checks. 404 tests.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Key.detect("C", "E", "G") → <Key C major>
Tries all major/minor keys, returns best match.
Prefers major when tied with relative minor.
Tone properties:
tone.is_natural → True for C, D, E, F, G, A, B
tone.is_sharp → True for C#, F#, etc.
tone.is_flat → True for Bb, Eb, etc.
Fretboard.INSTRUMENTS — list of all 25 preset names.
402 tests.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New features:
- Chord.from_name("Am7") — build chords from chart names
- Chord.__str__() — prints "C major" instead of raw tones
- Interval constants: Interval.PERFECT_FIFTH, MAJOR_THIRD, OCTAVE, etc.
- PROGRESSIONS dict: 8 common progressions as Roman numeral tuples
("I-V-vi-IV", "ii-V-I", "12-bar blues", etc.)
- Tone.enharmonic: C# → "Db", natural notes → None
- Key.__str__(): "C major"
Fix: docs CI now installs all dependencies (uv sync --group docs)
so autodoc can import pytheory modules. API reference pages were
blank on GitHub Pages because pytuning/scipy weren't installed.
New example: examples/explore.py — comprehensive demo of the full API.
393 tests.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Key class — the friendliest entry point for music theory:
Key("C", "major").chords → all diatonic triads
Key("C", "major").seventh_chords → all diatonic 7th chords
Key("C", "major").progression("I", "V", "vi", "IV")
Key("C", "major").relative → Key("A", "minor")
Key("C", "major").parallel → Key("C", "minor")
Note = Tone alias for discoverability.
README rewritten to showcase the full API:
tones, scales, diatonic harmony, chord analysis,
6 systems, 25 instruments, audio playback,
comprehensive feature list.
381 tests.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New features:
- Tone.interval_to(other): "perfect 5th", "major 3rd", "octave"
- Tone.midi: MIDI note number (C4=60, A4=69)
- Tone.transpose(n): alias for tone arithmetic
- Chord.transpose(n): shift all tones, preserving quality
- Chord.root: identify the root tone
- Chord.quality: identify the chord quality ("major", "minor 7th")
- Scale.transpose(n): shift to a new key
Cleanup:
- __version__ = "0.3.0"
- __all__ defined — no more ceil/floor leaking
- pyproject.toml: author, license, classifiers, project URLs
319 tests passing.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New features:
- Chord.identify(): name any chord (17 patterns — triads, 7ths, 9ths, sus, power)
- Chord.voice_leading(other): find smoothest voice motion between chords
- Chord.analyze(key): Roman numeral analysis (I, ii, V7, etc.)
- Chord.tension: score with tritone count, dominant function detection
- Tone.overtones(n): harmonic series frequencies
Also:
- Rewrite README with all current features and docs link
- Add all new features to chords guide with music theory context
- Remove logo from docs sidebar
- 296 tests passing
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Blues: major/minor pentatonic, blues scale, major blues, dominant,
minor (Dorian). The foundational scales of blues, rock, and jazz.
Gamelan: slendro (5-tone equidistant), pelog (7-tone with 3 pathet
subsets: nem, barang, lima). 12-TET approximations of Javanese
gamelan tuning with traditional tone names (ji, ro, lu, pat, mo,
nem, pi/barang).
Total systems: 6 (western, indian, arabic, japanese, blues, gamelan)
277 tests passing.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
intervals: now returns semitone counts (integers) instead of Hz
differences — octave-invariant and musically meaningful
harmony: frequency ratio simplicity model — reduces each pairwise
frequency ratio to simplest form and scores by 1/(num+denom).
Simple ratios (octave 2:1, fifth 3:2) score highest.
dissonance: Plomp-Levelt roughness with Bark-scale critical bandwidth
(Zwicker & Terhardt 1980). Models sensory roughness from interfering
fundamentals — peaks when freq difference ≈ critical bandwidth.
beat_frequencies: new property returning all pairwise beat frequencies
as sorted (tone, tone, hz) tuples
beat_pulse: returns smallest non-zero beat frequency (most perceptible)
All properties have detailed docstrings with psychoacoustic references,
perceptual ranges, and usage examples.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New systems:
- Arabic (Maqam): 10 maqamat (ajam, hijaz, nahawand, nikriz, saba, etc.)
with Arabic solfège tone names (Do, Re, Mi, Fa, Sol, La, Si)
- Japanese: 6 pentatonic scales (hirajoshi, in, yo, iwato, kumoi, insen)
and 2 heptatonic scales (ritsu, ryo)
Fretboard improvements:
- Fretboard.guitar() now accepts tuning parameter
- Built-in tunings: standard, drop d, open g, open d, open e, open a,
dadgad, half step down
- Custom tuning via tuple: Fretboard.guitar(("E4", "B3", ...))
- Fretboard.bass(five_string=True) for 5-string bass
Docs:
- Add Musical Systems guide page with all 4 systems
- Add logo to docs
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- 12 swaras: Sa, komal Re, Re, komal Ga, Ga, Ma, tivra Ma, Pa, komal Dha, Dha, komal Ni, Ni
- 10 thaats (parent scales): Bilawal, Khamaj, Kafi, Asavari, Bhairavi,
Kalyan, Bhairav, Poorvi, Marwa, Todi
- Extends generate_scale to accept direct interval patterns
- Sa maps to C's pitch position (Sa4 = 261.63 Hz)
- 17 new tests for Indian system
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Make play module import optional in __init__.py (PortAudio may not
be installed in CI environments)
- Skip wave generation and synth tests when PortAudio unavailable
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Tone:
- Add + operator for semitone addition (C4 + 7 → G4)
- Add - operator for subtraction and interval measurement (G4 - C4 → 7)
- Add <, <=, >, >= comparison by pitch frequency
- Add str() support (str(tone) → "C4")
- Add .frequency property as shorthand for .pitch()
- Tones are now sortable: sorted([G4, C4, E4]) works
Scale:
- Add iteration: for tone in scale
- Add len(): len(scale) → 8
- Add "in" operator: "C" in scale, tone in scale
- Add .note_names property
- Add .chord(*degrees) to build chords from scale degrees
- Add .triad(root) to build triads with octave wrapping
Chord:
- Add iteration: for tone in chord
- Add len(): len(chord) → 3
- Add "in" operator: "C" in chord
Fretboard:
- Add .guitar() classmethod for standard tuning
- Add .bass() classmethod for standard bass tuning
- Add .ukulele() classmethod for standard ukulele tuning
- Add iteration and len()
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add pytest as dev dependency in pyproject.toml
- Fix sawtooth_wave: numpy.linspace requires int for num parameter
- Fix Scale.degree() lookup by name ("tonic", "dominant") was broken
- Add tests for: Tone.from_tuple, from_index, _index, error paths,
multi-octave arithmetic, descending chromatic walk, all pitch frequencies,
Pythagorean temperament, all scale degrees by Roman numeral and name,
Scale repr/slice/degrees mismatch, TonedScale repr/get/with-Tone-object,
D/F/A/E/B major/minor scales, D Dorian, G Mixolydian, octave boundary
crossing, all mode intervals including Phrygian/Aeolian/Locrian/Ionian,
chord intervals/beat_pulse/empty chord, Chord/Fretboard fingering errors,
all NamedChord qualities (m6/m9/maj9/9), fix_fingering, flat-to-sharp
conversion, charts total count, charts_for_fretboard, all wave generators,
wave output types, Synth with real pitches, circle of fifths/fourths,
relative minor equivalence, enharmonic equivalence in scales, I-IV-V
progression integration test
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix Tone.__init__ overwriting explicit octave kwarg when parsing name
- Fix Tone.__eq__ calling names as attribute instead of method, add __hash__
- Fix octave arithmetic to use C-based boundaries (scientific pitch notation)
- Fix pitch() to account for octave (was ignoring it entirely)
- Fix modal scale generation: modes were overwritten due to DEGREES loop bug
- Fix modal offset rotation off-by-one in generate_scale
- Fix scales._scales property being called as function
- Fix chord intervals: major/minor thirds were swapped, added missing chord tones
- Remove broken duplicate NamedChord class in chords.py
- Expand test suite from 11 to 83 tests covering tones, scales, modes, chords,
pitches, fingerings, and intervals
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>