- scale_diagram() showcased on homepage and quickstart
- New cookbook page: analyze a song, 12-bar blues, find chords in a key,
compare scales, guitar chord chart, explore intervals
- play_progression() for sequencing chord playback with gaps
- Scale and Note aliases exported
- Version bump to 0.8.0
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>
- Cache fingering results by chord name + tuning for instant repeat lookups
- chart() goes from ~53s to <1ms on second call
- Barre chord detection: when multiple strings share the lowest fret,
count them as 1 finger instead of N
- Hard 4-fret span constraint rejects unplayable voicings
- Penalize shapes requiring more than 4 fingers
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>
New `fb.chord("G")` API lets you look up fingerings by chord name
instead of knowing fret positions upfront. Updates all docs to use
REPL-style examples with verified output.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Show Key class, chord progressions, chord identification, interval
naming, and labeled fingerings in the hero code block. Add pip install
line, CLI examples, and a Highlights section summarizing all features.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Gamelan uses its own tone names (nem, pi, barang, etc.), not Western
note names. Fixed tonic from C4 to nem4 and added pelog nem/barang
modes. Replaced miyako-bushi with iwato and kumoi (actual scale names
in the system). Added ValueError to exception handling.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Version is now pulled from pytheory.__version__ instead of hardcoded.
GitHub button changed from watch to star with count.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Both were using incorrect frequency scaling (magic numbers instead of
deriving cycle length from sample rate / hz). Now they match the sine
wave approach: compute one cycle at the correct frequency, then resize.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Melodies: Twinkle Twinkle, Ode to Joy, Happy Birthday, Fur Elise
Progressions: Pop I-V-vi-IV, 12-bar blues in A, Jazz ii-V-I turnaround
Interactive menu for picking songs. Clean helper functions for
melody and chord progression playback.
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>
Flat names are now resolved to their canonical sharp equivalents when
looking up tones in a system. This means Tone.from_string("Db4") now
works for frequency, arithmetic, intervals, and chord building —
previously it raised a ValueError.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace plain tuples from fingering() methods with a Fingering object
that labels each fret position with its string name, supporting both
named (f['A']) and index (f[1]) access while remaining backward
compatible with tuple equality.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Chord names like Cmaj7 and G7 were incorrectly treated as tone names
because they contain digits. Now tries chord name lookup first. v0.5.1.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Supports single tones and chords, with --synth (sine/saw/triangle),
--duration, and --temperament flags. Bumps version to v0.5.0.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Dedicated section explaining symbolic=True with examples across
all three temperaments, showing exact SymPy expressions, arbitrary
precision evaluation, and why the math reveals temperament differences.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
pytheory tone C5 -t pythagorean
pytheory tone A4 -t meantone
Shows frequency in chosen temperament and difference in cents
from equal temperament. Supports equal, pythagorean, meantone.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
CLI (pytheory command):
pytheory tone C4 — frequency, MIDI, overtones
pytheory scale C major — notes and intervals
pytheory chord C E G — identify, harmony, tension
pytheory key C major — full key analysis with diatonic chords
pytheory fingering Am — ASCII guitar tab
pytheory progression C major I V vi IV — build from Roman numerals
pytheory detect C D E G — detect the key
Jupyter notebook (examples/tutorial.ipynb):
46-cell interactive tutorial covering tones, scales, modes, keys,
chord analysis, progressions, world music systems, guitar fingerings,
and building a song from scratch.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Type hints: all methods and properties across Tone, Scale, TonedScale,
Key, Chord, and Fretboard now have full type annotations using
from __future__ import annotations.
Docstrings: added to all methods that were missing them —
constructors, dunder methods, properties, classmethods.
Property caching:
- TonedScale._scales: computed once and cached (immutable after init)
- Chord.identify(): cached result, cleared on transpose/inversion
- Tone.frequency: cached after first computation
428 tests passing, no behavior changes.
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>
Dependencies were at the root level instead of under [project] — uv
ignored them entirely. This caused uv.lock to omit pytuning, scipy,
numpy, and sounddevice. API reference pages were blank because
autodoc couldn't import the modules.
Also adds [build-system] so uv treats the project as editable
instead of virtual.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
uv sync --group docs only installs sphinx, not pytheory's deps
(pytuning, scipy, etc). Autodoc needs to import the package to
generate API reference pages. Now runs uv sync first.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
TonedScale(tonic="Sa4", system="indian") now works — no need to
import SYSTEMS. Same for Key("C", "major", system="blues").
Updated README and all docs to use the cleaner string syntax,
removing 'from pytheory.systems import SYSTEMS' boilerplate.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>