Fretboard string lists and Fingering positions/string-names now read
low-to-high (lowest-pitched string first), matching how chord diagrams
and tablature are conventionally written. Pass high_to_low=True to any
fretboard constructor to restore the pre-0.43 high-to-low behavior.
Design: each board keeps a private canonical (high-to-low) tone store
so the fingering scorer and GUITAR_OVERRIDES table stay untouched; a
single _orient() helper re-orients at the user-facing boundary (and,
being self-inverse, also canonicalizes custom tuning/position input).
Fingering carries its own orientation flag and presents oriented
positions/names via properties. The fingering cache key now includes
orientation so the two orderings don't collide.
to_tab() and Part.strum() now sort by pitch internally, so their output
is identical regardless of board orientation.
- All 25 instrument presets gain a high_to_low param, routed through a
canonical build path.
- Tests updated for the new default; added orientation-specific tests.
- Docs/examples flipped to low-to-high; chord_charts.py example now uses
the built-in Fingering.tab() instead of a hand-rolled renderer.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
to_tab(tuning=Fretboard.guitar()) now works, along with bass,
ukulele, mandolin, banjo, and any custom Fretboard with capo.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Three new export methods on Score:
- to_lilypond() — complete LilyPond source files for PDF engraving
- to_musicxml() — MusicXML 4.0 for MuseScore/Sibelius/Finale
- to_tab() — ASCII guitar/bass tablature (also on Part)
All three handle multi-part scores, bass clef detection, tied notes
across barlines, chords, and drum tone filtering.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Notes longer than one measure are split into tied pieces so abcjs
can render them correctly (e.g. 16-beat choir drone becomes four
tied whole notes).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Parts with only drum tones or rests are excluded from ABC output.
Chords correctly recognized as pitched content.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New method converts scores to ABC notation with support for multi-voice,
chords, rests, accidentals, and all durations. Pass html=True for a
self-contained HTML page with abcjs sheet music rendering.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Five new synth waveforms: tape-replay Mellotron (strings/flute/choir
tapes with wow, flutter, saturation, 8s fadeout), hard sync oscillator,
ring modulation, wavefolding, and analog drift VCO with pitch
instability. 14 new instrument presets for Score.part(). Synth kwargs
now pass through play()/save()/_render(). 808 bass envelope fixed
from pluck to piano.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Note.beats now returns 0.0 for held notes (_hold=True), matching the
renderer which already skipped advancing the beat position. Previously
every hold() call added its full duration to the part's total, causing
duration reports to be 2-3x too long on tracks with drone notes.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Single tanh was too mild. Now chains preamp gain → power amp clip →
asymmetric rectifier sag for proper overdrive/fuzz character.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Two variants modeling Himalayan singing bowl acoustics:
- Strike: mallet hit with chirp from inharmonic partials, long ring
- Ring: rim-rubbed sustained tone with slow build and beating modes
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
pytheory-live is now a proper command after pip install pytheory[live].
TUI moved to pytheory/live_tui.py, registered as console script.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
_Channel now stores and applies: chorus, detune, distortion,
saturation, tremolo, analog, delay, phaser, sub_osc, noise_mix.
TUI fx command: fx <ch> <param> <val> to tweak any effect live.
fx alone lists all available params. fx <ch> shows current values.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fixes CI failure — rtmidi needs ALSA headers on Linux which
aren't available in the test runner. Now optional: import is
lazy with clear error message if missing.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
LiveEngine listens for MIDI input and synthesizes audio in real-time.
Each MIDI channel maps to a pytheory instrument with its own synth,
envelope, and effects. Supports polyphony, voice stealing, and
GM drum channel (10).
Adds python-rtmidi as a dependency.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace the numeral package with ~30 lines of int2roman()/roman2int()
in _statics.py. Reduces supply chain surface. Fixes#47.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Smoothly sweep any parameter (lowpass, reverb, distortion, etc.)
from current value to target with linear, ease_in, ease_out, or
ease_in_out interpolation curves.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Part.crescendo(), Part.decrescendo(), Part.swell(), and Part.dynamics()
for velocity ramps and custom curves across note sequences.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add 6 new drum fills: cajon flam, cajon rumble, cajon breakdown,
metal triplet, metal blast, metal cascade. 27 fills total.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Duration enum now supports multiplication, division, and addition
so expressions like `Duration.WHOLE * 2` work instead of raising TypeError.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Replace pytuning with 30-line native implementations of EDO,
Pythagorean, and quarter-comma meantone scale generators
- Lazy-load scipy.signal (337ms) — only imported when audio rendering
is actually used, not on theory-only imports
- Removes pytuning and sympy from dependencies entirely
Import time: 0.479s → 0.056s (8.5x faster)
Closes#44
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
16 dedicated instrument synths, speaker cab sim, analog drift,
strumming with fretboard lookup, dhol/dholak/mridangam/djembe/
metal kit with 22 patterns, 5 new demo moods.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Drums are real Parts with full effects pipeline
- split=True creates kick/snare/hats/toms/cymbals/percussion Parts
- Sidechain triggers on kick only
- Score.from_midi() imports Standard MIDI Files
- Document split drums workflow
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Load any Standard MIDI File into a Score. Zero-dependency parser
handles Type 0 and Type 1 files. Each channel becomes a Part,
channel 10 becomes drum hits. Roundtrip with save_midi works.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>