sounddevice is now only imported when actually playing audio through
speakers. All other functions (save_midi, render_score, save) work
without PortAudio installed. Fixes 9 test failures in CI.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- `pytheory demo` plays a randomly generated track (6 moods, different every time)
- README rewritten to showcase full feature set: composition, effects, drums,
sidechain, automation, MIDI export, AI collaboration
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Makes programmed parts feel like a real player. Random timing jitter
and velocity wobble applied at render time, score data stays clean.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Per-note velocity for dynamics and accents
- Swing/groove parameter on Score and per-Part override
- score.set_tempo() for mid-song tempo changes with tempo map engine
- Part.fade_in() and Part.fade_out() volume envelopes
- Arpeggiator velocity support
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Part.lfo() generates automation points from oscillator shapes
- 4 shapes: sine, triangle, saw, square
- Rate, range, duration, and resolution all configurable
- Stack LFOs on different params for complex modulation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Part.arpeggio() with 5 patterns, octave spanning, division control
- Roman numeral parser handles bVI, bVII, bIII, #IV prefixes
- song_showoff.py: generative composition using every feature,
different every time (4 moods, matched keys/drums/effects)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Part.arpeggio() with up/down/updown/downup/random patterns
- Octave spanning and division control for arps
- Document legato, glide, and arpeggiator in rhythm guide
- Rename docs page to "Sequencing: Rhythm and Scores"
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Part(legato=True) renders continuous waveform without per-note retriggering
- Part(glide=0.04) adds 303-style pitch slides between notes
- Phase-accumulating oscillator for smooth frequency changes
- Exponential pitch interpolation for perceptually linear slides
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Schroeder reverb (4 comb + 2 allpass filters) with mix/decay
- Tempo-synced delay with feedback
- 12 dB/oct biquad lowpass with resonance (Q) control
- Effects set at part creation, applied per-part before mixing
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Pattern.fill() with 11 presets: rock, jazz, salsa, samba, funk, metal, blast, buildup, breakdown
- Score.fill() inserts a fill at the current position
- Score.drums() auto-fill support: fill_every=4 replaces every 4th bar
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Square wave: chiptune / 8-bit (odd harmonics at 1/n)
- Pulse wave: variable duty cycle NES-style timbres
- FM synthesis: DX7-style carrier/modulator for bells, e-piano, brass
- Noise: white noise for percussion and texture
- Supersaw: 7 detuned saws for trance/EDM pads
- Refactor Synth enum to string-valued with callable dispatch
- All 8 waveforms available via API, Part strings, and CLI
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- 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>
- 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>
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>
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>
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>
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>
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>
- User guide: quickstart, tones, scales, chords, fretboard, playback
- API reference: autodoc for all modules
- alabaster theme with Napoleon for Google/NumPy docstrings
- Update project description in pyproject.toml
- Add sphinx to docs dependency group
Build with: uv run --group docs sphinx-build -b html docs docs/_build/html
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>