mirror of
https://github.com/kennethreitz/pytheory.git
synced 2026-06-05 06:46:14 +00:00
Merge pull request #48 from kennethreitz/docs-audio
Audio samples in documentation
This commit is contained in:
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.
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
+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>
|
||||
@@ -0,0 +1,440 @@
|
||||
"""Generate audio samples for documentation.
|
||||
|
||||
Renders code examples from the docs as WAV files so they can be
|
||||
embedded as <audio> players on the website.
|
||||
|
||||
Usage:
|
||||
uv run python docs/generate_audio.py
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
|
||||
|
||||
from pytheory import Score, Duration, Key, Chord, Fretboard, DrumSound
|
||||
from pytheory.play import render_score, SAMPLE_RATE
|
||||
|
||||
import numpy
|
||||
import struct
|
||||
|
||||
AUDIO_DIR = os.path.join(os.path.dirname(__file__), "_static", "audio")
|
||||
os.makedirs(AUDIO_DIR, exist_ok=True)
|
||||
|
||||
|
||||
def save_wav(buf, path):
|
||||
"""Save a float32 buffer as 16-bit WAV."""
|
||||
# Normalize
|
||||
peak = numpy.abs(buf).max()
|
||||
if peak > 0:
|
||||
buf = buf / peak * 0.9
|
||||
samples = (buf * 32767).astype(numpy.int16)
|
||||
with open(path, "wb") as f:
|
||||
n = len(samples)
|
||||
f.write(b"RIFF")
|
||||
f.write(struct.pack("<I", 36 + n * 2))
|
||||
f.write(b"WAVE")
|
||||
f.write(b"fmt ")
|
||||
f.write(struct.pack("<IHHIIHH", 16, 1, 1, SAMPLE_RATE, SAMPLE_RATE * 2, 2, 16))
|
||||
f.write(b"data")
|
||||
f.write(struct.pack("<I", n * 2))
|
||||
f.write(samples.tobytes())
|
||||
print(f" {os.path.basename(path)} ({len(buf)/SAMPLE_RATE:.1f}s)")
|
||||
|
||||
|
||||
def render(name, score):
|
||||
"""Render a score to WAV in the audio directory."""
|
||||
buf = render_score(score)
|
||||
save_wav(buf, os.path.join(AUDIO_DIR, f"{name}.wav"))
|
||||
|
||||
|
||||
# ── Piano hold (polyphonic overlap) ──────────────────────────────────────
|
||||
|
||||
def gen_piano_hold():
|
||||
score = Score("4/4", bpm=85)
|
||||
piano = score.part("piano", instrument="piano", reverb=0.3)
|
||||
piano.hold("C3", Duration.WHOLE * 2, velocity=60)
|
||||
piano.hold("E3", Duration.WHOLE * 2, velocity=55)
|
||||
piano.hold("G3", Duration.WHOLE * 2, velocity=55)
|
||||
for n in ["E4", "G4", "C5", "G4", "E4", "D4", "C4", "E4"]:
|
||||
piano.add(n, Duration.QUARTER, velocity=80)
|
||||
render("piano_hold", score)
|
||||
|
||||
|
||||
# ── Articulations ────────────────────────────────────────────────────────
|
||||
|
||||
def gen_articulations():
|
||||
score = Score("4/4", bpm=90)
|
||||
piano = score.part("piano", instrument="piano", reverb=0.25)
|
||||
for n in ["C4", "E4", "G4", "C5"]:
|
||||
piano.add(n, Duration.QUARTER, velocity=80)
|
||||
for n in ["C4", "E4", "G4", "C5"]:
|
||||
piano.add(n, Duration.QUARTER, velocity=80, articulation="staccato")
|
||||
for n in ["C5", "G4", "E4", "C4"]:
|
||||
piano.add(n, Duration.QUARTER, velocity=80, articulation="legato")
|
||||
for n in ["C4", "E4", "G4", "C5"]:
|
||||
piano.add(n, Duration.QUARTER, velocity=80, articulation="marcato")
|
||||
render("articulations", score)
|
||||
|
||||
|
||||
# ── Dynamic curves ───────────────────────────────────────────────────────
|
||||
|
||||
def gen_dynamics():
|
||||
score = Score("4/4", bpm=90)
|
||||
piano = score.part("piano", instrument="piano", reverb=0.3)
|
||||
piano.crescendo(["C4", "D4", "E4", "F4", "G4", "A4", "B4", "C5"],
|
||||
Duration.QUARTER, start_vel=30, end_vel=110)
|
||||
piano.decrescendo(["C5", "B4", "A4", "G4", "F4", "E4", "D4", "C4"],
|
||||
Duration.QUARTER, start_vel=110, end_vel=30)
|
||||
render("dynamics", score)
|
||||
|
||||
|
||||
# ── Filter ramp ──────────────────────────────────────────────────────────
|
||||
|
||||
def gen_filter_ramp():
|
||||
score = Score("4/4", bpm=130)
|
||||
score.drums("house", repeats=8, fill="house", fill_every=8)
|
||||
score.set_drum_effects(volume=0.4)
|
||||
acid = score.part("acid", synth="saw", volume=0.6,
|
||||
lowpass=300, lowpass_q=8.0, distortion=0.3,
|
||||
legato=True, glide=0.03)
|
||||
acid.ramp(over=Duration.WHOLE * 4, curve="ease_in", lowpass=5000)
|
||||
for _ in range(4):
|
||||
for n in ["C2", "C3", "C2", "Eb2", "C2", "G2", "Bb2", "C2"]:
|
||||
acid.add(n, Duration.EIGHTH, velocity=90)
|
||||
acid.ramp(over=Duration.WHOLE * 4, curve="ease_out", lowpass=300)
|
||||
for _ in range(4):
|
||||
for n in ["C2", "C3", "C2", "Eb2", "C2", "G2", "Bb2", "C2"]:
|
||||
acid.add(n, Duration.EIGHTH, velocity=88)
|
||||
render("filter_ramp", score)
|
||||
|
||||
|
||||
# ── Rock beat ────────────────────────────────────────────────────────────
|
||||
|
||||
def gen_rock_beat():
|
||||
score = Score("4/4", bpm=120)
|
||||
score.drums("rock", repeats=4, fill="rock", fill_every=4)
|
||||
render("rock_beat", score)
|
||||
|
||||
|
||||
# ── Bossa nova ───────────────────────────────────────────────────────────
|
||||
|
||||
def gen_bossa_nova():
|
||||
score = Score("4/4", bpm=140)
|
||||
score.drums("bossa nova", repeats=4)
|
||||
rhodes = score.part("rhodes", synth="fm", envelope="piano", volume=0.3,
|
||||
reverb=0.4, reverb_decay=1.8)
|
||||
for sym in ["Am", "Am", "Dm", "Dm", "E7", "E7", "Am", "Am"]:
|
||||
rhodes.add(Chord.from_symbol(sym), Duration.WHOLE)
|
||||
render("bossa_nova", score)
|
||||
|
||||
|
||||
# ── Djembe ───────────────────────────────────────────────────────────────
|
||||
|
||||
def gen_djembe():
|
||||
score = Score("4/4", bpm=110)
|
||||
score.drums("tiriba", repeats=4, fill="djembe call", fill_every=4)
|
||||
score.set_drum_effects(reverb=0.2)
|
||||
render("djembe", score)
|
||||
|
||||
|
||||
# ── Tabla ────────────────────────────────────────────────────────────────
|
||||
|
||||
def gen_tabla():
|
||||
score = Score("4/4", bpm=80)
|
||||
score.drums("teental", repeats=2)
|
||||
score.drums("chakradar", repeats=1)
|
||||
score.set_drum_effects(reverb=0.2)
|
||||
render("tabla", score)
|
||||
|
||||
|
||||
# ── Marching snare ───────────────────────────────────────────────────────
|
||||
|
||||
def gen_march_snare():
|
||||
score = Score("4/4", bpm=120)
|
||||
p = score.part("snare", synth="sine", volume=0.8, reverb=0.15)
|
||||
S = DrumSound.MARCH_SNARE
|
||||
R = DrumSound.MARCH_RIMSHOT
|
||||
C = DrumSound.MARCH_CLICK
|
||||
|
||||
for _ in range(4):
|
||||
p.hit(C, Duration.QUARTER, velocity=95)
|
||||
|
||||
for _ in range(4):
|
||||
p.hit(R, Duration.SIXTEENTH, velocity=118)
|
||||
p.hit(S, Duration.SIXTEENTH, velocity=30)
|
||||
p.hit(S, Duration.SIXTEENTH, velocity=32)
|
||||
p.hit(S, Duration.SIXTEENTH, velocity=28)
|
||||
p.hit(R, Duration.SIXTEENTH, velocity=115)
|
||||
p.hit(S, Duration.SIXTEENTH, velocity=30)
|
||||
p.hit(S, Duration.SIXTEENTH, velocity=28)
|
||||
p.hit(S, Duration.SIXTEENTH, velocity=32)
|
||||
p.hit(R, Duration.SIXTEENTH, velocity=118)
|
||||
p.hit(S, Duration.SIXTEENTH, velocity=35)
|
||||
p.hit(S, Duration.SIXTEENTH, velocity=28)
|
||||
p.hit(S, Duration.SIXTEENTH, velocity=30)
|
||||
p.hit(R, Duration.SIXTEENTH, velocity=120)
|
||||
p.hit(S, Duration.SIXTEENTH, velocity=30)
|
||||
p.hit(S, Duration.SIXTEENTH, velocity=28)
|
||||
p.hit(S, Duration.SIXTEENTH, velocity=32)
|
||||
render("march_snare", score)
|
||||
|
||||
|
||||
# ── Ensemble comparison ──────────────────────────────────────────────────
|
||||
|
||||
def gen_ensemble():
|
||||
score = Score("4/4", bpm=120)
|
||||
S = DrumSound.MARCH_SNARE
|
||||
R = DrumSound.MARCH_RIMSHOT
|
||||
|
||||
# Solo first
|
||||
solo = score.part("solo", synth="sine", volume=0.7, reverb=0.15)
|
||||
for _ in range(2):
|
||||
solo.hit(R, Duration.SIXTEENTH, velocity=118)
|
||||
solo.hit(S, Duration.SIXTEENTH, velocity=30)
|
||||
solo.hit(S, Duration.SIXTEENTH, velocity=32)
|
||||
solo.hit(S, Duration.SIXTEENTH, velocity=28)
|
||||
solo.hit(R, Duration.SIXTEENTH, velocity=115)
|
||||
solo.hit(S, Duration.SIXTEENTH, velocity=30)
|
||||
solo.hit(S, Duration.SIXTEENTH, velocity=28)
|
||||
solo.hit(S, Duration.SIXTEENTH, velocity=32)
|
||||
solo.hit(R, Duration.SIXTEENTH, velocity=118)
|
||||
solo.hit(S, Duration.SIXTEENTH, velocity=35)
|
||||
solo.hit(S, Duration.SIXTEENTH, velocity=28)
|
||||
solo.hit(S, Duration.SIXTEENTH, velocity=30)
|
||||
solo.hit(R, Duration.SIXTEENTH, velocity=120)
|
||||
solo.hit(S, Duration.SIXTEENTH, velocity=30)
|
||||
solo.hit(S, Duration.SIXTEENTH, velocity=28)
|
||||
solo.hit(S, Duration.SIXTEENTH, velocity=32)
|
||||
|
||||
# Then ensemble
|
||||
line = score.part("line", synth="sine", volume=0.7, reverb=0.15, ensemble=8)
|
||||
for _ in range(8):
|
||||
line.rest(Duration.QUARTER)
|
||||
for _ in range(4):
|
||||
line.hit(R, Duration.SIXTEENTH, velocity=118)
|
||||
line.hit(S, Duration.SIXTEENTH, velocity=30)
|
||||
line.hit(S, Duration.SIXTEENTH, velocity=32)
|
||||
line.hit(S, Duration.SIXTEENTH, velocity=28)
|
||||
line.hit(R, Duration.SIXTEENTH, velocity=115)
|
||||
line.hit(S, Duration.SIXTEENTH, velocity=30)
|
||||
line.hit(S, Duration.SIXTEENTH, velocity=28)
|
||||
line.hit(S, Duration.SIXTEENTH, velocity=32)
|
||||
line.hit(R, Duration.SIXTEENTH, velocity=118)
|
||||
line.hit(S, Duration.SIXTEENTH, velocity=35)
|
||||
line.hit(S, Duration.SIXTEENTH, velocity=28)
|
||||
line.hit(S, Duration.SIXTEENTH, velocity=30)
|
||||
line.hit(R, Duration.SIXTEENTH, velocity=120)
|
||||
line.hit(S, Duration.SIXTEENTH, velocity=30)
|
||||
line.hit(S, Duration.SIXTEENTH, velocity=28)
|
||||
line.hit(S, Duration.SIXTEENTH, velocity=32)
|
||||
render("ensemble", score)
|
||||
|
||||
|
||||
# ── Guitar strum ─────────────────────────────────────────────────────────
|
||||
|
||||
def gen_strum():
|
||||
score = Score("4/4", bpm=100)
|
||||
guitar = score.part("guitar", instrument="acoustic_guitar",
|
||||
fretboard=Fretboard.guitar())
|
||||
for ch in ["G", "D", "Em", "C"] * 2:
|
||||
guitar.strum(ch, duration=Duration.WHOLE, velocity=75)
|
||||
render("strum", score)
|
||||
|
||||
|
||||
# ── Swell ────────────────────────────────────────────────────────────────
|
||||
|
||||
def gen_swell():
|
||||
score = Score("4/4", bpm=80)
|
||||
strings = score.part("strings", instrument="string_ensemble",
|
||||
reverb=0.4, ensemble=12)
|
||||
strings.swell(["C4", "D4", "E4", "F4", "G4", "F4", "E4", "D4",
|
||||
"C4", "D4", "E4", "F4", "G4", "A4", "G4", "E4"],
|
||||
Duration.QUARTER, low_vel=30, peak_vel=100)
|
||||
render("swell", score)
|
||||
|
||||
|
||||
# ── Generate all ─────────────────────────────────────────────────────────
|
||||
|
||||
# ── Cookbook: Acid House ───────────────────────────────────────────────────
|
||||
|
||||
def gen_acid_house():
|
||||
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)
|
||||
render("acid_house", score)
|
||||
|
||||
|
||||
# ── Cookbook: Dub Reggae ──────────────────────────────────────────────────
|
||||
|
||||
def gen_dub_reggae():
|
||||
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)
|
||||
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 _ in range(16):
|
||||
bass.add("A1", Duration.HALF)
|
||||
render("dub_reggae", score)
|
||||
|
||||
|
||||
# ── Cookbook: Jazz Ballad ─────────────────────────────────────────────────
|
||||
|
||||
def gen_jazz_ballad():
|
||||
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)
|
||||
render("jazz_ballad", score)
|
||||
|
||||
|
||||
# ── Quickstart example ───────────────────────────────────────────────────
|
||||
|
||||
def gen_quickstart():
|
||||
score = Score("4/4", bpm=140)
|
||||
score.drums("bossa nova", repeats=4)
|
||||
chords = score.part("chords", synth="sine", envelope="pad",
|
||||
reverb=0.4, volume=0.3)
|
||||
lead = score.part("lead", synth="saw", envelope="pluck",
|
||||
lowpass=2000, lowpass_q=3.0, distortion=0.8,
|
||||
legato=True, glide=0.03, volume=0.4)
|
||||
bass = score.part("bass", synth="sine", lowpass=500)
|
||||
key = Key("A", "minor")
|
||||
for chord in key.progression("i", "iv", "V", "i"):
|
||||
chords.add(chord, Duration.WHOLE)
|
||||
chords.add(chord, Duration.WHOLE)
|
||||
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)
|
||||
for n in ["A2", "E2", "A2", "C3"] * 4:
|
||||
bass.add(n, Duration.QUARTER)
|
||||
render("quickstart", score)
|
||||
|
||||
|
||||
# ── Sequencing complete example (bossa nova) ─────────────────────────────
|
||||
|
||||
def gen_sequencing_bossa():
|
||||
score = Score("4/4", bpm=140)
|
||||
score.drums("bossa nova", repeats=4)
|
||||
rhodes = score.part("rhodes", synth="fm", envelope="piano", volume=0.3,
|
||||
reverb=0.4, reverb_decay=1.8)
|
||||
lead = score.part("lead", synth="triangle", envelope="pluck", volume=0.45,
|
||||
delay=0.25, delay_time=0.32, delay_feedback=0.35, reverb=0.2)
|
||||
bass = score.part("bass", synth="sine", envelope="pluck", volume=0.45,
|
||||
lowpass=600)
|
||||
for sym in ["Am", "Am", "Dm", "Dm", "E7", "E7", "Am", "Am"]:
|
||||
rhodes.add(Chord.from_symbol(sym), Duration.WHOLE)
|
||||
for n, d in [("E5", 0.67), ("D5", 0.33), ("C5", 0.67), ("B4", 0.33),
|
||||
("A4", 1), ("C5", 0.67), ("E5", 0.33), ("D5", 0.67),
|
||||
("C5", 0.33), ("A4", 1)]:
|
||||
lead.add(n, d)
|
||||
for n in ["A2", "E2", "A2", "C3", "D2", "A2", "D2", "F2"]:
|
||||
bass.add(n, Duration.QUARTER)
|
||||
render("sequencing_bossa", score)
|
||||
|
||||
|
||||
# ── Drums layering (salsa) ───────────────────────────────────────────────
|
||||
|
||||
def gen_salsa_layered():
|
||||
score = Score("4/4", bpm=180)
|
||||
score.drums("salsa", repeats=4, fill="salsa", fill_every=4)
|
||||
pads = score.part("pads", synth="sine", envelope="pad", volume=0.3)
|
||||
lead = score.part("lead", synth="saw", envelope="pluck", volume=0.4)
|
||||
bass = score.part("bass", synth="sine", envelope="pluck", volume=0.45)
|
||||
for chord in Key("D", "minor").progression("ii", "V", "i", "i") * 2:
|
||||
pads.add(chord, Duration.WHOLE)
|
||||
lead.add("A5", 0.67).add("G5", 0.33).add("F5", 0.67).add("E5", 0.33)
|
||||
for n in ["D2", "A2", "D2", "F2"] * 2:
|
||||
bass.add(n, Duration.QUARTER)
|
||||
render("salsa_layered", score)
|
||||
|
||||
|
||||
# ── Playback basic ───────────────────────────────────────────────────────
|
||||
|
||||
def gen_playback_basic():
|
||||
score = Score("4/4", bpm=140)
|
||||
score.drums("bossa nova", repeats=4)
|
||||
chords = score.part("chords", synth="sine", envelope="pad")
|
||||
for sym in ["Am", "Dm", "E7", "Am"]:
|
||||
chords.add(Chord.from_symbol(sym), Duration.WHOLE)
|
||||
render("playback_basic", score)
|
||||
|
||||
|
||||
# ── Cookbook: song with sections ──────────────────────────────────────────
|
||||
|
||||
def gen_song_sections():
|
||||
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)
|
||||
render("song_sections", score)
|
||||
|
||||
|
||||
GENERATORS = [
|
||||
gen_piano_hold,
|
||||
gen_articulations,
|
||||
gen_dynamics,
|
||||
gen_filter_ramp,
|
||||
gen_rock_beat,
|
||||
gen_bossa_nova,
|
||||
gen_djembe,
|
||||
gen_tabla,
|
||||
gen_march_snare,
|
||||
gen_ensemble,
|
||||
gen_strum,
|
||||
gen_swell,
|
||||
gen_acid_house,
|
||||
gen_dub_reggae,
|
||||
gen_jazz_ballad,
|
||||
gen_quickstart,
|
||||
gen_sequencing_bossa,
|
||||
gen_salsa_layered,
|
||||
gen_playback_basic,
|
||||
gen_song_sections,
|
||||
]
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("Generating audio samples for docs...")
|
||||
print()
|
||||
for gen in GENERATORS:
|
||||
gen()
|
||||
print()
|
||||
print(f"Done. {len(GENERATORS)} files in {AUDIO_DIR}")
|
||||
@@ -411,6 +411,10 @@ Acid House Track
|
||||
|
||||
play_score(score)
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<audio controls style="width:100%;margin:0.5em 0 1.5em"><source src="../_static/audio/acid_house.wav" type="audio/wav"></audio>
|
||||
|
||||
Dub Reggae with Delay Madness
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -443,6 +447,10 @@ Sparse notes into infinite echo:
|
||||
|
||||
play_score(score)
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<audio controls style="width:100%;margin:0.5em 0 1.5em"><source src="../_static/audio/dub_reggae.wav" type="audio/wav"></audio>
|
||||
|
||||
Jazz Ballad with Humanize
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -480,6 +488,10 @@ The difference between a robot and a musician:
|
||||
|
||||
play_score(score)
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<audio controls style="width:100%;margin:0.5em 0 1.5em"><source src="../_static/audio/jazz_ballad.wav" type="audio/wav"></audio>
|
||||
|
||||
Song with Sections
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -513,6 +525,10 @@ Define once, arrange freely:
|
||||
play_score(score)
|
||||
score.save_midi("my_song.mid")
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<audio controls style="width:100%;margin:0.5em 0 1.5em"><source src="../_static/audio/song_sections.wav" type="audio/wav"></audio>
|
||||
|
||||
Export Everything to MIDI
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
@@ -249,6 +249,10 @@ Playing Patterns
|
||||
play_pattern(Pattern.preset("salsa"), repeats=4, bpm=180)
|
||||
play_pattern(Pattern.preset("afrobeat"), repeats=8, bpm=110)
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<audio controls style="width:100%;margin:0.5em 0 1.5em"><source src="../_static/audio/rock_beat.wav" type="audio/wav"></audio>
|
||||
|
||||
Fills
|
||||
-----
|
||||
|
||||
@@ -339,6 +343,10 @@ drum pattern and all named parts are mixed together by ``play_score()``:
|
||||
|
||||
play_score(score)
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<audio controls style="width:100%;margin:0.5em 0 1.5em"><source src="../_static/audio/salsa_layered.wav" type="audio/wav"></audio>
|
||||
|
||||
World Percussion
|
||||
----------------
|
||||
|
||||
@@ -458,6 +466,10 @@ West African-style break).
|
||||
score = Score("4/4", bpm=120)
|
||||
score.drums("djembe", repeats=8, fill="djembe call", fill_every=4)
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<audio controls style="width:100%;margin:0.5em 0 1.5em"><source src="../_static/audio/djembe.wav" type="audio/wav"></audio>
|
||||
|
||||
Metal Kit
|
||||
~~~~~~~~~
|
||||
|
||||
@@ -548,6 +560,10 @@ voice with per-player timing tendencies and micro pitch drift.
|
||||
# Or use patterns
|
||||
score.drums("drumline", repeats=4)
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<audio controls style="width:100%;margin:0.5em 0 1.5em"><source src="../_static/audio/march_snare.wav" type="audio/wav"></audio>
|
||||
|
||||
**Sympathetic resonance:** The marching snare builds up snare wire
|
||||
buzz as hits accumulate, and the buzz decays during rests — just like
|
||||
a real drum.
|
||||
|
||||
@@ -66,6 +66,10 @@ the mix louder and punchier:
|
||||
chords.add(Chord.from_symbol(sym), Duration.WHOLE)
|
||||
play_score(score)
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<audio controls style="width:100%;margin:0.5em 0 1.5em"><source src="../_static/audio/playback_basic.wav" type="audio/wav"></audio>
|
||||
|
||||
The render pipeline respects the Score's ``temperament`` and
|
||||
``reference_pitch`` settings, so Baroque or microtonal scores play back
|
||||
at the correct tuning:
|
||||
|
||||
@@ -185,6 +185,10 @@ chords, melody, bass, each with their own synth and effects:
|
||||
|
||||
play_score(score)
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<audio controls style="width:100%;margin:0.5em 0 1.5em"><source src="../_static/audio/quickstart.wav" type="audio/wav"></audio>
|
||||
|
||||
Export to Your DAW
|
||||
------------------
|
||||
|
||||
|
||||
@@ -392,6 +392,10 @@ rhodes, triangle lead, and filtered bass:
|
||||
|
||||
play_score(score)
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<audio controls style="width:100%;margin:0.5em 0 1.5em"><source src="../_static/audio/sequencing_bossa.wav" type="audio/wav"></audio>
|
||||
|
||||
Velocity
|
||||
--------
|
||||
|
||||
@@ -431,6 +435,10 @@ Pass ``articulation=`` to ``Part.add()``:
|
||||
piano.add("G4", Duration.QUARTER, articulation="accent") # louder
|
||||
piano.add("C5", Duration.HALF, articulation="fermata") # held longer
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<audio controls style="width:100%;margin:0.5em 0 1.5em"><source src="../_static/audio/articulations.wav" type="audio/wav"></audio>
|
||||
|
||||
What each articulation does:
|
||||
|
||||
- **staccato** — plays ~40% of the note duration with a quick fade-out. Short and detached.
|
||||
@@ -467,6 +475,10 @@ of notes instead of setting each one manually.
|
||||
piano.dynamics(["C4","E4","G4","C5"], Duration.QUARTER,
|
||||
velocities=[50, 80, 110, 90])
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<audio controls style="width:100%;margin:0.5em 0 1.5em"><source src="../_static/audio/dynamics.wav" type="audio/wav"></audio>
|
||||
|
||||
Four methods:
|
||||
|
||||
- **crescendo()** — linear velocity ramp from ``start_vel`` to ``end_vel``.
|
||||
@@ -548,6 +560,12 @@ Each ensemble voice gets a consistent timing personality (some rush,
|
||||
some drag) plus small per-note wobble, and slightly different tuning.
|
||||
The result sounds like a real section — together but alive.
|
||||
|
||||
Solo snare, then an 8-player section plays the same pattern:
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<audio controls style="width:100%;margin:0.5em 0 1.5em"><source src="../_static/audio/ensemble.wav" type="audio/wav"></audio>
|
||||
|
||||
Swing and Groove
|
||||
----------------
|
||||
|
||||
@@ -663,6 +681,10 @@ Four interpolation curves:
|
||||
# Smooth reverb wash fading in and settling
|
||||
pad.ramp(over=Duration.WHOLE * 4, curve="ease_in_out", reverb=0.6)
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<audio controls style="width:100%;margin:0.5em 0 1.5em"><source src="../_static/audio/filter_ramp.wav" type="audio/wav"></audio>
|
||||
|
||||
``ramp()`` generates automation points every quarter-beat by default.
|
||||
Set ``resolution=0.125`` for smoother curves (every 32nd note), or
|
||||
``resolution=1.0`` for lighter automation (every beat).
|
||||
|
||||
Reference in New Issue
Block a user