mirror of
https://github.com/kennethreitz/pytheory.git
synced 2026-06-05 23:00:20 +00:00
Compare commits
131 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6c83dbe5aa | |||
| b3f3e985b4 | |||
| c1925af69d | |||
| 7883c978f7 | |||
| 36d558573c | |||
| 1e2f09e2ab | |||
| 9404afc1f3 | |||
| 72aa097552 | |||
| 5ebf0bdd97 | |||
| 1d897c6609 | |||
| 4113aad5d0 | |||
| 6ecef688e1 | |||
| fcc5db8e3d | |||
| 9de113b6e7 | |||
| 0b98f7bd77 | |||
| e0a1ce9d18 | |||
| de7575fe0a | |||
| 665a6f5de5 | |||
| 63362df697 | |||
| 755b33a63b | |||
| 40901d603d | |||
| 9b3cbd9065 | |||
| 0911947971 | |||
| c2f748d5f3 | |||
| 7a6942c8e4 | |||
| db7fabf985 | |||
| a07b7e7cea | |||
| 7245cd0e51 | |||
| 9e85a48d0e | |||
| 95b7bd830c | |||
| 150c57ed3d | |||
| d35d2b12f3 | |||
| 2084473788 | |||
| 970c730012 | |||
| 5f94e1939b | |||
| b649b2e659 | |||
| ed6ba2ab9f | |||
| fd317f9cfd | |||
| c57e29fe28 | |||
| 938024bfa2 | |||
| acc92f9a60 | |||
| 0d340dad30 | |||
| 1762500108 | |||
| ac2801d07d | |||
| c49ec27b1b | |||
| 5f4070c4a7 | |||
| 8735393aaa | |||
| 12f15d5138 | |||
| 20fc5e40b8 | |||
| 91d16595b7 | |||
| 54659d39b1 | |||
| 7cb2c166f9 | |||
| ba2038d7ff | |||
| 198fded20e | |||
| 51159e309a | |||
| 54df949089 | |||
| 30c70da468 | |||
| c633bd6f61 | |||
| bc652c37d0 | |||
| 417d9a6908 | |||
| f7d8f08446 | |||
| b8d1fe5e81 | |||
| 2612444146 | |||
| 48a954d063 | |||
| 8a07be23e6 | |||
| d771117d5c | |||
| 1ae9404f07 | |||
| 2e5b18de2e | |||
| 248594fb21 | |||
| 3ce890c54c | |||
| 499c49b6eb | |||
| f85504b456 | |||
| d0624f8b78 | |||
| fb37a7c27b | |||
| fb36e75a42 | |||
| 81b54d2394 | |||
| fa6a3090cb | |||
| 58286ddb69 | |||
| 6d137be9f5 | |||
| 383802a1e1 | |||
| 7f2aeb2395 | |||
| 16b4c7d1fa | |||
| b9ee5c9cde | |||
| 7375d58209 | |||
| 6316a6c910 | |||
| 237cfe171c | |||
| 1751f97617 | |||
| 943a12b3bb | |||
| 04d2de3e70 | |||
| ead42751ef | |||
| 8dee0d00d8 | |||
| de112e0d9f | |||
| f469ad90f8 | |||
| bab7f39304 | |||
| 62557ba534 | |||
| 8b50a9c325 | |||
| 7e9caac70b | |||
| a0756b3172 | |||
| e3dd706032 | |||
| 9b412906bc | |||
| 54e0421997 | |||
| 109343ad30 | |||
| 28e84de566 | |||
| d353d64298 | |||
| 7ee02e7ed2 | |||
| a5c9a46eb2 | |||
| f9c63ec360 | |||
| b9e88b77d8 | |||
| 1910b09132 | |||
| 0c5287450b | |||
| 5ac1873d83 | |||
| 9fafca2b08 | |||
| af044f68ca | |||
| 60f697f846 | |||
| 7d678e364e | |||
| 3a8d829010 | |||
| 2a67906937 | |||
| b9dcad0454 | |||
| db9726168a | |||
| 26af923789 | |||
| 72e18a9bec | |||
| 7d56ed7a2c | |||
| 6efa4f18ce | |||
| 06fc4cabb7 | |||
| d3a93c18b3 | |||
| 0e10359236 | |||
| df00c3436d | |||
| 2f02df15b8 | |||
| a2740b8d57 | |||
| 840bfcc36c | |||
| 938c1cc132 |
@@ -7,3 +7,4 @@ t2.py
|
||||
__pycache__
|
||||
pytheory.egg-info
|
||||
docs/_build
|
||||
.claude/worktrees/
|
||||
|
||||
+259
@@ -2,6 +2,265 @@
|
||||
|
||||
All notable changes to PyTheory are documented here.
|
||||
|
||||
## 0.43.0
|
||||
|
||||
- **BREAKING — fingerings now read low-to-high by default.** `Fretboard`
|
||||
string lists and `Fingering` positions/string-names now run from the
|
||||
**lowest-pitched string first** (e.g. standard guitar reads `E A D G B E`),
|
||||
matching how chord diagrams and tablature are conventionally written.
|
||||
Previously they ran high-to-low (`E B G D A E`). This affects
|
||||
`Fretboard.tones`, iteration over a fretboard, `repr`, `chord()`, `tab()`,
|
||||
`chart()`, and `fingering()` output.
|
||||
|
||||
To restore the pre-0.43 high-to-low behavior, pass **`high_to_low=True`**
|
||||
to any fretboard constructor — `Fretboard.guitar(high_to_low=True)`,
|
||||
`Fretboard(tones=..., high_to_low=True)`, and likewise on every instrument
|
||||
preset (`bass`, `ukulele`, `mandolin`, … `keyboard`).
|
||||
|
||||
The flip also applies to **input**: a custom tuning tuple passed to
|
||||
`Fretboard.guitar(...)` and manual fret positions passed to
|
||||
`fingering(*positions)` are now read in the board's orientation
|
||||
(low-to-high by default).
|
||||
|
||||
`to_tab()` and `Part.strum()` are unaffected — they sort by pitch
|
||||
internally and produce identical output regardless of orientation.
|
||||
|
||||
## 0.42.1
|
||||
|
||||
- **Fretboard tuning support** — `to_tab()` now accepts `Fretboard` objects as
|
||||
the `tuning` parameter. Works with `Fretboard.guitar()`, `Fretboard.bass()`,
|
||||
`Fretboard.ukulele()`, `Fretboard.mandolin()`, `Fretboard.banjo()`, and any
|
||||
custom Fretboard with capo.
|
||||
|
||||
## 0.42.0
|
||||
|
||||
- **LilyPond export** — `Score.to_lilypond()` generates complete LilyPond source
|
||||
files with multi-staff scores, key/time signatures, tempo markings, and
|
||||
automatic bass clef detection. Output can be compiled to publication-quality
|
||||
PDFs with LilyPond.
|
||||
- **MusicXML export** — `Score.to_musicxml()` generates MusicXML 4.0 documents
|
||||
that can be opened in MuseScore, Sibelius, Finale, and any notation software.
|
||||
Includes proper ties, chords, clef detection, and tempo/time signature metadata.
|
||||
- **Guitar/bass tablature** — `Part.to_tab()` and `Score.to_tab()` generate ASCII
|
||||
tablature. Supports guitar (6-string), bass (4-string), drop D, and custom
|
||||
tunings. Automatically maps notes to the best string/fret positions.
|
||||
|
||||
## 0.41.4
|
||||
|
||||
- **Fix** — `to_abc()` now ties long notes across barlines instead of emitting
|
||||
oversized durations that abcjs can't render (e.g. 16-beat notes become four
|
||||
tied whole notes).
|
||||
|
||||
## 0.41.3
|
||||
|
||||
- **Fix** — `to_abc()` now skips parts with only drum tones or rests (no pitched
|
||||
notes), fixing "pitch is undefined" errors in abcjs. Chords are correctly
|
||||
recognized as pitched content.
|
||||
|
||||
## 0.41.2
|
||||
|
||||
- **Auto bass clef** — `to_abc()` detects low-register parts (808, bass, timpani)
|
||||
and assigns `clef=bass` automatically based on average note octave.
|
||||
|
||||
## 0.41.1
|
||||
|
||||
- **Fix** — `to_abc()` no longer crashes on parts containing drum tones.
|
||||
|
||||
## 0.41.0
|
||||
|
||||
- **ABC notation export** — `Score.to_abc()` converts scores to ABC notation
|
||||
strings. Supports multi-voice scores (via `V:` directives), chords, rests,
|
||||
accidentals, and all standard durations. Pass `html=True` to get a
|
||||
self-contained HTML page that renders sheet music in the browser via abcjs.
|
||||
|
||||
## 0.40.9
|
||||
|
||||
- **Mellotron synth** — tape-replay keyboard with wow/flutter, tape saturation,
|
||||
bandwidth limiting, hiss, and 8-second tape fadeout. Three tape banks via the
|
||||
`tape` parameter: `"strings"` (default), `"flute"`, and `"choir"`.
|
||||
- **Analog oscillator synths** — four new waveform generators for fat, alive,
|
||||
analog-style sounds:
|
||||
- `Synth.HARD_SYNC` — slave oscillator hard-synced to a master (Prophet-5
|
||||
leads). `slave_ratio` parameter controls harmonic content.
|
||||
- `Synth.RING_MOD` — two oscillators multiplied for metallic, bell-like
|
||||
inharmonic tones. `mod_ratio` parameter.
|
||||
- `Synth.WAVEFOLD` — west coast wavefolding (Buchla-style). `folds` parameter
|
||||
sweeps from warm to gnarly.
|
||||
- `Synth.DRIFT` — analog VCO with pitch drift, jitter, and noise floor.
|
||||
`shape` parameter (`"saw"`, `"square"`, `"triangle"`, `"pulse"`) and
|
||||
`drift_amount` for instability level.
|
||||
- **Synth kwargs passthrough** — `play()`, `save()`, and `_render()` now accept
|
||||
`**synth_kw` for forwarding parameters to synth wave functions (e.g.
|
||||
`play(tone, synth=Synth.MELLOTRON, tape="choir")`).
|
||||
- **14 new instrument presets** — `mellotron`, `mellotron_strings`,
|
||||
`mellotron_flute`, `mellotron_choir`, `sync_lead`, `sync_lead_bright`,
|
||||
`ring_mod_bell`, `ring_mod_metallic`, `wavefold_warm`, `wavefold_gnarly`,
|
||||
`drift_saw`, `drift_square`, `analog_pad`, `analog_bass`.
|
||||
- **808 bass envelope fix** — changed from `pluck` (zero sustain, wrong for 808)
|
||||
to `piano` (sharp attack with long decay tail).
|
||||
|
||||
## 0.40.8
|
||||
|
||||
- **Fix hold() inflating duration** — `Note.beats` was returning the full
|
||||
duration for held notes (`_hold=True`), causing `Part.total_beats` and
|
||||
`Score.duration_ms` to overcount. A part with `hold(Sa, WHOLE * 4)` followed
|
||||
by `add(Pa, QUARTER)` would report 17 beats instead of 1. Now held notes
|
||||
return 0 beats, matching the renderer which already skipped advancing the
|
||||
timeline for held notes.
|
||||
|
||||
## 0.40.7
|
||||
|
||||
- **Expose missing Synth enum entries** — rhodes, wurlitzer, vibraphone,
|
||||
pipe organ, and choir wave functions were already implemented but not
|
||||
accessible via the Synth enum. Now available as `Synth.RHODES`,
|
||||
`Synth.WURLITZER`, `Synth.VIBRAPHONE`, `Synth.PIPE_ORGAN`, `Synth.CHOIR`.
|
||||
|
||||
## 0.40.6
|
||||
|
||||
- **Saxophone presets cleaned up** — removed lowpass filters and vel_to_filter
|
||||
from all sax instrument presets (saxophone, alto_sax, tenor_sax, bari_sax).
|
||||
The saxophone wave function already shapes its own spectrum; the extra
|
||||
filters were dulling the tone.
|
||||
|
||||
## 0.40.5
|
||||
|
||||
- **Saxophone synth overhaul** — reed nonlinearity (asymmetric soft clipping),
|
||||
conical bore formant resonances, breath noise with attack envelope, separate
|
||||
reed buzz, key click transient, and sub-harmonic warmth. Vibrato dialed back
|
||||
to subtle, delayed onset.
|
||||
|
||||
## 0.40.4
|
||||
|
||||
- **Distortion overhaul** — multi-stage clipping (preamp → power amp →
|
||||
asymmetric rectifier) replaces single-stage tanh. Crunch, distorted,
|
||||
orange crunch, and metal guitar presets now sound properly driven.
|
||||
|
||||
## 0.40.3
|
||||
|
||||
- **Crotales synth** — tuned bronze discs with long ring and bright harmonics
|
||||
- **Tingsha synth** — paired Tibetan cymbals with beating from two detuned discs
|
||||
- **Rain stick** — cascading pebbles (steep and slow/shallow variants)
|
||||
- **Ocean drum** — steel beads rolling inside a frame drum, surf wash
|
||||
- **Cabasa** — metal bead chain on cylinder, bright metallic scrape
|
||||
- **Wind chimes** — multiple suspended metal tubes ringing at random offsets
|
||||
- **Finger cymbal** — single zill tap, bright metallic ping
|
||||
- `crotales`, `tingsha`, `singing_bowl`, `singing_bowl_ring` instrument presets
|
||||
- Audio demos in docs for all new sounds
|
||||
|
||||
## 0.40.2
|
||||
|
||||
- **Master compressor dialed back** — threshold raised from 0.5 to 0.7,
|
||||
makeup gain capped at 3x. Sparse arrangements no longer get
|
||||
over-amplified to clipping.
|
||||
|
||||
## 0.40.1
|
||||
|
||||
- **Singing bowl synth** — two variants: strike (mallet hit with chirp
|
||||
and long decay) and ring (rim-rubbed sustained tone with slow build).
|
||||
Inharmonic partials beat against near-degenerate mode pairs for
|
||||
authentic Himalayan bowl shimmer.
|
||||
- `singing_bowl` and `singing_bowl_ring` instrument presets
|
||||
- Audio demos in docs for both variants
|
||||
|
||||
## 0.40.0
|
||||
|
||||
- **Rhodes electric piano synth** — tine + tonebar + electromagnetic
|
||||
pickup model. `electric_piano` preset now uses dedicated `rhodes_synth`
|
||||
instead of FM
|
||||
- **73 audio demos in docs** — every synth, every drum pattern, every
|
||||
code example with `play_score()` now has an embedded audio player
|
||||
- Idiomatic demos: harp arpeggiates, guitars strum, cello bows, sitar
|
||||
drones, strings use ensemble
|
||||
- Trailing silence trimming on all audio exports
|
||||
- Raw waveform demos (no envelope) for classic waveforms
|
||||
|
||||
## 0.39.3
|
||||
|
||||
- **33 audio samples in documentation** — every `play_score()` example
|
||||
now has an embedded stereo audio player. Covers quickstart, sequencing,
|
||||
drums (all world percussion), playback, and cookbook.
|
||||
- **`docs/generate_audio.py`** — renders all doc examples to WAV
|
||||
- Numpy vectorization: cached time arrays, decay envelopes, drum hits;
|
||||
vectorized piano harmonic synthesis
|
||||
- Fixed acid legato example (removed pad envelope, added proper 303 recipe)
|
||||
|
||||
## 0.39.2
|
||||
|
||||
- **Marching percussion** — snare, rimshot, and stick click sounds with
|
||||
high-tension kevlar synthesis and woody-metallic rimshot crack
|
||||
- **`Part.flam()`**, **`Part.diddle()`**, **`Part.cheese()`** — marching
|
||||
rudiment methods for any drum sound
|
||||
- **`Part ensemble=`** — duplicate voices with per-player timing tendencies
|
||||
and micro pitch drift. Works on any Part (drumline, string section, choir).
|
||||
`ensemble=20` for a full snare line, `ensemble=4` for a string quartet.
|
||||
- **Sympathetic resonance** — marching snare buzz builds up with repeated
|
||||
hits, decays during rests (like real snare wire response)
|
||||
- **4 marching patterns** — march, cadence, paradiddle, roll
|
||||
- **Chakradar tabla pattern** — 16-beat tihai of tihais composition
|
||||
- Song #32: Snare Cadence (flams, diddles, cheese, triplets, 32nds)
|
||||
|
||||
## 0.39.1
|
||||
|
||||
- **Chakradar tabla pattern** — 16-beat tihai of tihais composition with
|
||||
3 escalating phrases and a crescendo triplet finale
|
||||
|
||||
## 0.39.0
|
||||
|
||||
- **Dropped `numeral` dependency** — Roman numeral helpers inlined,
|
||||
reducing supply chain surface (#47)
|
||||
- **`Part.ramp()`** — smooth parameter automation with 4 interpolation
|
||||
curves (linear, ease_in, ease_out, ease_in_out)
|
||||
- **Articulations** — staccato, legato, marcato, tenuto, accent, fermata
|
||||
- **Dynamic curves** — crescendo(), decrescendo(), swell(), dynamics()
|
||||
- **`Part.hit()`** — individual drum sounds with articulation support
|
||||
- **Cross-choke drum damping** — djembe, hi-hats, cajón, doumbek
|
||||
- **5 new djembe patterns** + 3 djembe fills (30 fills total)
|
||||
- **6 new drum fills** — 3 cajón, 3 metal
|
||||
- **Duration arithmetic** — multiply, divide, add
|
||||
- **Improved djembe slap** synthesis
|
||||
- Song #31: Acid Tabla
|
||||
|
||||
## 0.38.2
|
||||
|
||||
- **`Part.ramp()`** — smooth parameter automation from current value to
|
||||
target over a duration. Works for lowpass, reverb, distortion, chorus,
|
||||
delay, volume, and any `.set()` parameter. Four interpolation curves:
|
||||
linear, ease_in, ease_out, ease_in_out.
|
||||
|
||||
## 0.38.1
|
||||
|
||||
- **Dynamic curves** — `Part.crescendo()`, `Part.decrescendo()`,
|
||||
`Part.swell()`, and `Part.dynamics()` for velocity ramps and custom
|
||||
curves across a sequence of notes
|
||||
|
||||
## 0.38.0
|
||||
|
||||
- **Articulations** — `staccato`, `legato`, `marcato`, `tenuto`, `accent`,
|
||||
`fermata` via `articulation=` on `Part.add()` and `Part.hold()`
|
||||
- **`Part.hit()`** — place individual drum sounds in a Part's note stream
|
||||
with articulation, velocity, and effects support
|
||||
- **5 new djembe patterns** — dununba, tiriba, yankadi, djansa, mendiani
|
||||
- **3 new djembe fills** — djembe call, djembe roll, djembe break (30 fills total)
|
||||
- **Cross-choke drum damping** — striking one sound fades out related sounds
|
||||
(djembe, hi-hats, cajón, doumbek)
|
||||
- **Improved djembe slap** — dry goatskin pop instead of snare-like noise
|
||||
|
||||
## 0.37.0
|
||||
|
||||
- **5 new djembe patterns** — dununba, tiriba, yankadi, djansa, mendiani
|
||||
- **3 new djembe fills** — djembe call, djembe roll, djembe break (30 fills total)
|
||||
- **Cross-choke drum damping** — striking one sound on a hand drum fades
|
||||
out the ring of related sounds (djembe slap kills bass resonance, closed
|
||||
hat chokes open hat, cajón slap dampens bass, doumbek tek dampens dum)
|
||||
- **Improved djembe slap** — dry, high-pitched goatskin pop instead of
|
||||
snare-like noise rattle
|
||||
|
||||
## 0.36.6
|
||||
|
||||
- **6 new drum fills** — 3 cajón (flam, rumble, breakdown) and 3 metal
|
||||
(triplet, blast, cascade). 27 fills total.
|
||||
- Updated drums documentation with fill lists and examples
|
||||
|
||||
## 0.36.5
|
||||
|
||||
- **Duration arithmetic** — `Duration.WHOLE * 2`, `Duration.HALF + Duration.QUARTER`,
|
||||
|
||||
@@ -0,0 +1,207 @@
|
||||
"""Demo the 5 new synths: Mellotron, Hard Sync, Ring Mod, Wavefold, Drift.
|
||||
|
||||
Each synth gets a short musical phrase — not just a scale run — with
|
||||
reverb and rhythmic variety to show off its character.
|
||||
"""
|
||||
from pytheory import Score, Duration, play_score
|
||||
|
||||
EIGHTH = Duration.EIGHTH
|
||||
QUARTER = Duration.QUARTER
|
||||
HALF = Duration.HALF
|
||||
DOTTED_Q = Duration.DOTTED_QUARTER
|
||||
WHOLE = Duration.WHOLE
|
||||
|
||||
|
||||
# ── Mellotron Strings ────────────────────────────────────────────────────────
|
||||
# Strawberry Fields vibes — slow, haunted, with rests that breathe.
|
||||
|
||||
print("=== MELLOTRON STRINGS ===")
|
||||
s = Score("4/4", bpm=72)
|
||||
p = s.part("tape", instrument="mellotron_strings",
|
||||
reverb=0.45, reverb_type="cathedral", reverb_decay=2.0)
|
||||
p.add("G4", HALF).add("B4", QUARTER).add("D5", QUARTER)
|
||||
p.add("C5", DOTTED_Q).add("B4", EIGHTH).add("A4", HALF)
|
||||
p.rest(QUARTER)
|
||||
p.add("G4", DOTTED_Q).add("F#4", EIGHTH).add("G4", WHOLE)
|
||||
play_score(s)
|
||||
|
||||
|
||||
# ── Mellotron Flute ──────────────────────────────────────────────────────────
|
||||
# Lonely, breathy, with space between phrases.
|
||||
|
||||
print("\n=== MELLOTRON FLUTE ===")
|
||||
s = Score("3/4", bpm=84)
|
||||
p = s.part("flute", instrument="mellotron_flute",
|
||||
reverb=0.5, reverb_type="taj_mahal", reverb_decay=2.5)
|
||||
p.add("E5", HALF).add("D5", QUARTER)
|
||||
p.add("C5", DOTTED_Q).add("B4", EIGHTH).rest(QUARTER)
|
||||
p.add("A4", HALF).add("G4", QUARTER)
|
||||
p.add("A4", HALF).rest(QUARTER)
|
||||
p.add("E5", QUARTER).add("D5", QUARTER).add("C5", QUARTER)
|
||||
p.add("B4", HALF + QUARTER)
|
||||
play_score(s)
|
||||
|
||||
|
||||
# ── Mellotron Choir ──────────────────────────────────────────────────────────
|
||||
# Ghostly pad — slow chords, big reverb.
|
||||
|
||||
print("\n=== MELLOTRON CHOIR ===")
|
||||
s = Score("4/4", bpm=60)
|
||||
p = s.part("choir", instrument="mellotron_choir",
|
||||
reverb=0.6, reverb_type="cathedral", reverb_decay=3.0)
|
||||
p.add("C4", WHOLE)
|
||||
p.add("E4", HALF).add("G4", HALF)
|
||||
p.add("A4", DOTTED_Q).add("G4", EIGHTH).add("F4", HALF)
|
||||
p.add("E4", WHOLE)
|
||||
play_score(s)
|
||||
|
||||
|
||||
# ── Hard Sync Lead ───────────────────────────────────────────────────────────
|
||||
# Aggressive, punchy — fast 16ths and syncopation.
|
||||
|
||||
print("\n=== HARD SYNC LEAD ===")
|
||||
s = Score("4/4", bpm=128)
|
||||
p = s.part("sync", instrument="sync_lead",
|
||||
reverb=0.25, reverb_type="plate")
|
||||
p.add("E4", EIGHTH).add("E4", EIGHTH).rest(EIGHTH).add("G4", EIGHTH)
|
||||
p.add("A4", QUARTER).add("G4", EIGHTH).add("E4", EIGHTH)
|
||||
p.add("D4", EIGHTH).rest(EIGHTH).add("E4", EIGHTH).add("G4", EIGHTH)
|
||||
p.add("A4", HALF)
|
||||
p.rest(QUARTER).add("B4", EIGHTH).add("A4", EIGHTH)
|
||||
p.add("G4", QUARTER).add("E4", QUARTER).add("D4", HALF)
|
||||
play_score(s)
|
||||
|
||||
|
||||
# ── Hard Sync Bright ─────────────────────────────────────────────────────────
|
||||
# Higher slave ratio — more harmonics, screaming lead.
|
||||
|
||||
print("\n=== HARD SYNC BRIGHT ===")
|
||||
s = Score("4/4", bpm=138)
|
||||
p = s.part("sync2", instrument="sync_lead_bright",
|
||||
reverb=0.2, reverb_type="plate")
|
||||
p.add("A4", EIGHTH).add("C5", EIGHTH).add("D5", QUARTER)
|
||||
p.rest(EIGHTH).add("E5", EIGHTH).add("D5", EIGHTH).add("C5", EIGHTH)
|
||||
p.add("A4", QUARTER).rest(QUARTER).add("G4", EIGHTH).add("A4", EIGHTH)
|
||||
p.add("C5", HALF)
|
||||
play_score(s)
|
||||
|
||||
|
||||
# ── Ring Mod Bell ────────────────────────────────────────────────────────────
|
||||
# Shimmery, metallic — sparse hits with long reverb tail.
|
||||
|
||||
print("\n=== RING MOD BELL ===")
|
||||
s = Score("4/4", bpm=66)
|
||||
p = s.part("bell", instrument="ring_mod_bell",
|
||||
reverb=0.6, reverb_type="cave", reverb_decay=3.0)
|
||||
p.add("C5", HALF).rest(QUARTER).add("G4", QUARTER)
|
||||
p.rest(HALF).add("E5", HALF)
|
||||
p.add("D5", QUARTER).rest(QUARTER).add("C5", HALF)
|
||||
p.rest(WHOLE)
|
||||
p.add("G4", QUARTER).add("A4", QUARTER).add("C5", HALF)
|
||||
play_score(s)
|
||||
|
||||
|
||||
# ── Ring Mod Metallic ────────────────────────────────────────────────────────
|
||||
# Alien, inharmonic — atonal stabs.
|
||||
|
||||
print("\n=== RING MOD METALLIC ===")
|
||||
s = Score("4/4", bpm=100)
|
||||
p = s.part("metal", instrument="ring_mod_metallic",
|
||||
reverb=0.4, reverb_type="parking_garage", reverb_decay=2.0)
|
||||
p.add("F4", EIGHTH).rest(EIGHTH).add("Ab4", EIGHTH).add("F4", EIGHTH)
|
||||
p.rest(QUARTER).add("Db5", QUARTER).rest(QUARTER)
|
||||
p.add("C5", EIGHTH).add("Ab4", EIGHTH).rest(QUARTER).add("F4", HALF)
|
||||
p.rest(HALF).add("Db5", QUARTER).add("C5", QUARTER)
|
||||
play_score(s)
|
||||
|
||||
|
||||
# ── Wavefold Warm ────────────────────────────────────────────────────────────
|
||||
# Gentle folds — round and musical, like a filtered saw with overtones.
|
||||
|
||||
print("\n=== WAVEFOLD WARM ===")
|
||||
s = Score("4/4", bpm=108)
|
||||
p = s.part("fold", instrument="wavefold_warm",
|
||||
reverb=0.3, reverb_type="plate")
|
||||
p.add("A3", QUARTER).add("C4", QUARTER).add("E4", QUARTER).add("A4", QUARTER)
|
||||
p.add("G4", DOTTED_Q).add("E4", EIGHTH).add("C4", HALF)
|
||||
p.add("D4", QUARTER).add("F4", QUARTER).add("A4", HALF)
|
||||
p.add("G4", WHOLE)
|
||||
play_score(s)
|
||||
|
||||
|
||||
# ── Wavefold Gnarly ──────────────────────────────────────────────────────────
|
||||
# Cranked folds — buzzy, aggressive, with syncopation.
|
||||
|
||||
print("\n=== WAVEFOLD GNARLY ===")
|
||||
s = Score("4/4", bpm=130)
|
||||
p = s.part("gnarly", instrument="wavefold_gnarly",
|
||||
reverb=0.2, reverb_type="spring")
|
||||
p.add("E3", EIGHTH).add("E3", EIGHTH).rest(EIGHTH).add("G3", EIGHTH)
|
||||
p.add("A3", EIGHTH).rest(EIGHTH).add("B3", EIGHTH).add("A3", EIGHTH)
|
||||
p.add("E3", QUARTER).add("G3", EIGHTH).add("A3", EIGHTH).add("B3", QUARTER)
|
||||
p.rest(QUARTER)
|
||||
p.add("E4", EIGHTH).add("D4", EIGHTH).add("B3", QUARTER).add("A3", HALF)
|
||||
play_score(s)
|
||||
|
||||
|
||||
# ── Drift Saw ────────────────────────────────────────────────────────────────
|
||||
# Warm, alive analog saw — the Minimoog pad.
|
||||
|
||||
print("\n=== DRIFT SAW (vintage VCO) ===")
|
||||
s = Score("4/4", bpm=88)
|
||||
p = s.part("drift", instrument="drift_saw",
|
||||
reverb=0.35, reverb_type="taj_mahal", reverb_decay=2.0)
|
||||
p.add("D4", HALF).add("F4", HALF)
|
||||
p.add("A4", DOTTED_Q).add("G4", EIGHTH).add("F4", QUARTER).rest(QUARTER)
|
||||
p.add("D4", QUARTER).add("E4", QUARTER).add("F4", HALF)
|
||||
p.add("D4", WHOLE)
|
||||
play_score(s)
|
||||
|
||||
|
||||
# ── Drift Square ─────────────────────────────────────────────────────────────
|
||||
# Hollow, wobbly — 8-bit with analog soul.
|
||||
|
||||
print("\n=== DRIFT SQUARE ===")
|
||||
s = Score("4/4", bpm=110)
|
||||
p = s.part("dsq", instrument="drift_square",
|
||||
reverb=0.25, reverb_type="plate")
|
||||
p.add("C4", EIGHTH).add("E4", EIGHTH).add("G4", QUARTER).add("E4", QUARTER)
|
||||
p.rest(QUARTER)
|
||||
p.add("A4", EIGHTH).add("G4", EIGHTH).add("E4", QUARTER).add("C4", HALF)
|
||||
p.add("D4", QUARTER).add("F4", EIGHTH).add("G4", EIGHTH).add("A4", HALF)
|
||||
p.add("G4", WHOLE)
|
||||
play_score(s)
|
||||
|
||||
|
||||
# ── Analog Pad ───────────────────────────────────────────────────────────────
|
||||
# Slow, drifting chords — Juno-style lushness.
|
||||
|
||||
print("\n=== ANALOG PAD ===")
|
||||
s = Score("4/4", bpm=70)
|
||||
p = s.part("pad", instrument="analog_pad",
|
||||
reverb=0.5, reverb_type="taj_mahal", reverb_decay=3.0)
|
||||
p.add("A3", WHOLE)
|
||||
p.add("C4", HALF).add("E4", HALF)
|
||||
p.add("F4", WHOLE)
|
||||
p.add("E4", HALF).add("D4", HALF)
|
||||
p.add("C4", WHOLE)
|
||||
play_score(s)
|
||||
|
||||
|
||||
# ── Analog Bass ──────────────────────────────────────────────────────────────
|
||||
# Tight, punchy — Moog bass with filter sweep.
|
||||
|
||||
print("\n=== ANALOG BASS ===")
|
||||
s = Score("4/4", bpm=120)
|
||||
p = s.part("bass", instrument="analog_bass",
|
||||
reverb=0.1, reverb_type="plate")
|
||||
p.add("E2", EIGHTH).add("E2", EIGHTH).rest(EIGHTH).add("G2", EIGHTH)
|
||||
p.add("A2", QUARTER).rest(QUARTER)
|
||||
p.add("E2", EIGHTH).rest(EIGHTH).add("B2", EIGHTH).add("A2", EIGHTH)
|
||||
p.add("G2", QUARTER).add("E2", QUARTER).rest(HALF)
|
||||
p.add("E2", EIGHTH).add("E2", EIGHTH).add("G2", EIGHTH).add("A2", EIGHTH)
|
||||
p.add("B2", QUARTER).add("A2", QUARTER).add("E2", HALF)
|
||||
play_score(s)
|
||||
|
||||
|
||||
print("\nDone!")
|
||||
Vendored
BIN
Binary file not shown.
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
<audio controls style="width: 100%; margin: 0.5em 0 1.5em 0;">
|
||||
<source src="{{ pathto('_static/audio/' + file, 1) }}" type="audio/wav">
|
||||
Your browser does not support the audio element.
|
||||
</audio>
|
||||
File diff suppressed because it is too large
Load Diff
+27
-3
@@ -94,11 +94,11 @@ PyTheory includes 144 pre-built chords (12 roots x 12 qualities):
|
||||
|
||||
>>> fb = Fretboard.guitar()
|
||||
>>> fb.chord("C")
|
||||
Fingering(e=0, B=1, G=0, D=2, A=3, E=x)
|
||||
Fingering(E=x, A=3, D=2, G=0, B=1, e=0)
|
||||
>>> fb.chord("Am")
|
||||
Fingering(e=0, B=1, G=2, D=2, A=0, E=x)
|
||||
Fingering(E=x, A=0, D=2, G=2, B=1, e=0)
|
||||
>>> fb.chord("G7")
|
||||
Fingering(e=1, B=0, G=0, D=0, A=2, E=3)
|
||||
Fingering(E=3, A=2, D=0, G=0, B=0, e=1)
|
||||
|
||||
You can also build chords directly with ``Chord.from_name()``:
|
||||
|
||||
@@ -503,9 +503,16 @@ are standard arranging techniques for spreading chord tones across registers:
|
||||
>>> cmaj7 = Chord.from_symbol("Cmaj7")
|
||||
>>> cmaj7.close_voicing()
|
||||
<Chord C major 7th>
|
||||
>>> cmaj7.open_voicing()
|
||||
<Chord C major 7th>
|
||||
>>> cmaj7.drop2()
|
||||
<Chord C major 7th>
|
||||
|
||||
``open_voicing()`` takes the close voicing and raises every other
|
||||
non-root tone by an octave, spreading the chord across two octaves.
|
||||
The result is a wider, more spacious sound — common in orchestral
|
||||
writing and piano ballads where you want the harmony to breathe.
|
||||
|
||||
Chord Extensions
|
||||
----------------
|
||||
|
||||
@@ -596,6 +603,23 @@ music that doesn't follow traditional harmony, this is the tool.
|
||||
Major and minor triads share the same prime form — they're inversions
|
||||
of each other in pitch class space.
|
||||
|
||||
The **normal form** is the intermediate step — the most compact ascending
|
||||
arrangement of pitch classes before transposition. It preserves the
|
||||
actual pitch classes (not transposed to 0), so it tells you which
|
||||
specific notes are in the set:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> Chord.from_tones("C", "E", "G").normal_form
|
||||
(0, 4, 7)
|
||||
|
||||
>>> Chord.from_tones("A", "C", "E").normal_form
|
||||
(9, 0, 4)
|
||||
|
||||
Normal form keeps the original pitch classes; prime form transposes to 0
|
||||
for comparison. Use ``normal_form`` when you care about which notes,
|
||||
``prime_form`` when you care about the abstract shape.
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> Chord.from_tones("C", "E", "G").forte_number
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user