Scale notes spelled with flats (e.g. the Eb blue note in the blues
scale) were silently dropped from scale_diagram() because the fretboard
spells that pitch as D#, so the string comparison never matched. Match
notes enharmonically via the system's canonical name and display them
using the scale's own spelling. Pre-existing bug (also in 0.42.x),
surfaced while flipping the docs for the low-to-high release.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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>
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>
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>
- Harmonium: single free reed, nasal midrange, bellows swell.
The sound of kirtan and qawwali.
- Doumbek (darbuka): dum (center bass), tek (edge sharp), ka (muted).
4 patterns: maqsoum, baladi, saidi, ayoub.
2 fills: doumbek roll, doumbek accent.
- 42 synth waveforms total
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Grain cloud synthesis: source waveform chopped into tiny overlapping
grains (40ms, 50/sec) with Hanning windows, random scatter, and
per-grain pitch variation. Creates textures impossible with other
synthesis. Two presets: granular_pad, granular_texture.
30 synth waveforms total.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Tests for: all 14 dedicated synth waveforms, piano brightness scaling,
cabinet sim frequency reduction, analog drift rendering, strum with/
without fretboard, strum direction, all 6 tabla sounds, dhol/mridangam/
djembe/metal kit sounds, 20 world drum pattern presets, guitar preset
cabinet sim. 838 tests total.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- New acoustic_guitar_synth: Karplus-Strong with wooden body
resonance (3 formant peaks at 110/250/500 Hz), warmer initial
noise, gentle rolloff. Sounds woody, not harsh.
- Strum renders as a single chord hit — no more exposed grace
notes that sounded digital. Clean, full chord sound.
- 16 synth waveforms total
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Carnatic (72-TET): 10 melakartas including shankarabharanam,
kalyani, mayamalavagowla, kharaharapriya, etc.
- Score(system=) param passes tuning system to all parts, so
Part.add("Sa") resolves through the correct system
- 22 new tests covering all microtonal systems: TET factory,
19/31-TET, shruti, maqam, slendro, pelog, thai, makam,
carnatic, circle of fifths, from_frequency, Score integration
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Tone("X") now raises ValueError immediately instead of silently
storing an invalid name and only failing on .frequency access.
Closes#39
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Rewrite strings_wave with additive synthesis: natural 1/n harmonic
rolloff shaped by body resonance curve, per-harmonic phase
randomization, delayed vibrato onset, bow pressure variation
- Add highpass filter (12dB/oct biquad) to signal chain and Part API
- Add BOWED envelope (40ms attack with bite) for string instruments
- Update string presets to use strings_synth + bowed envelope
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Solo violin/viola/cello/contrabass now use triangle + strings envelope
(clean, clear). String ensemble keeps strings_synth + detune for
thick ensemble textures. Solo instruments need clarity, not width.
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>
- Chord.figured_bass: classical inversion notation (6, 6/4, 7, 6/5, 4/3, 2)
- Chord.analyze_figured(): Roman numerals with figured bass (V6/5, ii6)
- Chord.pitch_classes, normal_form, prime_form, forte_number: set theory
- Scale.recommend(): ranked scale suggestions from note sets
- Forte catalog: all trichords and tetrachords
- Documented in chords and scales guides
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Theory: circle, interval, identify, system (with correct per-system tonics)
Guitar: fingering, diagram (scale on fretboard)
22 new tests covering all REPL commands.
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 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>
- 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>
- Part: named voice with synth, envelope, and volume settings
- Score.part() creates and registers parts
- Score.add_pattern() for cleaner drum pattern attachment
- render_score() renders all parts + drums into one buffer
- play_score() updated to use the new multi-part renderer
- Backwards compatible: Score.add() still works for simple cases
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>
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>