diff --git a/docs/guide/cli.rst b/docs/guide/cli.rst
index b52c7ba..8c82cce 100644
--- a/docs/guide/cli.rst
+++ b/docs/guide/cli.rst
@@ -1,7 +1,20 @@
Command-Line Interface
======================
-PyTheory includes a CLI for quick music theory lookups from the terminal.
+PyTheory includes a CLI for music theory lookups, composition, and
+playback — all from the terminal.
+
+Demo
+----
+
+The fastest way to hear what PyTheory can do. Generates and plays a
+random multi-part track — different every time::
+
+ $ pytheory demo
+ ♫ Jazz Club
+ Bb major | 105 bpm
+ Bb → Gm → Cm → F
+ jazz drums | saw lead | fm pad
Tone Lookup
-----------
diff --git a/docs/guide/cookbook.rst b/docs/guide/cookbook.rst
index 9c58793..c6757f6 100644
--- a/docs/guide/cookbook.rst
+++ b/docs/guide/cookbook.rst
@@ -364,3 +364,166 @@ the most-played scale in rock:
D| D | - | E | - | - | G | - | A | - | B | - | - | D |
A| A | - | B | - | - | D | - | E | - | - | G | - | A |
E| E | - | - | G | - | A | - | B | - | - | D | - | E |
+
+Composition Recipes
+-------------------
+
+These recipes go beyond theory into actual music-making.
+
+Acid House Track
+~~~~~~~~~~~~~~~~
+
+303-style acid with sidechain pump:
+
+.. code-block:: python
+
+ from pytheory import Score, Pattern, Duration, Chord
+ from pytheory.play import play_score
+
+ score = Score("4/4", bpm=132)
+ score.drums("house", repeats=8, fill="house", fill_every=8)
+
+ pad = score.part(
+ "pad",
+ synth="supersaw",
+ envelope="pad",
+ reverb=0.4,
+ chorus=0.3,
+ sidechain=0.85,
+ )
+ acid = score.part(
+ "acid",
+ synth="saw",
+ envelope="pad",
+ legato=True,
+ glide=0.03,
+ distortion=0.8,
+ distortion_drive=8.0,
+ lowpass=1000,
+ lowpass_q=5.0,
+ )
+ acid.lfo("lowpass", rate=0.5, min=600, max=2500, bars=8)
+
+ for sym in ["Cm", "Fm", "Abm", "Gm"]:
+ pad.add(Chord.from_symbol(sym), Duration.WHOLE)
+ pad.add(Chord.from_symbol(sym), Duration.WHOLE)
+ acid.arpeggio(sym, bars=2, pattern="up", octaves=2)
+
+ play_score(score)
+
+Dub Reggae with Delay Madness
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Sparse notes into infinite echo:
+
+.. code-block:: python
+
+ score = Score("4/4", bpm=72)
+ score.drums("dub", repeats=8)
+
+ melodica = score.part(
+ "melodica",
+ synth="triangle",
+ envelope="pluck",
+ delay=0.5,
+ delay_time=0.66,
+ delay_feedback=0.55,
+ reverb=0.4,
+ reverb_type="cathedral",
+ )
+ bass = score.part("bass", synth="sine", lowpass=400, lowpass_q=1.5)
+
+ # Play almost nothing — let the delay do the work
+ melodica.add("A4", 2).rest(6)
+ melodica.add("E5", 1.5).rest(6.5)
+ melodica.add("D5", 1).add("C5", 1).add("A4", 2).rest(4)
+
+ for n in ["A1"] * 16:
+ bass.add(n, Duration.HALF)
+
+ play_score(score)
+
+Jazz Ballad with Humanize
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The difference between a robot and a musician:
+
+.. code-block:: python
+
+ score = Score("4/4", bpm=72, swing=0.5)
+ score.drums("jazz", repeats=8)
+
+ rhodes = score.part(
+ "rhodes",
+ synth="fm",
+ envelope="piano",
+ reverb=0.4,
+ reverb_type="plate",
+ humanize=0.3,
+ )
+ lead = score.part(
+ "lead",
+ synth="triangle",
+ envelope="strings",
+ delay=0.25,
+ reverb=0.3,
+ humanize=0.35,
+ )
+
+ key = Key("Bb", "major")
+ for chord in key.progression("I", "vi", "ii", "V") * 2:
+ rhodes.add(chord, Duration.WHOLE)
+
+ for n, d in [("D5", 1.5), ("F5", 0.5), ("Bb5", 2), (None, 4),
+ ("A5", 1), ("G5", 1), ("F5", 2), (None, 4)]:
+ lead.rest(d) if n is None else lead.add(n, d)
+
+ play_score(score)
+
+Song with Sections
+~~~~~~~~~~~~~~~~~~~
+
+Define once, arrange freely:
+
+.. code-block:: python
+
+ score = Score("4/4", bpm=120)
+ score.drums("rock", repeats=16, fill="rock", fill_every=4)
+
+ chords = score.part("chords", synth="saw", envelope="pad")
+ lead = score.part("lead", synth="triangle", envelope="pluck")
+
+ score.section("verse")
+ for sym in ["Am", "F", "C", "G"]:
+ chords.add(Chord.from_symbol(sym), Duration.WHOLE)
+ lead.add("A4", 1).add("C5", 1).add("E5", 1).rest(1)
+ lead.add("F5", 1).add("E5", 1).add("C5", 2)
+
+ score.section("chorus")
+ lead.set(reverb=0.4, lowpass=5000)
+ for sym in ["F", "G", "Am", "C"]:
+ chords.add(Chord.from_symbol(sym), Duration.WHOLE)
+ lead.add("C6", 2).add("A5", 1).add("G5", 1)
+ lead.add("F5", 2).add("E5", 2)
+ score.end_section()
+
+ score.repeat("verse")
+ score.repeat("chorus", times=2)
+
+ play_score(score)
+ score.save_midi("my_song.mid")
+
+Export Everything to MIDI
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The whole point — sketch fast, finish in your DAW:
+
+.. code-block:: python
+
+ # Any Score can be saved as MIDI
+ score.save_midi("track.mid")
+
+ # Simple progressions too
+ from pytheory import save_midi
+ chords = Key("C", "major").progression("I", "V", "vi", "IV")
+ save_midi(chords, "pop.mid", t=500, bpm=120)
diff --git a/docs/guide/quickstart.rst b/docs/guide/quickstart.rst
index 2afe72f..833a8ee 100644
--- a/docs/guide/quickstart.rst
+++ b/docs/guide/quickstart.rst
@@ -1,6 +1,8 @@
Quickstart
==========
+From zero to a multi-part arrangement in 5 minutes.
+
Installation
------------
@@ -8,200 +10,162 @@ Installation
$ pip install pytheory
-For audio playback, you'll also need `PortAudio `_:
+For audio playback through your speakers, you'll also need
+`PortAudio `_:
- macOS: ``brew install portaudio``
- Ubuntu: ``apt install libportaudio2``
- Windows: included with the ``sounddevice`` package
-Tones
------
+PortAudio is only needed for live playback. MIDI export, WAV export,
+and all theory functions work without it.
-A :class:`~pytheory.tones.Tone` is a single musical note:
+Hear Something Immediately
+--------------------------
+
+::
+
+ $ pytheory demo
+
+This generates and plays a random track — different every time. It's
+the fastest way to hear what PyTheory can do.
+
+Explore Music Theory
+--------------------
+
+The theory layer is where most people start. Every concept in Western
+music theory (and five other systems) has a clean Python API:
.. code-block:: pycon
- >>> from pytheory import Tone
+ >>> from pytheory import Key, Chord, Tone
- >>> a4 = Tone.from_string("A4", system="western")
- >>> a4.frequency
- 440.0
+ >>> key = Key("C", "major")
+ >>> key.chords
+ ['C major', 'D minor', 'E minor', 'F major', 'G major', 'A minor', 'B diminished']
- >>> c4 = Tone.from_string("C4", system="western")
- >>> c4.midi
- 60
+ >>> [c.symbol for c in key.progression("I", "V", "vi", "IV")]
+ ['C', 'G', 'Am', 'F']
- >>> Tone.from_frequency(440)
-
- >>> Tone.from_midi(60)
-
+ >>> Chord.from_symbol("Am7").identify()
+ 'A minor 7th'
- >>> c4 + 4
-
- >>> c4 + 7
-
-
- >>> g4 = c4 + 7
- >>> g4 - c4
- 7
- >>> c4.interval_to(g4)
+ >>> Tone.from_string("C4").interval_to(Tone.from_string("G4"))
'perfect 5th'
- >>> Tone.from_string("C#4", system="western").enharmonic
- 'Db'
+ >>> Key("C", "major").pivot_chords(Key("G", "major"))
+ ['A minor', 'B minor', 'C major', 'D major', 'E minor', 'G major']
-Scales
-------
-
-Build scales in any key and mode:
-
-.. code-block:: pycon
-
- >>> from pytheory import TonedScale
-
- >>> c = TonedScale(tonic="C4")
-
- >>> c["major"].note_names
- ['C', 'D', 'E', 'F', 'G', 'A', 'B', 'C']
-
- >>> c["minor"].note_names
- ['C', 'D', 'Eb', 'F', 'G', 'Ab', 'Bb', 'C']
-
- >>> c["dorian"].note_names
- ['C', 'D', 'Eb', 'F', 'G', 'A', 'Bb', 'C']
-
- >>> major = c["major"]
- >>> major["tonic"]
- C4
- >>> major["dominant"]
- G4
- >>> major["V"]
- G4
-
-Keys and Chords
+Compose a Track
---------------
-The :class:`~pytheory.scales.Key` class ties everything together —
-scales, chords, and progressions:
+This is where it gets fun. A ``Score`` is your arrangement — drums,
+chords, melody, bass, each with their own synth and effects:
-.. code-block:: pycon
+.. code-block:: python
- >>> from pytheory import Key
+ from pytheory import Score, Pattern, Key, Duration, Chord
+ from pytheory.play import play_score
- >>> key = Key("G", "major")
- >>> key.note_names
- ['G', 'A', 'B', 'C', 'D', 'E', 'F#', 'G']
+ score = Score("4/4", bpm=140)
+ score.drums("bossa nova", repeats=4)
- >>> key.chords
- ['G major', 'A minor', 'B minor', 'C major', 'D major', 'E minor', 'F# diminished']
+ chords = score.part(
+ "chords",
+ synth="fm",
+ envelope="pad",
+ reverb=0.4,
+ )
+ lead = score.part(
+ "lead",
+ synth="saw",
+ envelope="pluck",
+ delay=0.3,
+ lowpass=3000,
+ humanize=0.2,
+ )
+ bass = score.part(
+ "bass",
+ synth="sine",
+ lowpass=500,
+ )
- >>> chords = key.progression("I", "V", "vi", "IV")
- >>> [c.identify() for c in chords]
- ['G major', 'D major', 'E minor', 'C major']
+ key = Key("A", "minor")
+ for chord in key.progression("i", "iv", "V", "i"):
+ chords.add(chord, Duration.WHOLE)
+ chords.add(chord, Duration.WHOLE)
- >>> Key.detect("C", "E", "G", "A", "D")
-
+ lead.arpeggio("Am", bars=2, pattern="updown", octaves=2)
+ lead.arpeggio("Dm", bars=2, pattern="updown", octaves=2)
+ lead.set(lowpass=5000, reverb=0.3)
+ lead.arpeggio("E7", bars=2, pattern="up", octaves=2)
+ lead.arpeggio("Am", bars=2, pattern="updown", octaves=2)
-Build chords directly:
+ for n in ["A2", "E2", "A2", "C3"] * 4:
+ bass.add(n, Duration.QUARTER)
-.. code-block:: pycon
+ play_score(score)
- >>> from pytheory import Chord
+Export to Your DAW
+------------------
- >>> Chord.from_tones("C", "E", "G")
-
- >>> Chord.from_name("Am7")
-
- >>> Chord.from_intervals("G", 4, 7, 10)
-
+The whole point: sketch in Python, finish in Logic / Ableton / Reaper.
- >>> Chord.from_tones("Bb", "D", "F").identify()
- 'Bb major'
+.. code-block:: python
- >>> Chord.from_name("G7").analyze("C")
- 'V7'
+ score.save_midi("my_sketch.mid")
-Guitar Fingerings
+Open that file in any DAW and you'll see all the notes laid out on
+the timeline, ready to assign to real instruments and mix.
+
+You can also save rendered audio:
+
+.. code-block:: python
+
+ from pytheory import save
+ save(Chord.from_symbol("Am7"), "am7.wav", t=2_000)
+
+What's in the Box
-----------------
-.. code-block:: pycon
+**Theory** — tones, scales (40+ across 6 musical systems), chords
+(17 types, Roman numeral analysis, tension scoring, voice leading),
+keys (detection, signatures, modulation paths, borrowed chords).
- >>> from pytheory import Fretboard
+**Sequencing** — Score, Part, Duration, TimeSignature. Arpeggiator
+with 5 patterns. Legato with pitch glide. Per-note velocity. Swing.
+Tempo changes. Fade in/out. Song sections with repeat. Humanize.
- >>> fb = Fretboard.guitar()
+**Synthesis** — 10 waveforms: sine, saw, triangle, square, pulse, FM,
+noise, supersaw, PWM slow, PWM fast. 8 ADSR envelopes.
- >>> fb.chord("C")
- Fingering(e=0, B=1, G=0, D=2, A=3, E=x)
+**Effects** — distortion, chorus, lowpass filter (with resonance),
+delay, reverb (algorithmic + 7 convolution presets including
+Taj Mahal with 12-second tail). All per-part with automation and
+LFO modulation. Sidechain compression.
- >>> fb.chord("C")['A']
- 3
+**Drums** — 58 pattern presets (rock, jazz, salsa, bossa nova,
+afrobeat, house, trap, and 50+ more). 21 fill presets. 27 synthesized
+drum voices.
- >>> fb.fingering(0, 0, 0, 2, 2, 0).identify()
- 'E minor'
+**Instruments** — 25 presets (guitar with 8 tunings, bass, ukulele,
+mandolin family, violin family, banjo, harp, oud, sitar, erhu, and
+more) with chord fingering generation and scale diagrams.
- >>> print(fb.tab("Am"))
- A minor
- e|--0--
- B|--1--
- G|--2--
- D|--2--
- A|--0--
- E|--x--
+**Export** — MIDI, WAV, real-time playback.
- >>> from pytheory import Scale
- >>> pentatonic = Scale(tonic="A4", system="blues")["minor pentatonic"]
- >>> print(fb.scale_diagram(pentatonic, frets=5))
- 0 1 2 3 4 5
- E| E | - | - | G | - | A |
- B| - | C | - | D | - | E |
- G| G | - | A | - | - | C |
- D| D | - | E | - | - | G |
- A| A | - | - | C | - | D |
- E| E | - | - | G | - | A |
+**CLI** — ``pytheory demo``, ``pytheory key``, ``pytheory chord``,
+``pytheory identify``, ``pytheory midi``, ``pytheory play``, and more.
-Audio Playback
---------------
+Where to Go Next
+-----------------
-.. code-block:: pycon
-
- >>> from pytheory import Tone, Chord, play, save, Synth
-
- >>> play(Tone.from_string("A4"), t=1_000)
-
- >>> play(Chord.from_name("Am7"), synth=Synth.TRIANGLE, t=2_000)
-
- >>> save(Chord.from_name("C"), "c_major.wav", t=2_000)
-
-Command Line
-------------
-
-PyTheory also works from the terminal::
-
- $ pytheory tone A4
- $ pytheory chord C E G
- $ pytheory key G major
- $ pytheory scale C dorian
- $ pytheory fingering Am
- $ pytheory progression C major I V vi IV
- $ pytheory detect C E G A D
- $ pytheory play Am7 --synth triangle
-
-What's Included
----------------
-
-- **6 musical systems**: Western, Indian (Hindustani), Arabic (Maqam),
- Japanese, Blues/Pentatonic, Javanese Gamelan
-- **40+ scales**: major, minor, harmonic minor, 7 modes, 10 thaats,
- 10 maqamat, 6 Japanese pentatonic scales, blues, pentatonic,
- slendro, pelog, and more
-- **Pitch calculation** in equal, Pythagorean, and meantone temperaments
-- **Chord identification**: name any chord from its notes, intervals, or
- MIDI numbers (17 chord types recognized)
-- **Chord charts** with 144 pre-built chords (12 roots x 12 qualities)
-- **Chord analysis**: consonance scoring, Plomp-Levelt dissonance,
- beat frequency calculation, harmonic tension, voice leading
-- **Key detection** and **Roman numeral analysis** (I-IV-V-I progressions)
-- **Fingering generation** for 25 instruments with labeled string names,
- including guitar (8 tunings), bass, ukulele, mandolin, and more
-- **Audio playback** with sine, sawtooth, and triangle wave synthesis
-- **WAV export** for saving rendered audio to disk
+- :doc:`theory` — music theory fundamentals
+- :doc:`tones` — working with individual notes
+- :doc:`scales` — scales, modes, and keys
+- :doc:`chords` — chord construction, analysis, and progressions
+- :doc:`sequencing` — composing multi-part arrangements
+- :doc:`synths` — the 10 waveforms and 8 envelopes
+- :doc:`effects` — reverb, delay, distortion, chorus, lowpass, automation
+- :doc:`drums` — 58 patterns, 21 fills, drum synthesis
+- :doc:`playback` — play, save, export