mirror of
https://github.com/kennethreitz/interpretations.git
synced 2026-06-05 06:46:15 +00:00
02e59afa93
New sections: FM solo melody (bars 65-72), saw + square harmony in thirds (73-80), sine/triangle/PWM canon in a round (81-88), all waveforms return for finale then dissolve (89-96). Lead melody louder. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1054 lines
36 KiB
Python
1054 lines
36 KiB
Python
"""
|
|
WAVEFORMS — every oscillator gets a turn.
|
|
Sine, triangle, square, saw, FM, PWM, wavefold, supersaw, noise.
|
|
Percussive blips stacking into a machine. Occasional sustained pads.
|
|
F minor, 118 BPM.
|
|
"""
|
|
|
|
from pytheory import Key, Duration, Score, Tone, play_score
|
|
from pytheory.rhythm import DrumSound
|
|
|
|
key = Key("F", "minor")
|
|
s = key.scale # F G Ab Bb C Db Eb
|
|
|
|
F = s[0]; G = s[1]; Ab = s[2]; Bb = s[3]
|
|
C = s[4]; Db = s[5]; Eb = s[6]
|
|
|
|
score = Score("4/4", bpm=118)
|
|
|
|
K = DrumSound.KICK
|
|
CH = DrumSound.CLOSED_HAT
|
|
|
|
prog = key.progression("i", "VII", "VI", "iv")
|
|
|
|
# ═══════════════════════════════════════════════════════════════════
|
|
# STRUCTURE (64 bars, ~3:15):
|
|
# Bars 1-8: Sine blips — percussive, melodic, setting the grid
|
|
# Bars 9-16: Triangle joins — harmony, counterpoint
|
|
# Bars 17-24: Square enters — rhythmic fill, staccato
|
|
# Bars 25-32: Saw arp — the energy lifts
|
|
# Bars 33-40: All four interlocking — the machine hums
|
|
# Bars 41-48: Supersaw pad + kick — the room opens
|
|
# Bars 49-56: Peak — everything singing, melodic peak
|
|
# Bars 57-64: Unwind — layers peel away, sine last
|
|
# ═══════════════════════════════════════════════════════════════════
|
|
|
|
# ── SINE — percussive blips, the seed of everything ───────────
|
|
sine = score.part("sine", synth="sine", envelope="pluck", volume=0.5,
|
|
reverb=0.4, reverb_type="taj_mahal",
|
|
delay=0.15, delay_time=0.254, delay_feedback=0.25,
|
|
pan=-0.15)
|
|
|
|
# Bars 1-8: melodic blips — the rhythm IS the melody
|
|
# F minor: descending, dark. Land on Ab and Db, not C and F.
|
|
sine_phrase = [
|
|
(F, Duration.SIXTEENTH, 78), (None, Duration.SIXTEENTH, 0),
|
|
(Eb, Duration.SIXTEENTH, 72), (Db, Duration.SIXTEENTH, 70),
|
|
(None, Duration.EIGHTH, 0),
|
|
(C, Duration.EIGHTH, 68),
|
|
(Db, Duration.SIXTEENTH, 72), (None, Duration.SIXTEENTH, 0),
|
|
(Ab.add(-12), Duration.SIXTEENTH, 65), (None, Duration.SIXTEENTH, 0),
|
|
(None, Duration.QUARTER, 0),
|
|
]
|
|
sine_phrase_b = [
|
|
(Ab, Duration.SIXTEENTH, 75), (None, Duration.SIXTEENTH, 0),
|
|
(G, Duration.SIXTEENTH, 68), (F, Duration.SIXTEENTH, 72),
|
|
(None, Duration.EIGHTH, 0),
|
|
(Eb, Duration.EIGHTH, 70),
|
|
(Db, Duration.SIXTEENTH, 72), (None, Duration.SIXTEENTH, 0),
|
|
(C, Duration.SIXTEENTH, 65), (None, Duration.SIXTEENTH, 0),
|
|
(None, Duration.QUARTER, 0),
|
|
]
|
|
for _ in range(4):
|
|
for note, dur, vel in sine_phrase:
|
|
if note is None:
|
|
sine.rest(dur)
|
|
else:
|
|
sine.add(note, dur, velocity=vel)
|
|
for note, dur, vel in sine_phrase_b:
|
|
if note is None:
|
|
sine.rest(dur)
|
|
else:
|
|
sine.add(note, dur, velocity=vel)
|
|
|
|
# ── SINE PAD — the same waveform, but sustained, opens up ──────
|
|
sine_pad = score.part("sine_pad", synth="sine", envelope="pad", volume=0.2,
|
|
reverb=0.3, reverb_type="taj_mahal",
|
|
chorus=0.2, chorus_rate=0.06, chorus_depth=0.008,
|
|
pan=0.15)
|
|
|
|
# Bars 1-4: silent — let the blips establish
|
|
for _ in range(4):
|
|
sine_pad.rest(Duration.WHOLE)
|
|
|
|
# Bars 5-8: sine opens up — held notes an octave below the blips
|
|
sine_pad.add(F.add(-12), Duration.WHOLE, velocity=35)
|
|
sine_pad.add(Ab.add(-12), Duration.WHOLE, velocity=38)
|
|
sine_pad.add(Db, Duration.WHOLE, velocity=40)
|
|
sine_pad.add(F.add(-12), Duration.WHOLE, velocity=35)
|
|
|
|
# Bars 9-16: wider — octave spread, low and high together
|
|
sine_pad.add(F.add(-12), Duration.HALF, velocity=42)
|
|
sine_pad.add(Ab, Duration.HALF, velocity=38)
|
|
sine_pad.add(Db.add(-12), Duration.WHOLE, velocity=40)
|
|
sine_pad.add(F.add(-12), Duration.HALF, velocity=42)
|
|
sine_pad.add(C, Duration.HALF, velocity=35)
|
|
sine_pad.add(Ab.add(-12), Duration.WHOLE, velocity=40)
|
|
sine_pad.add(Db.add(-12), Duration.HALF, velocity=42)
|
|
sine_pad.add(Eb, Duration.HALF, velocity=38)
|
|
sine_pad.add(F.add(-12), Duration.WHOLE, velocity=40)
|
|
sine_pad.add(Ab.add(-12), Duration.WHOLE, velocity=38)
|
|
|
|
# Bars 17-56: continues — swelling and receding
|
|
for _ in range(10):
|
|
sine_pad.add(F.add(-12), Duration.WHOLE, velocity=42)
|
|
sine_pad.add(Ab.add(-12), Duration.WHOLE, velocity=38)
|
|
sine_pad.add(Db.add(-12), Duration.WHOLE, velocity=40)
|
|
sine_pad.add(Eb.add(-12), Duration.WHOLE, velocity=38)
|
|
|
|
# Bars 57-64: fading
|
|
for vel in [35, 30, 25, 20, 15, 10, 5, 0]:
|
|
if vel > 0:
|
|
sine_pad.add(F.add(-12), Duration.WHOLE, velocity=vel)
|
|
else:
|
|
sine_pad.rest(Duration.WHOLE)
|
|
|
|
# ── TRIANGLE PAD — occasional sustained warmth ─────────────────
|
|
tri_pad = score.part("tri_pad", synth="triangle", envelope="pad", volume=0.15,
|
|
reverb=0.25, reverb_type="cathedral",
|
|
chorus=0.2, chorus_rate=0.05, chorus_depth=0.01,
|
|
pan=-0.35)
|
|
|
|
# Mostly silent — just opens up at transitions
|
|
for _ in range(16):
|
|
tri_pad.rest(Duration.WHOLE)
|
|
# Bars 17-18: triangle opens up when square enters
|
|
tri_pad.add(Ab.add(-12), Duration.WHOLE, velocity=38)
|
|
tri_pad.add(Db, Duration.WHOLE, velocity=35)
|
|
for _ in range(6):
|
|
tri_pad.rest(Duration.WHOLE)
|
|
# Bars 25-26: opens again when saw enters
|
|
tri_pad.add(F.add(-12), Duration.WHOLE, velocity=40)
|
|
tri_pad.add(Eb, Duration.WHOLE, velocity=35)
|
|
for _ in range(6):
|
|
tri_pad.rest(Duration.WHOLE)
|
|
# Bars 33-34: opens when kick drops
|
|
tri_pad.add(Db, Duration.WHOLE, velocity=42)
|
|
tri_pad.add(Ab.add(-12), Duration.WHOLE, velocity=38)
|
|
for _ in range(14):
|
|
tri_pad.rest(Duration.WHOLE)
|
|
# Bars 49-50: opens at peak
|
|
tri_pad.add(F.add(-12), Duration.WHOLE, velocity=45)
|
|
tri_pad.add(Ab.add(-12), Duration.WHOLE, velocity=42)
|
|
for _ in range(14):
|
|
tri_pad.rest(Duration.WHOLE)
|
|
|
|
# ── SAW PAD — rare, big, only at the peak ─────────────────────
|
|
saw_pad = score.part("saw_pad", synth="saw", envelope="pad", volume=0.12,
|
|
lowpass=2000,
|
|
reverb=0.2, reverb_type="spring",
|
|
chorus=0.3, chorus_rate=0.1, chorus_depth=0.008,
|
|
pan=0.35)
|
|
|
|
# Silent until bar 49
|
|
for _ in range(48):
|
|
saw_pad.rest(Duration.WHOLE)
|
|
# Bars 49-52: the saw opens up — one sustained moment
|
|
for chord in prog:
|
|
saw_pad.add(chord, Duration.WHOLE, velocity=40)
|
|
# Back to silence
|
|
for _ in range(12):
|
|
saw_pad.rest(Duration.WHOLE)
|
|
|
|
# Bars 9-56: blips continue — the constant thread
|
|
for _ in range(24):
|
|
for note, dur, vel in sine_phrase:
|
|
if note is None:
|
|
sine.rest(dur)
|
|
else:
|
|
sine.add(note, dur, velocity=vel)
|
|
for note, dur, vel in sine_phrase_b:
|
|
if note is None:
|
|
sine.rest(dur)
|
|
else:
|
|
sine.add(note, dur, velocity=vel)
|
|
|
|
# Bars 57-64: fading
|
|
for rep in range(4):
|
|
off = rep * -12
|
|
for note, dur, vel in sine_phrase:
|
|
if note is None:
|
|
sine.rest(dur)
|
|
else:
|
|
sine.add(note, dur, velocity=max(20, vel + off))
|
|
for note, dur, vel in sine_phrase_b:
|
|
if note is None:
|
|
sine.rest(dur)
|
|
else:
|
|
sine.add(note, dur, velocity=max(20, vel + off))
|
|
|
|
# ── TRIANGLE — harmony, enters bar 9 ─────────────────────────
|
|
tri = score.part("triangle", synth="triangle", envelope="pluck", volume=0.4,
|
|
reverb=0.2, reverb_decay=1.0,
|
|
delay=0.12, delay_time=0.254, delay_feedback=0.2,
|
|
pan=0.3)
|
|
|
|
for _ in range(8):
|
|
tri.rest(Duration.WHOLE)
|
|
|
|
# Bars 9-16: counterpoint — fills the gaps in sine's rhythm
|
|
# Triangle: descending thirds, landing on dark notes
|
|
tri_phrase = [
|
|
(None, Duration.EIGHTH, 0),
|
|
(Db, Duration.SIXTEENTH, 70), (C, Duration.SIXTEENTH, 65),
|
|
(None, Duration.EIGHTH, 0),
|
|
(Ab.add(-12), Duration.SIXTEENTH, 68), (None, Duration.SIXTEENTH, 0),
|
|
(Bb.add(-12), Duration.SIXTEENTH, 62), (None, Duration.SIXTEENTH, 0),
|
|
(None, Duration.EIGHTH, 0),
|
|
(Ab.add(-12), Duration.EIGHTH, 65),
|
|
]
|
|
tri_phrase_b = [
|
|
(None, Duration.EIGHTH, 0),
|
|
(F, Duration.SIXTEENTH, 72), (Eb, Duration.SIXTEENTH, 68),
|
|
(None, Duration.EIGHTH, 0),
|
|
(Db, Duration.SIXTEENTH, 70), (None, Duration.SIXTEENTH, 0),
|
|
(C, Duration.SIXTEENTH, 62), (None, Duration.SIXTEENTH, 0),
|
|
(None, Duration.EIGHTH, 0),
|
|
(Db, Duration.EIGHTH, 68),
|
|
]
|
|
for _ in range(4):
|
|
for note, dur, vel in tri_phrase:
|
|
if note is None:
|
|
tri.rest(dur)
|
|
else:
|
|
tri.add(note, dur, velocity=vel)
|
|
for note, dur, vel in tri_phrase_b:
|
|
if note is None:
|
|
tri.rest(dur)
|
|
else:
|
|
tri.add(note, dur, velocity=vel)
|
|
|
|
# Bars 17-56: continues
|
|
for _ in range(20):
|
|
for note, dur, vel in tri_phrase:
|
|
if note is None:
|
|
tri.rest(dur)
|
|
else:
|
|
tri.add(note, dur, velocity=vel)
|
|
for note, dur, vel in tri_phrase_b:
|
|
if note is None:
|
|
tri.rest(dur)
|
|
else:
|
|
tri.add(note, dur, velocity=vel)
|
|
|
|
# Bars 57-64: fading
|
|
for rep in range(4):
|
|
off = rep * -12
|
|
for note, dur, vel in tri_phrase:
|
|
if note is None:
|
|
tri.rest(dur)
|
|
else:
|
|
tri.add(note, dur, velocity=max(18, vel + off))
|
|
for note, dur, vel in tri_phrase_b:
|
|
if note is None:
|
|
tri.rest(dur)
|
|
else:
|
|
tri.add(note, dur, velocity=max(18, vel + off))
|
|
|
|
# ── SQUARE — staccato rhythm, enters bar 17 ──────────────────
|
|
sq = score.part("square", synth="square", envelope="pluck", volume=0.3,
|
|
lowpass=3500,
|
|
reverb=0.15, reverb_decay=0.8,
|
|
delay=0.1, delay_time=0.127, delay_feedback=0.15,
|
|
pan=-0.4)
|
|
|
|
for _ in range(16):
|
|
sq.rest(Duration.WHOLE)
|
|
|
|
# Bars 17-24: rhythmic stabs — off the beat
|
|
sq_stab = [
|
|
# Square: off-beat stabs — Db and Ab, the minor anchors
|
|
(None, Duration.SIXTEENTH, 0), (Db, Duration.SIXTEENTH, 70),
|
|
(None, Duration.SIXTEENTH, 0), (None, Duration.SIXTEENTH, 0),
|
|
(None, Duration.SIXTEENTH, 0), (Ab.add(-12), Duration.SIXTEENTH, 65),
|
|
(None, Duration.SIXTEENTH, 0), (Db, Duration.SIXTEENTH, 72),
|
|
(None, Duration.EIGHTH, 0),
|
|
(None, Duration.SIXTEENTH, 0), (Ab.add(-12), Duration.SIXTEENTH, 65),
|
|
(None, Duration.QUARTER, 0),
|
|
]
|
|
for _ in range(8):
|
|
for note, dur, vel in sq_stab:
|
|
if note is None:
|
|
sq.rest(dur)
|
|
else:
|
|
sq.add(note, dur, velocity=vel)
|
|
|
|
# Bars 25-56: continues
|
|
for _ in range(32):
|
|
for note, dur, vel in sq_stab:
|
|
if note is None:
|
|
sq.rest(dur)
|
|
else:
|
|
sq.add(note, dur, velocity=vel)
|
|
|
|
# Bars 57-64: fading
|
|
for rep in range(8):
|
|
off = rep * -8
|
|
for note, dur, vel in sq_stab:
|
|
if note is None:
|
|
sq.rest(dur)
|
|
else:
|
|
sq.add(note, dur, velocity=max(15, vel + off))
|
|
|
|
# ── SAW ARP — energy lift, enters bar 25 ─────────────────────
|
|
saw = score.part("saw", synth="saw", envelope="pluck", volume=0.3,
|
|
lowpass=4000,
|
|
distortion=0.05, saturation=0.2,
|
|
reverb=0.18, reverb_type="spring",
|
|
delay=0.2, delay_time=0.254, delay_feedback=0.3,
|
|
pan=0.4)
|
|
saw.lfo("lowpass", rate=0.01, min=2000, max=6000, bars=64, shape="triangle")
|
|
|
|
for _ in range(24):
|
|
saw.rest(Duration.WHOLE)
|
|
|
|
# Bars 25-32: arpeggio — the energy lifts
|
|
# Saw arps — descending shapes, minor triads
|
|
arp_a = [C, Ab, F, Ab, C, F, Ab, F] # i — Fm descending feel
|
|
arp_b = [Bb, G, Eb, G, Bb, Eb, G, Eb] # VII — Eb
|
|
arp_c = [Ab, F, Db, F, Ab, Db, F.add(-12), Db.add(-12)] # VI — Db
|
|
arp_d = [F, Db, Bb.add(-12), Db, F, Bb.add(-12), Db, F] # iv — Bbm
|
|
|
|
for _ in range(2):
|
|
for note in arp_a:
|
|
saw.add(note, Duration.EIGHTH, velocity=68)
|
|
for note in arp_b:
|
|
saw.add(note, Duration.EIGHTH, velocity=65)
|
|
for note in arp_c:
|
|
saw.add(note, Duration.EIGHTH, velocity=70)
|
|
for note in arp_d:
|
|
saw.add(note, Duration.EIGHTH, velocity=68)
|
|
|
|
# Bars 33-56: continues — the constant motion
|
|
for _ in range(6):
|
|
for note in arp_a:
|
|
saw.add(note, Duration.EIGHTH, velocity=72)
|
|
for note in arp_b:
|
|
saw.add(note, Duration.EIGHTH, velocity=68)
|
|
for note in arp_c:
|
|
saw.add(note, Duration.EIGHTH, velocity=72)
|
|
for note in arp_d:
|
|
saw.add(note, Duration.EIGHTH, velocity=70)
|
|
|
|
# Bars 57-64: fading arps
|
|
for rep in range(2):
|
|
off = rep * -15
|
|
for note in arp_a:
|
|
saw.add(note, Duration.EIGHTH, velocity=max(20, 62 + off))
|
|
for note in arp_b:
|
|
saw.add(note, Duration.EIGHTH, velocity=max(20, 58 + off))
|
|
for note in arp_c:
|
|
saw.add(note, Duration.EIGHTH, velocity=max(20, 60 + off))
|
|
for note in arp_d:
|
|
saw.add(note, Duration.EIGHTH, velocity=max(20, 58 + off))
|
|
|
|
# ── SUPERSAW PAD — the room opens, bar 41 ────────────────────
|
|
pad = score.part("pad", synth="supersaw", envelope="pad", volume=0.12,
|
|
reverb=0.6, reverb_type="taj_mahal",
|
|
chorus=0.3, chorus_rate=0.15, chorus_depth=0.008,
|
|
lowpass=2500)
|
|
|
|
for _ in range(40):
|
|
pad.rest(Duration.WHOLE)
|
|
|
|
# Bars 41-56: chord pads — warmth behind the blips
|
|
for _ in range(4):
|
|
for chord in prog:
|
|
pad.add(chord, Duration.WHOLE, velocity=48)
|
|
|
|
# Bars 57-64: fading
|
|
for vel in [42, 35, 28, 22, 15, 10, 5, 0]:
|
|
if vel > 0:
|
|
pad.add(prog[0], Duration.WHOLE, velocity=vel)
|
|
else:
|
|
pad.rest(Duration.WHOLE)
|
|
|
|
# ── FM — metallic, bell-like blips, enters bar 25 ─────────────
|
|
fm = score.part("fm", synth="fm", envelope="pluck", volume=0.3,
|
|
reverb=0.3, reverb_type="cathedral",
|
|
delay=0.15, delay_time=0.254, delay_feedback=0.2,
|
|
pan=-0.35)
|
|
|
|
for _ in range(24):
|
|
fm.rest(Duration.WHOLE)
|
|
|
|
# FM phrase — metallic, inharmonic, fills gaps
|
|
fm_phrase = [
|
|
(Ab, Duration.SIXTEENTH, 68), (None, Duration.SIXTEENTH, 0),
|
|
(None, Duration.EIGHTH, 0),
|
|
(Db, Duration.SIXTEENTH, 65), (None, Duration.SIXTEENTH, 0),
|
|
(Eb, Duration.SIXTEENTH, 70), (None, Duration.SIXTEENTH, 0),
|
|
(None, Duration.EIGHTH, 0),
|
|
(C, Duration.SIXTEENTH, 62), (None, Duration.SIXTEENTH, 0),
|
|
(None, Duration.QUARTER, 0),
|
|
]
|
|
for _ in range(32):
|
|
for note, dur, vel in fm_phrase:
|
|
if note is None:
|
|
fm.rest(dur)
|
|
else:
|
|
fm.add(note, dur, velocity=vel)
|
|
|
|
# Bars 57-64: fading
|
|
for rep in range(8):
|
|
off = rep * -8
|
|
for note, dur, vel in fm_phrase:
|
|
if note is None:
|
|
fm.rest(dur)
|
|
else:
|
|
fm.add(note, dur, velocity=max(15, vel + off))
|
|
|
|
# ── PWM — wobbling pulse width, enters bar 33 ─────────────────
|
|
pwm = score.part("pwm", synth="pwm", envelope="pluck", volume=0.25,
|
|
reverb=0.2, reverb_decay=1.0,
|
|
delay=0.12, delay_time=0.127, delay_feedback=0.18,
|
|
pan=0.35)
|
|
|
|
for _ in range(32):
|
|
pwm.rest(Duration.WHOLE)
|
|
|
|
# PWM phrase — the wobble gives it movement even on single notes
|
|
pwm_phrase = [
|
|
(F, Duration.SIXTEENTH, 72), (None, Duration.SIXTEENTH, 0),
|
|
(Eb, Duration.SIXTEENTH, 65), (None, Duration.SIXTEENTH, 0),
|
|
(None, Duration.EIGHTH, 0),
|
|
(Db, Duration.SIXTEENTH, 68), (F, Duration.SIXTEENTH, 70),
|
|
(None, Duration.EIGHTH, 0),
|
|
(Eb, Duration.SIXTEENTH, 65), (None, Duration.SIXTEENTH, 0),
|
|
(None, Duration.QUARTER, 0),
|
|
]
|
|
for _ in range(24):
|
|
for note, dur, vel in pwm_phrase:
|
|
if note is None:
|
|
pwm.rest(dur)
|
|
else:
|
|
pwm.add(note, dur, velocity=vel)
|
|
|
|
# Bars 57-64: fading
|
|
for rep in range(8):
|
|
off = rep * -8
|
|
for note, dur, vel in pwm_phrase:
|
|
if note is None:
|
|
pwm.rest(dur)
|
|
else:
|
|
pwm.add(note, dur, velocity=max(15, vel + off))
|
|
|
|
# ── WAVEFOLD — harsh, complex harmonics, enters bar 41 ────────
|
|
wf = score.part("wavefold", synth="wavefold", envelope="pluck", volume=0.2,
|
|
reverb=0.15, reverb_decay=0.8,
|
|
delay=0.1, delay_time=0.254, delay_feedback=0.15,
|
|
pan=-0.2)
|
|
|
|
for _ in range(40):
|
|
wf.rest(Duration.WHOLE)
|
|
|
|
# Wavefold phrase — aggressive, complex
|
|
wf_phrase = [
|
|
(C, Duration.SIXTEENTH, 72), (Db, Duration.SIXTEENTH, 68),
|
|
(None, Duration.EIGHTH, 0),
|
|
(Ab.add(-12), Duration.SIXTEENTH, 65), (None, Duration.SIXTEENTH, 0),
|
|
(None, Duration.EIGHTH, 0),
|
|
(F, Duration.SIXTEENTH, 70), (Eb, Duration.SIXTEENTH, 65),
|
|
(None, Duration.EIGHTH, 0),
|
|
(Db, Duration.EIGHTH, 68),
|
|
]
|
|
for _ in range(16):
|
|
for note, dur, vel in wf_phrase:
|
|
if note is None:
|
|
wf.rest(dur)
|
|
else:
|
|
wf.add(note, dur, velocity=vel)
|
|
|
|
# Bars 57-64: fading
|
|
for rep in range(8):
|
|
off = rep * -8
|
|
for note, dur, vel in wf_phrase:
|
|
if note is None:
|
|
wf.rest(dur)
|
|
else:
|
|
wf.add(note, dur, velocity=max(15, vel + off))
|
|
|
|
# ── 808 — sustained sub, the grit underneath ──────────────────
|
|
sub = score.part("808", synth="sine", envelope="pad", volume=0.55,
|
|
lowpass=200, distortion=0.2, distortion_drive=3.0,
|
|
sub_osc=0.5, saturation=0.4, sidechain=0.3)
|
|
|
|
for _ in range(16):
|
|
sub.rest(Duration.WHOLE)
|
|
|
|
# Bars 17-56: sustained 808, follows the chord roots
|
|
roots = [F.add(-24), Eb.add(-24), Db.add(-24), Bb.add(-24)]
|
|
for _ in range(10):
|
|
for root in roots:
|
|
sub.add(root, Duration.WHOLE, velocity=38)
|
|
|
|
# Bars 57-64: fading
|
|
for vel in [32, 28, 22, 18, 14, 10, 5, 0]:
|
|
if vel > 0:
|
|
sub.add(F.add(-24), Duration.WHOLE, velocity=vel)
|
|
else:
|
|
sub.rest(Duration.WHOLE)
|
|
|
|
# ── KICK — four on the floor first, alone ──────────────────────
|
|
kick = score.part("kick", volume=0.6, humanize=0.03)
|
|
|
|
for _ in range(24):
|
|
kick.rest(Duration.WHOLE)
|
|
|
|
# Bars 25-32: just the kick — four on the floor, nothing else
|
|
for _ in range(8):
|
|
for beat in range(4):
|
|
kick.hit(K, Duration.QUARTER, velocity=100)
|
|
|
|
# Bars 33-56: continues under the full drums
|
|
for _ in range(24):
|
|
for beat in range(4):
|
|
kick.hit(K, Duration.QUARTER, velocity=105)
|
|
|
|
# Bars 57-64: fading
|
|
for vel in [92, 78, 65, 52, 38, 25, 0, 0]:
|
|
if vel > 0:
|
|
for beat in range(4):
|
|
kick.hit(K, Duration.QUARTER, velocity=vel)
|
|
else:
|
|
kick.rest(Duration.WHOLE)
|
|
|
|
# ── DRUMS — complex rhythmic pattern, enters bar 33 ───────────
|
|
S = DrumSound.SNARE
|
|
OH = DrumSound.OPEN_HAT
|
|
|
|
hats = score.part("hats", volume=0.25, pan=0.15, humanize=0.04,
|
|
delay=0.06, delay_time=0.127, delay_feedback=0.1)
|
|
|
|
snare = score.part("snare", volume=0.4, humanize=0.04,
|
|
reverb=0.15, reverb_decay=0.6,
|
|
delay=0.05, delay_time=0.254, delay_feedback=0.08,
|
|
pan=0.05)
|
|
|
|
for _ in range(32):
|
|
hats.rest(Duration.WHOLE)
|
|
snare.rest(Duration.WHOLE)
|
|
|
|
# Bars 33-40: rhythmic hats + snare on 2&4 — the groove locks
|
|
for _ in range(8):
|
|
# Hats: 16ths with accents and ghost notes
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=72)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=38)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=55)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=35)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=68)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=40)
|
|
hats.hit(OH, Duration.SIXTEENTH, velocity=58)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=35)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=72)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=38)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=52)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=35)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=65)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=42)
|
|
hats.hit(OH, Duration.SIXTEENTH, velocity=55)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=35)
|
|
# Snare: 2 and 4 with ghost notes
|
|
snare.rest(Duration.EIGHTH)
|
|
snare.hit(S, Duration.SIXTEENTH, velocity=40) # ghost
|
|
snare.rest(Duration.SIXTEENTH)
|
|
snare.hit(S, Duration.QUARTER, velocity=95) # 2
|
|
snare.rest(Duration.EIGHTH)
|
|
snare.hit(S, Duration.SIXTEENTH, velocity=38) # ghost
|
|
snare.rest(Duration.SIXTEENTH)
|
|
snare.hit(S, Duration.QUARTER, velocity=98) # 4
|
|
|
|
# Bars 41-48: tighter — more ghost notes, busier
|
|
for _ in range(8):
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=75)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=42)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=58)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=38)
|
|
hats.hit(OH, Duration.SIXTEENTH, velocity=62)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=35)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=55)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=42)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=72)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=40)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=58)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=35)
|
|
hats.hit(OH, Duration.SIXTEENTH, velocity=60)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=38)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=55)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=42)
|
|
# Snare with more ghosts
|
|
snare.hit(S, Duration.SIXTEENTH, velocity=35) # ghost
|
|
snare.rest(Duration.SIXTEENTH)
|
|
snare.hit(S, Duration.SIXTEENTH, velocity=38) # ghost
|
|
snare.rest(Duration.SIXTEENTH)
|
|
snare.hit(S, Duration.QUARTER, velocity=98) # 2
|
|
snare.hit(S, Duration.SIXTEENTH, velocity=35) # ghost
|
|
snare.rest(Duration.SIXTEENTH)
|
|
snare.hit(S, Duration.SIXTEENTH, velocity=40) # ghost
|
|
snare.rest(Duration.SIXTEENTH)
|
|
snare.hit(S, Duration.QUARTER, velocity=100) # 4
|
|
|
|
# Bars 49-56: peak — snare fills every 4 bars
|
|
for bar in range(8):
|
|
if bar % 4 == 3:
|
|
# Fill — 16th note snare roll
|
|
for i in range(16):
|
|
snare.hit(S, Duration.SIXTEENTH, velocity=min(110, 60 + i * 3))
|
|
for i in range(16):
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=min(80, 45 + i * 2))
|
|
else:
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=78)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=42)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=60)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=38)
|
|
hats.hit(OH, Duration.SIXTEENTH, velocity=65)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=40)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=58)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=35)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=75)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=42)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=55)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=38)
|
|
hats.hit(OH, Duration.SIXTEENTH, velocity=62)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=40)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=58)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=42)
|
|
snare.rest(Duration.EIGHTH)
|
|
snare.hit(S, Duration.SIXTEENTH, velocity=40)
|
|
snare.rest(Duration.SIXTEENTH)
|
|
snare.hit(S, Duration.QUARTER, velocity=100)
|
|
snare.rest(Duration.EIGHTH)
|
|
snare.hit(S, Duration.SIXTEENTH, velocity=42)
|
|
snare.rest(Duration.SIXTEENTH)
|
|
snare.hit(S, Duration.QUARTER, velocity=102)
|
|
|
|
# Bars 57-64: fading
|
|
for vel in [88, 75, 62, 48, 35, 22, 0, 0]:
|
|
if vel > 0:
|
|
for beat in range(4):
|
|
hats.hit(CH, Duration.EIGHTH, velocity=max(15, vel - 20))
|
|
hats.hit(CH, Duration.EIGHTH, velocity=max(12, vel - 35))
|
|
snare.rest(Duration.QUARTER)
|
|
snare.hit(S, Duration.QUARTER, velocity=vel)
|
|
snare.rest(Duration.HALF)
|
|
else:
|
|
hats.rest(Duration.WHOLE)
|
|
snare.rest(Duration.WHOLE)
|
|
|
|
# ── MELODIC PEAK — sine lead, bars 49-56 ─────────────────────
|
|
lead = score.part("lead", synth="sine", volume=0.55,
|
|
reverb=0.25, reverb_type="taj_mahal",
|
|
delay=0.18, delay_time=0.254, delay_feedback=0.25,
|
|
pan=-0.05)
|
|
|
|
for _ in range(48):
|
|
lead.rest(Duration.WHOLE)
|
|
|
|
# Bars 49-56: the melody sings above everything
|
|
# Lead melody — descending, minor, Db-C pull at the heart
|
|
lead_melody = [
|
|
(Ab, Duration.HALF, 80), (G, Duration.QUARTER, 72),
|
|
(F, Duration.QUARTER, 70),
|
|
(Eb, Duration.HALF, 75), (Db, Duration.QUARTER, 72),
|
|
(C, Duration.QUARTER, 68),
|
|
(Db, Duration.DOTTED_HALF, 78), (C, Duration.QUARTER, 70),
|
|
(Ab.add(-12), Duration.WHOLE, 72),
|
|
(F, Duration.QUARTER, 75), (G, Duration.QUARTER, 70),
|
|
(Ab, Duration.HALF, 78),
|
|
(Bb, Duration.QUARTER, 72), (Ab, Duration.QUARTER, 70),
|
|
(G, Duration.HALF, 68), (F, Duration.HALF, 72),
|
|
(F, Duration.WHOLE, 70),
|
|
(None, Duration.WHOLE, 0),
|
|
]
|
|
for note, dur, vel in lead_melody:
|
|
if note is None:
|
|
lead.rest(dur)
|
|
else:
|
|
lead.add(note, dur, velocity=vel)
|
|
|
|
# Bars 57-64: one last phrase, dissolving
|
|
lead.add(Ab, Duration.HALF, velocity=65)
|
|
lead.add(G, Duration.HALF, velocity=58)
|
|
lead.add(F, Duration.WHOLE, velocity=52)
|
|
for _ in range(6):
|
|
lead.rest(Duration.WHOLE)
|
|
|
|
# ═══════════════════════════════════════════════════════════════════
|
|
# EXTENSION — solos, harmonies, and a proper ending (bars 65-96)
|
|
# The track doesn't fade — it evolves.
|
|
# ═══════════════════════════════════════════════════════════════════
|
|
|
|
# ── Bars 65-72: FM SOLO — metallic melody floats above the bed ──
|
|
# Everything else drops to drones/pads, FM takes the spotlight
|
|
sine.add(F.add(-12), Duration.WHOLE, velocity=40)
|
|
sine.add(F.add(-12), Duration.WHOLE, velocity=40)
|
|
sine.add(F.add(-12), Duration.WHOLE, velocity=40)
|
|
sine.add(F.add(-12), Duration.WHOLE, velocity=40)
|
|
sine.add(F.add(-12), Duration.WHOLE, velocity=40)
|
|
sine.add(F.add(-12), Duration.WHOLE, velocity=40)
|
|
sine.add(F.add(-12), Duration.WHOLE, velocity=40)
|
|
sine.add(F.add(-12), Duration.WHOLE, velocity=40)
|
|
|
|
for _ in range(8):
|
|
tri.rest(Duration.WHOLE)
|
|
|
|
for _ in range(8):
|
|
sq.rest(Duration.WHOLE)
|
|
|
|
# Saw holds a drone
|
|
for _ in range(8):
|
|
saw.add(F.add(-12), Duration.WHOLE, velocity=35)
|
|
|
|
# FM solo melody — bell-like, singing
|
|
fm_solo = [
|
|
(Ab, Duration.QUARTER, 75), (G, Duration.EIGHTH, 68),
|
|
(F, Duration.EIGHTH, 65), (Eb, Duration.HALF, 72),
|
|
(Db, Duration.QUARTER, 70), (C, Duration.QUARTER, 65),
|
|
(Db, Duration.HALF, 72), (Eb, Duration.HALF, 68),
|
|
(F, Duration.QUARTER, 75), (Ab, Duration.QUARTER, 72),
|
|
(G, Duration.QUARTER, 68), (F, Duration.QUARTER, 72),
|
|
(Eb, Duration.HALF, 70), (Db, Duration.HALF, 72),
|
|
(C, Duration.QUARTER, 65), (Db, Duration.QUARTER, 70),
|
|
(F, Duration.HALF, 75),
|
|
(Ab, Duration.QUARTER, 78), (Bb, Duration.QUARTER, 72),
|
|
(Ab, Duration.QUARTER, 70), (G, Duration.QUARTER, 65),
|
|
(F, Duration.WHOLE, 72),
|
|
(None, Duration.WHOLE, 0),
|
|
]
|
|
for note, dur, vel in fm_solo:
|
|
if note is None:
|
|
fm.rest(dur)
|
|
else:
|
|
fm.add(note, dur, velocity=vel)
|
|
|
|
for _ in range(8):
|
|
pwm.rest(Duration.WHOLE)
|
|
for _ in range(8):
|
|
wf.rest(Duration.WHOLE)
|
|
|
|
# Supersaw pad underneath
|
|
for _ in range(2):
|
|
for chord in prog:
|
|
pad.add(chord, Duration.WHOLE, velocity=42)
|
|
|
|
# Sub continues
|
|
for _ in range(8):
|
|
sub.add(F.add(-24), Duration.WHOLE, velocity=35)
|
|
|
|
# Drums light
|
|
for _ in range(8):
|
|
kick.hit(K, Duration.QUARTER, velocity=85)
|
|
kick.rest(Duration.DOTTED_HALF)
|
|
for _ in range(8):
|
|
hats.rest(Duration.WHOLE)
|
|
snare.rest(Duration.WHOLE)
|
|
|
|
sine_pad.add(F.add(-12), Duration.WHOLE, velocity=35)
|
|
sine_pad.add(Ab.add(-12), Duration.WHOLE, velocity=32)
|
|
sine_pad.add(Db, Duration.WHOLE, velocity=35)
|
|
sine_pad.add(F.add(-12), Duration.WHOLE, velocity=32)
|
|
sine_pad.add(Ab.add(-12), Duration.WHOLE, velocity=35)
|
|
sine_pad.add(Db, Duration.WHOLE, velocity=32)
|
|
sine_pad.add(F.add(-12), Duration.WHOLE, velocity=30)
|
|
sine_pad.add(F.add(-12), Duration.WHOLE, velocity=28)
|
|
|
|
for _ in range(8):
|
|
tri_pad.rest(Duration.WHOLE)
|
|
for _ in range(8):
|
|
saw_pad.rest(Duration.WHOLE)
|
|
for _ in range(8):
|
|
lead.rest(Duration.WHOLE)
|
|
|
|
# ── Bars 73-80: SAW + SQUARE DUET — harmony in thirds ──────────
|
|
# Two voices singing together, harmonized
|
|
duet_melody = [
|
|
(F, Duration.QUARTER, 72), (G, Duration.QUARTER, 68),
|
|
(Ab, Duration.HALF, 75),
|
|
(Bb, Duration.QUARTER, 70), (Ab, Duration.EIGHTH, 65),
|
|
(G, Duration.EIGHTH, 62), (F, Duration.HALF, 68),
|
|
(Eb, Duration.QUARTER, 65), (F, Duration.QUARTER, 70),
|
|
(G, Duration.HALF, 72),
|
|
(Ab, Duration.WHOLE, 75),
|
|
(Bb, Duration.QUARTER, 72), (C, Duration.QUARTER, 70),
|
|
(Bb, Duration.QUARTER, 68), (Ab, Duration.QUARTER, 72),
|
|
(G, Duration.HALF, 70), (F, Duration.HALF, 72),
|
|
(F, Duration.WHOLE, 68),
|
|
(None, Duration.WHOLE, 0),
|
|
]
|
|
# Harmony — a third below
|
|
duet_harmony = [
|
|
(Db, Duration.QUARTER, 65), (Eb, Duration.QUARTER, 62),
|
|
(F, Duration.HALF, 68),
|
|
(G, Duration.QUARTER, 62), (F, Duration.EIGHTH, 58),
|
|
(Eb, Duration.EIGHTH, 55), (Db, Duration.HALF, 60),
|
|
(C, Duration.QUARTER, 58), (Db, Duration.QUARTER, 62),
|
|
(Eb, Duration.HALF, 65),
|
|
(F, Duration.WHOLE, 68),
|
|
(G, Duration.QUARTER, 65), (Ab, Duration.QUARTER, 62),
|
|
(G, Duration.QUARTER, 60), (F, Duration.QUARTER, 65),
|
|
(Eb, Duration.HALF, 62), (Db, Duration.HALF, 65),
|
|
(Db, Duration.WHOLE, 62),
|
|
(None, Duration.WHOLE, 0),
|
|
]
|
|
|
|
saw.set(volume=0.4)
|
|
for note, dur, vel in duet_melody:
|
|
if note is None:
|
|
saw.rest(dur)
|
|
else:
|
|
saw.add(note, dur, velocity=vel)
|
|
|
|
sq.set(volume=0.3)
|
|
for note, dur, vel in duet_harmony:
|
|
if note is None:
|
|
sq.rest(dur)
|
|
else:
|
|
sq.add(note, dur, velocity=vel)
|
|
|
|
# Others hold drones or rest
|
|
for _ in range(8):
|
|
sine.add(F.add(-12), Duration.WHOLE, velocity=35)
|
|
for _ in range(8):
|
|
tri.rest(Duration.WHOLE)
|
|
for _ in range(8):
|
|
fm.rest(Duration.WHOLE)
|
|
for _ in range(8):
|
|
pwm.rest(Duration.WHOLE)
|
|
for _ in range(8):
|
|
wf.rest(Duration.WHOLE)
|
|
for _ in range(2):
|
|
for chord in prog:
|
|
pad.add(chord, Duration.WHOLE, velocity=38)
|
|
for _ in range(8):
|
|
sub.add(F.add(-24), Duration.WHOLE, velocity=32)
|
|
for _ in range(8):
|
|
kick.hit(K, Duration.QUARTER, velocity=90)
|
|
kick.rest(Duration.QUARTER)
|
|
kick.hit(K, Duration.QUARTER, velocity=82)
|
|
kick.rest(Duration.QUARTER)
|
|
for _ in range(8):
|
|
hats.rest(Duration.EIGHTH)
|
|
hats.hit(CH, Duration.EIGHTH, velocity=48)
|
|
hats.rest(Duration.EIGHTH)
|
|
hats.hit(CH, Duration.EIGHTH, velocity=42)
|
|
hats.rest(Duration.HALF)
|
|
for _ in range(8):
|
|
snare.rest(Duration.QUARTER)
|
|
snare.hit(S, Duration.QUARTER, velocity=75)
|
|
snare.rest(Duration.HALF)
|
|
for _ in range(8):
|
|
sine_pad.rest(Duration.WHOLE)
|
|
for _ in range(8):
|
|
tri_pad.rest(Duration.WHOLE)
|
|
for _ in range(8):
|
|
saw_pad.rest(Duration.WHOLE)
|
|
for _ in range(8):
|
|
lead.rest(Duration.WHOLE)
|
|
|
|
# ── Bars 81-88: CANON — sine, triangle, PWM in staggered entries ─
|
|
# Same phrase, entering 2 beats apart — three voices in a round
|
|
canon_phrase = [
|
|
(Ab, Duration.QUARTER, 72), (G, Duration.EIGHTH, 65),
|
|
(F, Duration.EIGHTH, 62), (Eb, Duration.QUARTER, 68),
|
|
(Db, Duration.QUARTER, 70),
|
|
(C, Duration.QUARTER, 65), (Db, Duration.QUARTER, 68),
|
|
(F, Duration.HALF, 72),
|
|
]
|
|
|
|
# Sine starts
|
|
for note, dur, vel in canon_phrase:
|
|
sine.add(note, dur, velocity=vel)
|
|
for note, dur, vel in canon_phrase:
|
|
sine.add(note, dur, velocity=max(20, vel - 10))
|
|
|
|
# Triangle enters 2 beats late
|
|
tri.rest(Duration.HALF)
|
|
for note, dur, vel in canon_phrase:
|
|
tri.add(note, dur, velocity=max(20, vel - 5))
|
|
for note, dur, vel in canon_phrase:
|
|
tri.add(note, dur, velocity=max(20, vel - 12))
|
|
tri.rest(Duration.HALF)
|
|
|
|
# PWM enters 4 beats late
|
|
pwm.rest(Duration.WHOLE)
|
|
for note, dur, vel in canon_phrase:
|
|
pwm.add(note, dur, velocity=max(20, vel - 8))
|
|
for note, dur, vel in canon_phrase:
|
|
pwm.add(note, dur, velocity=max(20, vel - 15))
|
|
pwm.rest(Duration.WHOLE)
|
|
|
|
# Others drone
|
|
for _ in range(8):
|
|
sq.rest(Duration.WHOLE)
|
|
saw.set(volume=0.25)
|
|
for _ in range(8):
|
|
saw.add(F.add(-12), Duration.WHOLE, velocity=30)
|
|
for _ in range(8):
|
|
fm.rest(Duration.WHOLE)
|
|
for _ in range(8):
|
|
wf.rest(Duration.WHOLE)
|
|
for _ in range(2):
|
|
for chord in prog:
|
|
pad.add(chord, Duration.WHOLE, velocity=35)
|
|
for _ in range(8):
|
|
sub.add(F.add(-24), Duration.WHOLE, velocity=30)
|
|
for _ in range(8):
|
|
kick.rest(Duration.WHOLE)
|
|
for _ in range(8):
|
|
hats.rest(Duration.WHOLE)
|
|
for _ in range(8):
|
|
snare.rest(Duration.WHOLE)
|
|
for _ in range(8):
|
|
sine_pad.rest(Duration.WHOLE)
|
|
tri_pad.add(Ab.add(-12), Duration.WHOLE, velocity=35)
|
|
tri_pad.add(Db, Duration.WHOLE, velocity=32)
|
|
for _ in range(6):
|
|
tri_pad.rest(Duration.WHOLE)
|
|
for _ in range(8):
|
|
saw_pad.rest(Duration.WHOLE)
|
|
for _ in range(8):
|
|
lead.rest(Duration.WHOLE)
|
|
|
|
# ── Bars 89-96: FINALE — all 9 back together, then dissolve ────
|
|
# One last full statement, then they leave one by one
|
|
|
|
# Everyone plays their phrase one more time — fortissimo
|
|
sine.set(volume=0.45)
|
|
for _ in range(4):
|
|
for note, dur, vel in sine_phrase:
|
|
if note is None:
|
|
sine.rest(dur)
|
|
else:
|
|
sine.add(note, dur, velocity=vel)
|
|
for note, dur, vel in sine_phrase_b:
|
|
if note is None:
|
|
sine.rest(dur)
|
|
else:
|
|
sine.add(note, dur, velocity=max(20, vel - 15))
|
|
|
|
tri.set(volume=0.35)
|
|
for _ in range(4):
|
|
for note, dur, vel in tri_phrase:
|
|
if note is None:
|
|
tri.rest(dur)
|
|
else:
|
|
tri.add(note, dur, velocity=vel)
|
|
for note, dur, vel in tri_phrase_b:
|
|
if note is None:
|
|
tri.rest(dur)
|
|
else:
|
|
tri.add(note, dur, velocity=max(18, vel - 15))
|
|
|
|
sq.set(volume=0.25)
|
|
for _ in range(8):
|
|
for note, dur, vel in sq_stab:
|
|
if note is None:
|
|
sq.rest(dur)
|
|
else:
|
|
sq.add(note, dur, velocity=max(20, vel - 15))
|
|
|
|
saw.set(volume=0.3)
|
|
for _ in range(4):
|
|
for note in arp_a:
|
|
saw.add(note, Duration.EIGHTH, velocity=55)
|
|
for note in arp_b:
|
|
saw.add(note, Duration.EIGHTH, velocity=52)
|
|
|
|
fm.set(volume=0.2)
|
|
for _ in range(8):
|
|
for note, dur, vel in fm_phrase:
|
|
if note is None:
|
|
fm.rest(dur)
|
|
else:
|
|
fm.add(note, dur, velocity=max(18, vel - 18))
|
|
|
|
pwm.set(volume=0.18)
|
|
for _ in range(8):
|
|
for note, dur, vel in pwm_phrase:
|
|
if note is None:
|
|
pwm.rest(dur)
|
|
else:
|
|
pwm.add(note, dur, velocity=max(15, vel - 20))
|
|
|
|
wf.set(volume=0.12)
|
|
for _ in range(8):
|
|
for note, dur, vel in wf_phrase:
|
|
if note is None:
|
|
wf.rest(dur)
|
|
else:
|
|
wf.add(note, dur, velocity=max(15, vel - 22))
|
|
|
|
for _ in range(2):
|
|
for chord in prog:
|
|
pad.add(chord, Duration.WHOLE, velocity=35)
|
|
|
|
for vel in [30, 25, 22, 18, 15, 12, 8, 0]:
|
|
if vel > 0:
|
|
sub.add(F.add(-24), Duration.WHOLE, velocity=vel)
|
|
else:
|
|
sub.rest(Duration.WHOLE)
|
|
|
|
for vel in [80, 68, 55, 42, 30, 18, 0, 0]:
|
|
if vel > 0:
|
|
for beat in range(4):
|
|
kick.hit(K, Duration.QUARTER, velocity=vel)
|
|
else:
|
|
kick.rest(Duration.WHOLE)
|
|
|
|
for vel in [45, 38, 30, 22, 15, 0, 0, 0]:
|
|
if vel > 0:
|
|
for beat in range(4):
|
|
hats.rest(Duration.EIGHTH)
|
|
hats.hit(CH, Duration.EIGHTH, velocity=vel)
|
|
else:
|
|
hats.rest(Duration.WHOLE)
|
|
|
|
for vel in [70, 58, 45, 32, 20, 0, 0, 0]:
|
|
if vel > 0:
|
|
snare.rest(Duration.QUARTER)
|
|
snare.hit(S, Duration.QUARTER, velocity=vel)
|
|
snare.rest(Duration.HALF)
|
|
else:
|
|
snare.rest(Duration.WHOLE)
|
|
|
|
for vel in [30, 25, 20, 15, 10, 5, 0, 0]:
|
|
if vel > 0:
|
|
sine_pad.add(F.add(-12), Duration.WHOLE, velocity=vel)
|
|
else:
|
|
sine_pad.rest(Duration.WHOLE)
|
|
|
|
for _ in range(8):
|
|
tri_pad.rest(Duration.WHOLE)
|
|
for _ in range(8):
|
|
saw_pad.rest(Duration.WHOLE)
|
|
|
|
for _ in range(8):
|
|
lead.rest(Duration.WHOLE)
|
|
|
|
# ═════════════════════════════════════════════════════════════════
|
|
import sys
|
|
|
|
print(f"Key: {key}")
|
|
print(f"BPM: 118")
|
|
print(f"Parts: {list(score.parts.keys())}")
|
|
print(f"Duration: {score.duration_ms / 1000:.1f}s | {score.measures} measures")
|
|
|
|
if "--live" in sys.argv:
|
|
print("Playing WAVEFORMS (live engine)...")
|
|
from pytheory_live.live import LiveEngine
|
|
engine = LiveEngine(buffer_size=1024)
|
|
engine.play_score(score)
|
|
else:
|
|
print("Playing WAVEFORMS...")
|
|
play_score(score)
|