mirror of
https://github.com/kennethreitz/pytheory.git
synced 2026-06-05 23:00:20 +00:00
Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 960fdbe3df | |||
| b3f3e985b4 | |||
| c1925af69d | |||
| 7883c978f7 | |||
| 36d558573c | |||
| 1e2f09e2ab | |||
| 9404afc1f3 | |||
| 72aa097552 | |||
| 5ebf0bdd97 | |||
| 1d897c6609 | |||
| 4113aad5d0 | |||
| 6ecef688e1 | |||
| fcc5db8e3d | |||
| 9de113b6e7 | |||
| 0b98f7bd77 | |||
| e0a1ce9d18 | |||
| de7575fe0a | |||
| 665a6f5de5 | |||
| 63362df697 | |||
| 755b33a63b | |||
| 40901d603d | |||
| 9b3cbd9065 | |||
| 0911947971 | |||
| c2f748d5f3 |
@@ -7,3 +7,4 @@ t2.py
|
||||
__pycache__
|
||||
pytheory.egg-info
|
||||
docs/_build
|
||||
.claude/worktrees/
|
||||
|
||||
+128
@@ -2,6 +2,134 @@
|
||||
|
||||
All notable changes to PyTheory are documented here.
|
||||
|
||||
## 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
|
||||
|
||||
@@ -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.
@@ -850,6 +850,56 @@ def gen_synth_ukulele():
|
||||
p.strum(ch, Duration.WHOLE, velocity=72)
|
||||
render("synth_ukulele", score)
|
||||
|
||||
def gen_synth_hard_sync():
|
||||
score = Score("4/4", bpm=120)
|
||||
p = score.part("demo", instrument="sync_lead_bright", volume=0.5)
|
||||
for n in ["C4", "E4", "G4", "C5", "G4", "E4", "C4", "E4"]:
|
||||
p.add(n, Duration.QUARTER, velocity=90)
|
||||
render("synth_hard_sync", score)
|
||||
|
||||
|
||||
def gen_synth_ring_mod():
|
||||
score = Score("4/4", bpm=90)
|
||||
p = score.part("demo", instrument="ring_mod_bell", volume=0.5)
|
||||
for n in ["C5", "E5", "G5", "C6", "G5", "E5", "C5", "E5"]:
|
||||
p.add(n, Duration.QUARTER, velocity=80)
|
||||
render("synth_ring_mod", score)
|
||||
|
||||
|
||||
def gen_synth_wavefold():
|
||||
score = Score("4/4", bpm=110)
|
||||
p = score.part("demo", instrument="wavefold_warm", volume=0.5)
|
||||
for n in ["C4", "E4", "G4", "C5", "G4", "E4", "C4", "E4"]:
|
||||
p.add(n, Duration.QUARTER, velocity=85)
|
||||
render("synth_wavefold", score)
|
||||
|
||||
|
||||
def gen_synth_drift():
|
||||
score = Score("4/4", bpm=90)
|
||||
p = score.part("demo", instrument="drift_saw", volume=0.5, reverb=0.35,
|
||||
reverb_type="taj_mahal")
|
||||
for n in ["C4", "E4", "G4", "C5", "G4", "E4", "C4", "E4"]:
|
||||
p.add(n, Duration.HALF, velocity=75)
|
||||
render("synth_drift", score)
|
||||
|
||||
|
||||
def gen_synth_karplus():
|
||||
score = Score("4/4", bpm=100)
|
||||
p = score.part("demo", synth="pluck_synth", envelope="none",
|
||||
volume=0.5, reverb=0.2)
|
||||
for n in ["C4", "E4", "G4", "C5", "G4", "E4", "C4", "E4"]:
|
||||
p.add(n, Duration.QUARTER, velocity=85)
|
||||
render("synth_karplus", score)
|
||||
|
||||
|
||||
def gen_synth_mellotron():
|
||||
score = Score("4/4", bpm=80)
|
||||
p = score.part("demo", instrument="mellotron_flute", volume=0.5)
|
||||
for n in ["C4", "E4", "G4", "C5"]:
|
||||
p.add(n, Duration.WHOLE, velocity=75)
|
||||
render("synth_mellotron", score)
|
||||
|
||||
|
||||
def gen_synth_granular():
|
||||
score = Score("4/4", bpm=80)
|
||||
p = score.part("demo", instrument="granular_pad", volume=0.5, reverb=0.4)
|
||||
@@ -858,6 +908,68 @@ def gen_synth_granular():
|
||||
render("synth_granular", score)
|
||||
|
||||
|
||||
def gen_synth_crotales():
|
||||
score = Score("4/4", bpm=60)
|
||||
p = score.part("demo", synth="crotales_synth", envelope="none",
|
||||
volume=0.5, reverb=0.3)
|
||||
for n in ["C6", "E6", "G6", "C7", "G6", "E6", "C6"]:
|
||||
p.add(n, Duration.HALF, velocity=80)
|
||||
render("synth_crotales", score)
|
||||
|
||||
|
||||
def gen_synth_tingsha():
|
||||
score = Score("4/4", bpm=40)
|
||||
p = score.part("demo", synth="tingsha_synth", envelope="none",
|
||||
volume=0.5, reverb=0.4)
|
||||
for n in ["E5", "A5", "E6", "A5"]:
|
||||
p.add(n, Duration.WHOLE, velocity=75)
|
||||
render("synth_tingsha", score)
|
||||
|
||||
|
||||
def gen_rainstick():
|
||||
score = Score("4/4", bpm=60)
|
||||
p = score.part("demo", synth="sine", volume=1.0)
|
||||
p.hit(DrumSound.RAINSTICK, Duration.WHOLE * 3, velocity=90)
|
||||
render("rainstick", score)
|
||||
|
||||
|
||||
def gen_rainstick_slow():
|
||||
score = Score("4/4", bpm=60)
|
||||
p = score.part("demo", synth="sine", volume=1.0)
|
||||
p.hit(DrumSound.RAINSTICK_SLOW, Duration.WHOLE * 4, velocity=85)
|
||||
render("rainstick_slow", score)
|
||||
|
||||
|
||||
def gen_ocean_drum():
|
||||
score = Score("4/4", bpm=60)
|
||||
p = score.part("demo", synth="sine", volume=1.0)
|
||||
p.hit(DrumSound.OCEAN_DRUM, Duration.WHOLE * 3, velocity=85)
|
||||
render("ocean_drum", score)
|
||||
|
||||
|
||||
def gen_cabasa():
|
||||
score = Score("4/4", bpm=100)
|
||||
p = score.part("demo", synth="sine", volume=1.0)
|
||||
for _ in range(16):
|
||||
p.hit(DrumSound.CABASA, Duration.EIGHTH, velocity=100)
|
||||
render("cabasa", score)
|
||||
|
||||
|
||||
def gen_wind_chimes():
|
||||
score = Score("4/4", bpm=60)
|
||||
p = score.part("demo", synth="sine", volume=1.0)
|
||||
p.hit(DrumSound.WIND_CHIMES, Duration.WHOLE * 3, velocity=85)
|
||||
render("wind_chimes", score)
|
||||
|
||||
|
||||
def gen_finger_cymbal():
|
||||
score = Score("4/4", bpm=80)
|
||||
p = score.part("demo", synth="sine", volume=1.0)
|
||||
for _ in range(8):
|
||||
p.hit(DrumSound.FINGER_CYMBAL, Duration.QUARTER, velocity=85)
|
||||
render("finger_cymbal", score)
|
||||
|
||||
|
||||
def gen_synth_singing_bowl_strike():
|
||||
score = Score("4/4", bpm=40)
|
||||
p = score.part("demo", synth="singing_bowl_strike_synth", envelope="none",
|
||||
@@ -1077,9 +1189,23 @@ GENERATORS = [
|
||||
gen_synth_banjo,
|
||||
gen_synth_mandolin,
|
||||
gen_synth_ukulele,
|
||||
gen_synth_hard_sync,
|
||||
gen_synth_ring_mod,
|
||||
gen_synth_wavefold,
|
||||
gen_synth_drift,
|
||||
gen_synth_karplus,
|
||||
gen_synth_mellotron,
|
||||
gen_synth_granular,
|
||||
gen_synth_crotales,
|
||||
gen_synth_tingsha,
|
||||
gen_synth_singing_bowl_strike,
|
||||
gen_synth_singing_bowl_ring,
|
||||
gen_rainstick,
|
||||
gen_rainstick_slow,
|
||||
gen_ocean_drum,
|
||||
gen_cabasa,
|
||||
gen_wind_chimes,
|
||||
gen_finger_cymbal,
|
||||
gen_arpeggio,
|
||||
gen_legato_glide,
|
||||
gen_acid_house,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,404 @@
|
||||
Nashville Numbers, Blues Scales, and Tablature
|
||||
===============================================
|
||||
|
||||
Three tools that work together: the Nashville number system for writing
|
||||
chord charts, blues scales for improvisation, and tablature for seeing
|
||||
where to put your fingers. This guide covers all three and shows how
|
||||
they connect.
|
||||
|
||||
The Nashville Number System
|
||||
---------------------------
|
||||
|
||||
The `Nashville number system <https://en.wikipedia.org/wiki/Nashville_Number_System>`_
|
||||
replaces chord names with Arabic numerals (1, 2, 3...) so that a chart
|
||||
works in **any key**. It's the standard chart format in Nashville
|
||||
recording studios — a session musician can read a number chart and
|
||||
transpose on the fly without rewriting anything.
|
||||
|
||||
The idea is simple: each number refers to a **scale degree**. In any
|
||||
major key, 1 is the tonic chord, 4 is the subdominant, 5 is the
|
||||
dominant, and so on. The chord quality (major, minor, diminished) is
|
||||
determined by the key — you don't need to write it out.
|
||||
|
||||
In C major::
|
||||
|
||||
1 = C major 5 = G major
|
||||
2 = D minor 6 = A minor
|
||||
3 = E minor 7 = B diminished
|
||||
4 = F major
|
||||
|
||||
In G major::
|
||||
|
||||
1 = G major 5 = D major
|
||||
2 = A minor 6 = E minor
|
||||
3 = B minor 7 = F# diminished
|
||||
4 = C major
|
||||
|
||||
Same numbers, different key, different chords — but the same harmonic
|
||||
relationships.
|
||||
|
||||
Using Nashville Numbers in PyTheory
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Both :class:`~pytheory.scales.Key` and :class:`~pytheory.scales.TonedScale`
|
||||
support the ``nashville()`` method:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> from pytheory import Key
|
||||
|
||||
>>> key = Key("C", "major")
|
||||
>>> [c.identify() for c in key.nashville(1, 4, 5, 1)]
|
||||
['C major', 'F major', 'G major', 'C major']
|
||||
|
||||
>>> # Same progression, different key — just change the Key
|
||||
>>> key_g = Key("G", "major")
|
||||
>>> [c.identify() for c in key_g.nashville(1, 4, 5, 1)]
|
||||
['G major', 'C major', 'D major', 'G major']
|
||||
|
||||
Nashville numbers and Roman numerals produce the same result — they're
|
||||
two notations for the same concept:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> key = Key("G", "major")
|
||||
>>> nash = [c.identify() for c in key.nashville(1, 5, 6, 4)]
|
||||
>>> roman = [c.identify() for c in key.progression("I", "V", "vi", "IV")]
|
||||
>>> nash == roman
|
||||
True
|
||||
|
||||
Seventh Chords
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
Suffix ``"7"`` to get seventh chords — essential for jazz and blues
|
||||
charts:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> key = Key("C", "major")
|
||||
>>> [c.identify() for c in key.nashville("17", "47", "57")]
|
||||
['C major 7th', 'F major 7th', 'G dominant 7th']
|
||||
|
||||
Nashville vs. Roman Numerals
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
When should you use which?
|
||||
|
||||
- **Nashville numbers** — faster to type, easier to read at a glance,
|
||||
standard in studio sessions. Use ``key.nashville(1, 4, 5, 1)``.
|
||||
- **Roman numerals** — encode chord quality (uppercase = major,
|
||||
lowercase = minor), standard in theory textbooks. Use
|
||||
``key.progression("I", "IV", "V", "I")``.
|
||||
|
||||
Both are fully supported. Use whichever fits your workflow.
|
||||
|
||||
Blues Scales
|
||||
------------
|
||||
|
||||
The `blues scale <https://en.wikipedia.org/wiki/Blues_scale>`_ is a
|
||||
six-note scale built from the minor pentatonic plus one chromatic
|
||||
passing tone — the **blue note** (flat 5th). That single added note
|
||||
gives the blues its tension and character.
|
||||
|
||||
The blues system in PyTheory includes several related scales:
|
||||
|
||||
==================== ===== ==================================
|
||||
Scale Notes Character
|
||||
==================== ===== ==================================
|
||||
minor pentatonic 5 Foundation of rock and blues soloing
|
||||
major pentatonic 5 Bright, country, pop
|
||||
blues 6 Minor pentatonic + blue note (b5)
|
||||
major blues 6 Major pentatonic + blue note (b3)
|
||||
dominant 7 Mixolydian — dominant 7th sound
|
||||
minor 7 Dorian-like — minor with natural 6th
|
||||
==================== ===== ==================================
|
||||
|
||||
Building Blues Scales
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Use ``system="blues"`` when creating a :class:`~pytheory.scales.TonedScale`:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> from pytheory import TonedScale
|
||||
|
||||
>>> c = TonedScale(tonic="C4", system="blues")
|
||||
|
||||
>>> c["minor pentatonic"].note_names
|
||||
['C', 'Eb', 'F', 'G', 'Bb', 'C']
|
||||
|
||||
>>> c["blues"].note_names
|
||||
['C', 'Eb', 'F', 'Gb', 'G', 'Bb', 'C']
|
||||
|
||||
>>> c["major pentatonic"].note_names
|
||||
['C', 'D', 'E', 'G', 'A', 'C']
|
||||
|
||||
>>> c["major blues"].note_names
|
||||
['C', 'D', 'Eb', 'E', 'G', 'A', 'C']
|
||||
|
||||
The Anatomy of a Blues Scale
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The blues scale in C::
|
||||
|
||||
C Eb F Gb G Bb C
|
||||
1 b3 4 b5 5 b7 8
|
||||
|
||||
Root ──┐
|
||||
├── minor 3rd (3 semitones)
|
||||
├── perfect 4th (5 semitones)
|
||||
├── diminished 5th (6 semitones) ← the "blue note"
|
||||
├── perfect 5th (7 semitones)
|
||||
├── minor 7th (10 semitones)
|
||||
└── octave (12 semitones)
|
||||
|
||||
The blue note (Gb/F#) sits between the 4th and 5th — a dissonant,
|
||||
unstable pitch that resolves up or down. It's what makes blues sound
|
||||
like blues.
|
||||
|
||||
The 12-Bar Blues
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
The `12-bar blues <https://en.wikipedia.org/wiki/Twelve-bar_blues>`_ is
|
||||
the most important chord progression in American music. It uses the
|
||||
Nashville numbers 1, 4, and 5::
|
||||
|
||||
| 1 | 1 | 1 | 1 |
|
||||
| 4 | 4 | 1 | 1 |
|
||||
| 5 | 4 | 1 | 5 |
|
||||
|
||||
In the key of A:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> from pytheory import Key
|
||||
|
||||
>>> key = Key("A", "major")
|
||||
>>> bars = key.nashville(1,1,1,1, 4,4,1,1, 5,4,1,5)
|
||||
>>> [c.identify() for c in bars]
|
||||
['A major', 'A major', 'A major', 'A major', 'D major', 'D major', 'A major', 'A major', 'E major', 'D major', 'A major', 'E major']
|
||||
|
||||
For an authentic blues sound, use dominant 7th chords:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> bars_7 = key.nashville("17","17","17","17", "47","47","17","17", "57","47","17","57")
|
||||
>>> [c.identify() for c in bars_7]
|
||||
['A major 7th', 'A major 7th', 'A major 7th', 'A major 7th', 'D major 7th', 'D major 7th', 'A major 7th', 'A major 7th', 'E dominant 7th', 'D major 7th', 'A major 7th', 'E dominant 7th']
|
||||
|
||||
Or use the built-in named progression:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> key = Key("A", "major")
|
||||
>>> blues = key.common_progressions()["12-bar blues"]
|
||||
>>> [c.identify() for c in blues]
|
||||
['A major', 'A major', 'A major', 'A major', 'D major', 'D major', 'A major', 'A major', 'E major', 'D major', 'A major', 'E major']
|
||||
|
||||
Blues Scale on the Fretboard
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Visualize the blues scale on guitar to see the patterns:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> from pytheory import Fretboard, TonedScale
|
||||
|
||||
>>> fb = Fretboard.guitar()
|
||||
>>> blues = TonedScale(tonic="A4", system="blues")["blues"]
|
||||
>>> print(fb.scale_diagram(blues, frets=12))
|
||||
0 1 2 3 4 5 6 7 8 9 10 11 12
|
||||
E| - | - | - | - | - | A | - | - | C | - | D | Eb| E |
|
||||
B| - | - | - | D | Eb| E | - | - | - | - | A | - | - |
|
||||
G| - | - | A | - | - | C | - | D | Eb| E | - | - | - |
|
||||
D| - | - | - | - | A | - | - | C | - | D | Eb| E | - |
|
||||
A| A | - | - | C | - | D | Eb| E | - | - | - | - | A |
|
||||
E| - | - | - | - | - | A | - | - | C | - | D | Eb| E |
|
||||
|
||||
The minor pentatonic (same scale without the Eb) is the most-played
|
||||
scale in rock guitar. Add the blue note and you have the full blues
|
||||
scale — the same shapes, one extra fret.
|
||||
|
||||
Tablature
|
||||
---------
|
||||
|
||||
`Tablature <https://en.wikipedia.org/wiki/Tablature>`_ (tab) shows
|
||||
**where to put your fingers** rather than what notes to play. Each line
|
||||
represents a string; numbers indicate fret positions. PyTheory generates
|
||||
tabs at three levels:
|
||||
|
||||
1. **Chord tabs** — single chord fingerings
|
||||
2. **Part tabs** — full melody/sequence notation
|
||||
3. **Score tabs** — extract a part from a multi-part score
|
||||
|
||||
Chord Tablature
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
Get the tab for any chord on any instrument:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> from pytheory import Fretboard
|
||||
|
||||
>>> fb = Fretboard.guitar()
|
||||
>>> print(fb.tab("C"))
|
||||
C major
|
||||
e|--0--
|
||||
B|--1--
|
||||
G|--0--
|
||||
D|--2--
|
||||
A|--3--
|
||||
E|--x--
|
||||
|
||||
>>> print(fb.tab("Am"))
|
||||
A minor
|
||||
e|--0--
|
||||
B|--1--
|
||||
G|--2--
|
||||
D|--2--
|
||||
A|--0--
|
||||
E|--x--
|
||||
|
||||
>>> print(fb.tab("E7"))
|
||||
E dominant 7th
|
||||
e|--0--
|
||||
B|--0--
|
||||
G|--1--
|
||||
D|--0--
|
||||
A|--2--
|
||||
E|--0--
|
||||
|
||||
Works with any instrument:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> uke = Fretboard.ukulele()
|
||||
>>> print(uke.tab("C"))
|
||||
C major
|
||||
A|--3--
|
||||
E|--0--
|
||||
C|--0--
|
||||
G|--0--
|
||||
|
||||
Reading Tab Notation
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
e|--0-- ← open string (don't fret, just pluck)
|
||||
B|--1-- ← press fret 1
|
||||
G|--0-- ← open string
|
||||
D|--2-- ← press fret 2
|
||||
A|--3-- ← press fret 3
|
||||
E|--x-- ← muted (don't play this string)
|
||||
|
||||
- Each line is a string (highest pitch at top, lowest at bottom)
|
||||
- Numbers are fret positions (0 = open, 1-24 = fretted)
|
||||
- ``x`` means the string is muted / not played
|
||||
- ``|`` marks measure boundaries in sequence tabs
|
||||
|
||||
Part Tablature
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Generate tab from a composed part using ``to_tab()``:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pytheory import Score, Key, Duration
|
||||
|
||||
score = Score("4/4", bpm=120)
|
||||
lead = score.part("lead", synth="saw")
|
||||
|
||||
# A simple blues lick
|
||||
for note in ["A4", "C5", "D5", "Eb5", "E5", "G5", "A5"]:
|
||||
lead.add(note, Duration.QUARTER)
|
||||
|
||||
print(lead.to_tab())
|
||||
|
||||
This outputs standard ASCII tab with measure lines, mapping each note
|
||||
to the most playable string and fret position.
|
||||
|
||||
Tuning Options
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
The ``to_tab()`` method supports multiple tunings:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# Standard guitar (default)
|
||||
lead.to_tab(tuning="guitar")
|
||||
|
||||
# 4-string bass
|
||||
lead.to_tab(tuning="bass")
|
||||
|
||||
# Drop D guitar
|
||||
lead.to_tab(tuning="drop_d")
|
||||
|
||||
# Any Fretboard object — use any of the 25+ instrument presets
|
||||
from pytheory import Fretboard
|
||||
lead.to_tab(tuning=Fretboard.mandolin())
|
||||
lead.to_tab(tuning=Fretboard.banjo())
|
||||
|
||||
# Custom tuning as MIDI note numbers (low string first)
|
||||
lead.to_tab(tuning=[40, 45, 50, 55, 59, 64])
|
||||
|
||||
Score Tablature
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
Extract tab from a multi-part score:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
score = Score("4/4", bpm=120)
|
||||
rhythm = score.part("rhythm", synth="saw")
|
||||
lead = score.part("lead", synth="triangle")
|
||||
bass = score.part("bass", synth="sine")
|
||||
|
||||
# ... compose parts ...
|
||||
|
||||
# Tab the lead part
|
||||
print(score.to_tab("lead"))
|
||||
|
||||
# Tab the first non-drum part (if no name given)
|
||||
print(score.to_tab())
|
||||
|
||||
# Bass tab
|
||||
print(score.to_tab("bass", tuning="bass"))
|
||||
|
||||
Putting It All Together
|
||||
-----------------------
|
||||
|
||||
Here's a complete example that uses all three features — Nashville
|
||||
numbers for the chord progression, the blues scale for the melody, and
|
||||
tab export to see the fingering:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pytheory import Key, TonedScale, Fretboard, Score, Duration
|
||||
|
||||
# 1. Nashville numbers for the progression
|
||||
key = Key("A", "major")
|
||||
chords = key.nashville(1, 1, 1, 1, 4, 4, 1, 1, 5, 4, 1, 5)
|
||||
|
||||
# 2. Blues scale for the melody
|
||||
blues = TonedScale(tonic="A4", system="blues")["blues"]
|
||||
|
||||
# 3. Compose a score
|
||||
score = Score("4/4", bpm=120)
|
||||
rhythm = score.part("rhythm", synth="saw", envelope="pad")
|
||||
lead = score.part("lead", synth="triangle", envelope="pluck")
|
||||
|
||||
for chord in chords:
|
||||
rhythm.add(chord, Duration.WHOLE)
|
||||
|
||||
for note_name in blues.note_names[:-1]: # walk up the scale
|
||||
lead.add(f"{note_name}4", Duration.HALF)
|
||||
|
||||
# 4. See it as tablature
|
||||
print(lead.to_tab())
|
||||
|
||||
# 5. See the scale on the fretboard
|
||||
fb = Fretboard.guitar()
|
||||
print(fb.scale_diagram(blues, frets=12))
|
||||
|
||||
Nashville numbers tell you *what chords to play*. The blues scale tells you *what notes to solo with*. Tablature tells you *where to put your fingers*. Together, they're everything you need to play the blues.
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user