mirror of
https://github.com/kennethreitz/interpretations.git
synced 2026-06-05 14:50:20 +00:00
a9b356f5cc
Silk Road: mellotron_flute in finale. The Dialogue: drift pad, mellotron ending. Acid Reign: wavefold in breakdown. Chakra: drift at crown. Raga Midnight: mellotron_strings over 808 drop. The Temple: granular_pad texture. Sleight of Hand: mellotron_choir. Gravity: drift tambura. Ghost Protocol: NES pulled back. An Exception: psycho bass 0.3. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
483 lines
17 KiB
Python
483 lines
17 KiB
Python
"""
|
|
GRAVITY — heavy. Piano, 808, snap. The weight of it all.
|
|
C minor, 88 BPM. No gimmicks. Just pressure.
|
|
"""
|
|
|
|
from pytheory import Key, Duration, Score, Tone, play_score
|
|
from pytheory.rhythm import DrumSound
|
|
|
|
key = Key("C", "minor")
|
|
s = key.scale # C D Eb F G Ab Bb
|
|
|
|
C = s[0]; D = s[1]; Eb = s[2]; F = s[3]
|
|
G = s[4]; Ab = s[5]; Bb = s[6]
|
|
|
|
score = Score("4/4", bpm=88)
|
|
|
|
prog = key.progression("i", "VI", "iv", "VII")
|
|
prog2 = key.progression("i", "VII", "VI", "v")
|
|
|
|
K = DrumSound.KICK
|
|
S = DrumSound.SNARE
|
|
CH = DrumSound.CLOSED_HAT
|
|
OH = DrumSound.OPEN_HAT
|
|
CL = DrumSound.CLAP
|
|
|
|
# ═══════════════════════════════════════════════════════════════════
|
|
# STRUCTURE (64 bars, ~2:55):
|
|
# Bars 1-4: Piano alone — the weight
|
|
# Bars 5-8: 808 enters — the floor drops
|
|
# Bars 9-16: Drums — boom bap + trap hats
|
|
# Bars 17-24: Full groove — everything locked
|
|
# Bars 25-32: Melody — Rhodes sings over the beat
|
|
# Bars 33-40: Breakdown — stripped back, just piano + 808
|
|
# Bars 41-48: Build — drums return harder, strings swell
|
|
# Bars 49-56: Peak — everything, hats going wild
|
|
# Bars 57-64: Outro — peeling away, piano last
|
|
# ═══════════════════════════════════════════════════════════════════
|
|
|
|
# ── PIANO — the foundation, dark chords ────────────────────────
|
|
piano = score.part("piano", instrument="piano", volume=0.5,
|
|
reverb=0.4, reverb_type="taj_mahal",
|
|
delay=0.12, delay_time=0.341, delay_feedback=0.2,
|
|
pan=-0.15, humanize=0.1)
|
|
|
|
# Piano patterns — sparse hits, let the space breathe
|
|
# Pattern A: stab, silence, low octave hit
|
|
def piano_bar_a(chord, vel):
|
|
piano.add(chord, Duration.EIGHTH, velocity=vel)
|
|
piano.rest(Duration.QUARTER)
|
|
piano.rest(Duration.EIGHTH)
|
|
piano.rest(Duration.QUARTER)
|
|
piano.add(chord, Duration.EIGHTH, velocity=max(30, vel - 20))
|
|
piano.rest(Duration.EIGHTH)
|
|
|
|
# Pattern B: low single note, space, high stab
|
|
def piano_bar_b(root, vel):
|
|
piano.add(root.add(-12), Duration.EIGHTH, velocity=vel)
|
|
piano.rest(Duration.DOTTED_QUARTER)
|
|
piano.rest(Duration.EIGHTH)
|
|
piano.add(root.add(12), Duration.SIXTEENTH, velocity=max(30, vel - 10))
|
|
piano.rest(Duration.SIXTEENTH)
|
|
piano.rest(Duration.QUARTER)
|
|
|
|
# Pattern C: two quick stabs then nothing
|
|
def piano_bar_c(chord, vel):
|
|
piano.rest(Duration.EIGHTH)
|
|
piano.add(chord, Duration.SIXTEENTH, velocity=vel)
|
|
piano.rest(Duration.SIXTEENTH)
|
|
piano.add(chord, Duration.EIGHTH, velocity=max(30, vel - 15))
|
|
piano.rest(Duration.HALF)
|
|
piano.rest(Duration.QUARTER)
|
|
|
|
single_roots = [C, Ab.add(-12), F, Bb]
|
|
|
|
# Bars 1-4: alone — just drops into silence
|
|
for i, chord in enumerate(prog):
|
|
piano_bar_a(chord, 78)
|
|
|
|
# Bars 5-8: 808 enters, piano gets sparser
|
|
for i, (chord, root) in enumerate(zip(prog, single_roots)):
|
|
piano_bar_b(root, 75)
|
|
|
|
# Bars 9-32: alternating patterns, never predictable
|
|
for section in range(6):
|
|
p = prog if section % 2 == 0 else prog2
|
|
r = single_roots if section % 2 == 0 else [C, Bb, Ab.add(-12), G]
|
|
vel = 78
|
|
piano_bar_a(p[0], vel)
|
|
piano_bar_b(r[1], vel)
|
|
piano_bar_c(p[2], vel)
|
|
piano_bar_a(p[3], vel)
|
|
|
|
# Bars 33-40: breakdown — barely there, single low notes
|
|
for root in single_roots * 2:
|
|
piano.add(root.add(-12), Duration.QUARTER, velocity=55)
|
|
piano.rest(Duration.DOTTED_HALF)
|
|
|
|
# Bars 41-56: back, patterns return harder
|
|
for section in range(4):
|
|
p = prog if section % 2 == 0 else prog2
|
|
r = single_roots if section % 2 == 0 else [C, Bb, Ab.add(-12), G]
|
|
vel = 82
|
|
piano_bar_a(p[0], vel)
|
|
piano_bar_c(p[1], vel)
|
|
piano_bar_b(r[2], vel)
|
|
piano_bar_a(p[3], vel)
|
|
|
|
# Bars 57-64: fading — one note per bar, dissolving
|
|
for root, vel in zip([C, Eb, G, Ab, Eb, C, G.add(-12), C.add(-12)],
|
|
[65, 58, 52, 45, 38, 32, 25, 18]):
|
|
piano.add(root, Duration.QUARTER, velocity=vel)
|
|
piano.rest(Duration.DOTTED_HALF)
|
|
|
|
# ── 808 — the floor, slides between roots ─────────────────────
|
|
sub = score.part("808", synth="sine", envelope="pad", volume=0.7,
|
|
lowpass=200, distortion=0.2, distortion_drive=3.0,
|
|
sub_osc=0.5, saturation=0.4, sidechain=0.35)
|
|
|
|
# Bars 1-4: silent
|
|
for _ in range(4):
|
|
sub.rest(Duration.WHOLE)
|
|
|
|
# Bars 5-64: 808 — continuous wave, one root per bar
|
|
roots = [C.add(-24), Ab.add(-24), F.add(-24), Bb.add(-24)]
|
|
roots2 = [C.add(-24), Bb.add(-24), Ab.add(-24), G.add(-24)]
|
|
|
|
for section in range(15):
|
|
r = roots if section % 2 == 0 else roots2
|
|
vel = 42 if section < 12 else max(18, 42 - (section - 12) * 8)
|
|
for root in r:
|
|
sub.add(root, Duration.WHOLE, velocity=vel)
|
|
|
|
# ── KICK — boom bap pocket ────────────────────────────────────
|
|
kick = score.part("kick", volume=0.8, humanize=0.04,
|
|
distortion=0.08, distortion_drive=1.5)
|
|
|
|
# Bars 1-8: silent
|
|
for _ in range(8):
|
|
kick.rest(Duration.WHOLE)
|
|
|
|
# Bars 9-32: boom bap — kick on 1, and-of-2, 3
|
|
for _ in range(24):
|
|
kick.hit(K, Duration.QUARTER, velocity=112)
|
|
kick.rest(Duration.EIGHTH)
|
|
kick.hit(K, Duration.EIGHTH, velocity=95)
|
|
kick.hit(K, Duration.QUARTER, velocity=108)
|
|
kick.rest(Duration.QUARTER)
|
|
|
|
# Bars 33-40: breakdown — just beat 1
|
|
for _ in range(8):
|
|
kick.hit(K, Duration.QUARTER, velocity=100)
|
|
kick.rest(Duration.DOTTED_HALF)
|
|
|
|
# Bars 41-56: back full, harder
|
|
for _ in range(16):
|
|
kick.hit(K, Duration.QUARTER, velocity=118)
|
|
kick.rest(Duration.EIGHTH)
|
|
kick.hit(K, Duration.EIGHTH, velocity=100)
|
|
kick.hit(K, Duration.QUARTER, velocity=112)
|
|
kick.rest(Duration.QUARTER)
|
|
|
|
# Bars 57-64: fading
|
|
for vel in [105, 95, 85, 75, 62, 48, 35, 22]:
|
|
kick.hit(K, Duration.QUARTER, velocity=vel)
|
|
kick.rest(Duration.DOTTED_HALF)
|
|
|
|
# ── SNARE — crack on 2 and 4 ──────────────────────────────────
|
|
snare = score.part("snare", volume=0.55, humanize=0.04,
|
|
reverb=0.2, reverb_decay=0.8,
|
|
delay=0.08, delay_time=0.341, delay_feedback=0.12,
|
|
pan=0.05)
|
|
|
|
for _ in range(8):
|
|
snare.rest(Duration.WHOLE)
|
|
|
|
# Bars 9-32: 2 and 4
|
|
for _ in range(24):
|
|
snare.rest(Duration.QUARTER)
|
|
snare.hit(S, Duration.QUARTER, velocity=105)
|
|
snare.rest(Duration.QUARTER)
|
|
snare.hit(S, Duration.QUARTER, velocity=108)
|
|
|
|
# Bars 33-40: breakdown — ghost snares
|
|
for _ in range(8):
|
|
snare.rest(Duration.QUARTER)
|
|
snare.hit(S, Duration.QUARTER, velocity=55)
|
|
snare.rest(Duration.QUARTER)
|
|
snare.hit(S, Duration.QUARTER, velocity=50)
|
|
|
|
# Bars 41-56: back hard
|
|
for _ in range(16):
|
|
snare.rest(Duration.QUARTER)
|
|
snare.hit(S, Duration.QUARTER, velocity=110)
|
|
snare.rest(Duration.QUARTER)
|
|
snare.hit(S, Duration.QUARTER, velocity=112)
|
|
|
|
# Bars 57-64: fading
|
|
for vel in [100, 88, 75, 62, 50, 38, 25, 15]:
|
|
snare.rest(Duration.QUARTER)
|
|
snare.hit(S, Duration.QUARTER, velocity=vel)
|
|
snare.rest(Duration.HALF)
|
|
|
|
# ── HATS — trap-style, evolving patterns ───────────────────────
|
|
hats = score.part("hats", volume=0.28, pan=0.2, humanize=0.05)
|
|
|
|
for _ in range(8):
|
|
hats.rest(Duration.WHOLE)
|
|
|
|
# Bars 9-16: simple 8ths
|
|
for _ in range(8):
|
|
for beat in range(4):
|
|
hats.hit(CH, Duration.EIGHTH, velocity=72)
|
|
hats.hit(CH, Duration.EIGHTH, velocity=48)
|
|
|
|
# Bars 17-24: 16ths creep in
|
|
for _ in range(8):
|
|
hats.hit(CH, Duration.EIGHTH, velocity=72)
|
|
hats.hit(CH, Duration.EIGHTH, velocity=48)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=68)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=42)
|
|
hats.hit(CH, Duration.EIGHTH, velocity=55)
|
|
hats.hit(CH, Duration.EIGHTH, velocity=72)
|
|
hats.hit(CH, Duration.EIGHTH, velocity=48)
|
|
hats.hit(OH, Duration.EIGHTH, velocity=62)
|
|
|
|
# Bars 25-32: more active, triplet feel creeps in
|
|
for _ in range(8):
|
|
hats.hit(CH, Duration.EIGHTH, velocity=72)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=52)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=48)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=68)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=42)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=55)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=42)
|
|
hats.hit(CH, Duration.EIGHTH, velocity=72)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=48)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=52)
|
|
hats.hit(OH, Duration.EIGHTH, velocity=60)
|
|
|
|
# Bars 33-40: breakdown — barely there
|
|
for _ in range(8):
|
|
hats.hit(CH, Duration.QUARTER, velocity=35)
|
|
hats.rest(Duration.DOTTED_HALF)
|
|
|
|
# Bars 41-48: build back — 16ths
|
|
for _ in range(8):
|
|
for beat in range(4):
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=72)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=42)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=55)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=38)
|
|
|
|
# Bars 49-56: PEAK — 32nd note hat rolls scattered
|
|
for bar in range(8):
|
|
if bar % 2 == 1:
|
|
# 32nd note roll bar
|
|
for i in range(32):
|
|
vel = min(90, 40 + (i % 8) * 6)
|
|
hats.hit(CH, 0.125, velocity=vel)
|
|
else:
|
|
# Normal 16th bar with open hat
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=75)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=45)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=58)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=42)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=70)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=45)
|
|
hats.hit(OH, Duration.SIXTEENTH, velocity=62)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=42)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=72)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=48)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=55)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=42)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=68)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=45)
|
|
hats.hit(OH, Duration.SIXTEENTH, velocity=60)
|
|
hats.hit(CH, Duration.SIXTEENTH, velocity=38)
|
|
|
|
# Bars 57-64: fading
|
|
for vel in [60, 52, 44, 36, 28, 22, 15, 0]:
|
|
if vel > 0:
|
|
for beat in range(4):
|
|
hats.hit(CH, Duration.EIGHTH, velocity=vel)
|
|
hats.hit(CH, Duration.EIGHTH, velocity=max(12, vel - 25))
|
|
else:
|
|
hats.rest(Duration.WHOLE)
|
|
|
|
# ── TAMBURA — buried drone, barely there, just warmth ──────────
|
|
tambura = score.part("tambura", synth="drift", envelope="pad", volume=0.08,
|
|
reverb=0.5, reverb_type="taj_mahal",
|
|
chorus=0.3, chorus_rate=0.06, chorus_depth=0.01,
|
|
lowpass=800, pan=-0.3)
|
|
|
|
for _ in range(4):
|
|
tambura.rest(Duration.WHOLE)
|
|
for _ in range(52):
|
|
tambura.add(C.add(-24), Duration.WHOLE, velocity=35)
|
|
for vel in [28, 22, 16, 10, 6, 3, 0, 0]:
|
|
if vel > 0:
|
|
tambura.add(C.add(-24), Duration.WHOLE, velocity=vel)
|
|
else:
|
|
tambura.rest(Duration.WHOLE)
|
|
|
|
# ── SINGING BOWL — bookends, marks the gravity ────────────────
|
|
bowl = score.part("bowl", instrument="singing_bowl", volume=0.3,
|
|
reverb=0.8, reverb_type="taj_mahal",
|
|
delay=0.15, delay_time=0.682, delay_feedback=0.2,
|
|
pan=0.2)
|
|
|
|
bowl.add(C.add(-24), Duration.WHOLE, velocity=65)
|
|
for _ in range(62):
|
|
bowl.rest(Duration.WHOLE)
|
|
bowl.add(C.add(-24), Duration.WHOLE, velocity=50)
|
|
|
|
# ── SITAR — one bend in the breakdown, like a ghost ───────────
|
|
sitar = score.part("sitar", instrument="sitar", volume=0.25,
|
|
reverb=0.35, reverb_type="taj_mahal",
|
|
delay=0.2, delay_time=0.341, delay_feedback=0.3,
|
|
pan=0.3, humanize=0.08)
|
|
|
|
for _ in range(34):
|
|
sitar.rest(Duration.WHOLE)
|
|
|
|
# Bar 35-36: one long bent note — the sample flip moment
|
|
sitar.add(Eb, Duration.WHOLE, velocity=65, bend=-0.25)
|
|
sitar.add(C, Duration.WHOLE, velocity=55, bend=0.15)
|
|
|
|
# Bar 37: quick ornamental phrase then gone
|
|
sitar.add(Eb, Duration.QUARTER, velocity=60)
|
|
sitar.add(D, Duration.EIGHTH, velocity=55)
|
|
sitar.add(C, Duration.EIGHTH, velocity=52)
|
|
sitar.add(Bb.add(-12), Duration.HALF, velocity=58, bend=-0.15)
|
|
|
|
for _ in range(27):
|
|
sitar.rest(Duration.WHOLE)
|
|
|
|
# ── CLAP — layered with snare for weight ───────────────────────
|
|
clap = score.part("clap", volume=0.2, reverb=0.15,
|
|
delay=0.06, delay_time=0.341, delay_feedback=0.1,
|
|
pan=-0.08, humanize=0.04)
|
|
|
|
for _ in range(16):
|
|
clap.rest(Duration.WHOLE)
|
|
|
|
# Bars 17-32: layered on snare hits
|
|
for _ in range(16):
|
|
clap.rest(Duration.QUARTER)
|
|
clap.hit(CL, Duration.QUARTER, velocity=82)
|
|
clap.rest(Duration.QUARTER)
|
|
clap.hit(CL, Duration.QUARTER, velocity=85)
|
|
|
|
# Bars 33-40: silent
|
|
for _ in range(8):
|
|
clap.rest(Duration.WHOLE)
|
|
|
|
# Bars 41-56: back
|
|
for _ in range(16):
|
|
clap.rest(Duration.QUARTER)
|
|
clap.hit(CL, Duration.QUARTER, velocity=85)
|
|
clap.rest(Duration.QUARTER)
|
|
clap.hit(CL, Duration.QUARTER, velocity=88)
|
|
|
|
# Bars 57-64: silent
|
|
for _ in range(8):
|
|
clap.rest(Duration.WHOLE)
|
|
|
|
# ── RHODES — melody enters bar 25, the soul ───────────────────
|
|
rhodes = score.part("rhodes", instrument="electric_piano", volume=0.3,
|
|
reverb=0.5, reverb_type="taj_mahal",
|
|
delay=0.2, delay_time=0.341, delay_feedback=0.3,
|
|
tremolo_depth=0.1, tremolo_rate=2.5,
|
|
pan=0.25, humanize=0.08)
|
|
|
|
for _ in range(24):
|
|
rhodes.rest(Duration.WHOLE)
|
|
|
|
# Bars 25-32: melody — simple, soulful, singing
|
|
melody = [
|
|
(Eb.add(12), Duration.HALF, 80), (D.add(12), Duration.QUARTER, 72),
|
|
(C.add(12), Duration.QUARTER, 75),
|
|
(Bb, Duration.HALF, 78), (Ab, Duration.QUARTER, 70),
|
|
(G, Duration.QUARTER, 72),
|
|
(Ab, Duration.DOTTED_HALF, 80), (G, Duration.QUARTER, 72),
|
|
(F, Duration.HALF, 75), (Eb, Duration.HALF, 78),
|
|
(G, Duration.HALF, 80), (Ab, Duration.QUARTER, 75),
|
|
(Bb, Duration.QUARTER, 72),
|
|
(C.add(12), Duration.HALF, 82), (Bb, Duration.QUARTER, 75),
|
|
(Ab, Duration.QUARTER, 70),
|
|
(G, Duration.WHOLE, 78),
|
|
(None, Duration.WHOLE, 0),
|
|
]
|
|
for note, dur, vel in melody:
|
|
if note is None:
|
|
rhodes.rest(dur)
|
|
else:
|
|
rhodes.add(note, dur, velocity=vel)
|
|
|
|
# Bars 33-40: silent through breakdown
|
|
for _ in range(8):
|
|
rhodes.rest(Duration.WHOLE)
|
|
|
|
# Bars 41-48: melody returns, stronger
|
|
for note, dur, vel in melody:
|
|
if note is None:
|
|
rhodes.rest(dur)
|
|
else:
|
|
rhodes.add(note, dur, velocity=min(127, vel + 8))
|
|
|
|
# Bars 49-56: variation — higher, more intense
|
|
melody2 = [
|
|
(G.add(12), Duration.QUARTER, 85), (Ab.add(12), Duration.QUARTER, 82),
|
|
(Bb.add(12), Duration.HALF, 88),
|
|
(Ab.add(12), Duration.QUARTER, 80), (G.add(12), Duration.QUARTER, 78),
|
|
(Eb.add(12), Duration.HALF, 82),
|
|
(D.add(12), Duration.QUARTER, 78), (Eb.add(12), Duration.QUARTER, 80),
|
|
(G.add(12), Duration.HALF, 85),
|
|
(C.add(12), Duration.WHOLE, 82),
|
|
(Bb, Duration.HALF, 78), (Ab, Duration.QUARTER, 72),
|
|
(G, Duration.QUARTER, 70),
|
|
(Eb, Duration.WHOLE, 75),
|
|
(None, Duration.WHOLE, 0),
|
|
(None, Duration.WHOLE, 0),
|
|
]
|
|
for note, dur, vel in melody2:
|
|
if note is None:
|
|
rhodes.rest(dur)
|
|
else:
|
|
rhodes.add(note, dur, velocity=vel)
|
|
|
|
# Bars 57-64: one last phrase, fading
|
|
rhodes.add(Eb.add(12), Duration.HALF, velocity=65)
|
|
rhodes.add(C.add(12), Duration.HALF, velocity=58)
|
|
rhodes.add(G, Duration.WHOLE, velocity=50)
|
|
for _ in range(6):
|
|
rhodes.rest(Duration.WHOLE)
|
|
|
|
# ── STRINGS — swell at bar 41, the drama ──────────────────────
|
|
strings = score.part("strings", instrument="string_ensemble", volume=0.15,
|
|
reverb=0.6, reverb_type="cathedral",
|
|
chorus=0.2, chorus_rate=0.15, chorus_depth=0.006,
|
|
pan=-0.2)
|
|
|
|
for _ in range(40):
|
|
strings.rest(Duration.WHOLE)
|
|
|
|
# Bars 41-56: slow swells under the beat
|
|
for _ in range(4):
|
|
for chord in prog:
|
|
strings.add(chord, Duration.WHOLE, velocity=48)
|
|
|
|
# Bars 57-64: fading
|
|
for vel in [42, 35, 28, 22, 18, 12, 8, 0]:
|
|
if vel > 0:
|
|
strings.add(prog[0], Duration.WHOLE, velocity=vel)
|
|
else:
|
|
strings.rest(Duration.WHOLE)
|
|
|
|
# ── VINYL — lo-fi texture throughout ──────────────────────────
|
|
vinyl = score.part("vinyl", synth="noise", envelope="pad", volume=0.025,
|
|
lowpass=1500, highpass=500,
|
|
distortion=0.3, distortion_drive=2.5,
|
|
saturation=0.5, pan=0.1)
|
|
|
|
for _ in range(64):
|
|
vinyl.add(C, Duration.WHOLE, velocity=20)
|
|
|
|
# ═════════════════════════════════════════════════════════════════
|
|
import sys
|
|
|
|
print(f"Key: {key}")
|
|
print(f"BPM: 88")
|
|
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 GRAVITY (live engine)...")
|
|
from pytheory_live.live import LiveEngine
|
|
engine = LiveEngine(buffer_size=1024)
|
|
engine.play_score(score)
|
|
else:
|
|
print("Playing GRAVITY...")
|
|
play_score(score)
|