mirror of
https://github.com/kennethreitz/interpretations.git
synced 2026-06-05 06:46:15 +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>
628 lines
25 KiB
Python
628 lines
25 KiB
Python
"""
|
|
THE DIALOGUE — two voices learning to speak together.
|
|
Sitar (human) and theremin (machine) start alone, find each other,
|
|
and become something neither could be on their own.
|
|
"""
|
|
|
|
from pytheory import Key, Duration, Score, Tone, play_score
|
|
from pytheory.rhythm import DrumSound
|
|
|
|
key = Key("E", "phrygian")
|
|
s = key.scale # E F G A B C D
|
|
|
|
Sa = s[0] # E (Sa)
|
|
Re = s[1] # F (komal Re)
|
|
Ga = s[2] # G (komal Ga)
|
|
Ma = s[3] # A (Ma)
|
|
Pa = s[4] # B (Pa)
|
|
Dha = s[5] # C (komal Dha)
|
|
Ni = s[6] # D (komal Ni)
|
|
|
|
score = Score("4/4", bpm=75, system="shruti", temperament="just",
|
|
reference_pitch=432.0)
|
|
|
|
# ═══════════════════════════════════════════════════════════════════
|
|
# STRUCTURE (80 bars, ~7 min):
|
|
# Bars 1-8: Silence, then tambura — the shared space opens
|
|
# Bars 9-16: Sitar alone — the human speaks first
|
|
# Bars 17-24: Theremin alone — the machine responds
|
|
# Bars 25-32: Call and response — they notice each other
|
|
# Bars 33-40: Weaving together — phrases overlap
|
|
# Bars 41-48: Tabla enters — they've found a shared pulse
|
|
# Bars 49-56: Harmonium + choir — the harmony deepens
|
|
# Bars 57-64: The peak — full communion, everyone singing
|
|
# Bars 65-72: Unwinding — voices separate but changed
|
|
# Bars 73-80: Silence returns — but different from before
|
|
# ═══════════════════════════════════════════════════════════════════
|
|
|
|
# ── TAMBURA — the shared space, the room they're both in ────────
|
|
tambura = score.part("tambura", synth="sine", envelope="pad", volume=0.25,
|
|
reverb=0.95, reverb_type="taj_mahal",
|
|
chorus=0.5, chorus_rate=0.06, chorus_depth=0.012,
|
|
lowpass=900, pan=-0.2, saturation=0.15)
|
|
|
|
# Bars 1-4: silence
|
|
for _ in range(4):
|
|
tambura.rest(Duration.WHOLE)
|
|
|
|
# Bars 5-8: fade in — the space opens
|
|
for vel in [15, 25, 35, 45]:
|
|
tambura.add(Sa.add(-24), Duration.HALF, velocity=vel)
|
|
tambura.add(Pa.add(-24), Duration.HALF, velocity=max(10, vel - 8))
|
|
|
|
# Bars 9-72: full drone
|
|
for _ in range(64):
|
|
tambura.add(Sa.add(-24), Duration.HALF, velocity=55)
|
|
tambura.add(Pa.add(-24), Duration.HALF, velocity=48)
|
|
|
|
# Bars 73-80: fade out
|
|
for vel in [48, 40, 32, 25, 18, 12, 6, 0]:
|
|
if vel > 0:
|
|
tambura.add(Sa.add(-24), Duration.HALF, velocity=vel)
|
|
tambura.add(Pa.add(-24), Duration.HALF, velocity=max(5, vel - 8))
|
|
else:
|
|
tambura.rest(Duration.WHOLE)
|
|
|
|
# ── TAMBURA HIGH — octave shimmer ──────────────────────────────
|
|
tambura_hi = score.part("tambura_hi", synth="sine", envelope="pad", volume=0.15,
|
|
reverb=0.95, reverb_type="taj_mahal",
|
|
chorus=0.6, chorus_rate=0.04, chorus_depth=0.015,
|
|
lowpass=1400, pan=0.25)
|
|
|
|
for _ in range(8):
|
|
tambura_hi.rest(Duration.WHOLE)
|
|
for _ in range(64):
|
|
tambura_hi.add(Sa.add(-12), Duration.WHOLE, velocity=40)
|
|
for vel in [35, 28, 20, 14, 10, 6, 3, 0]:
|
|
if vel > 0:
|
|
tambura_hi.add(Sa.add(-12), Duration.WHOLE, velocity=vel)
|
|
else:
|
|
tambura_hi.rest(Duration.WHOLE)
|
|
|
|
# ── SINGING BOWL — marks transitions ───────────────────────────
|
|
bowl = score.part("bowl", instrument="singing_bowl", volume=0.5,
|
|
reverb=1.0, reverb_type="taj_mahal",
|
|
delay=0.35, delay_time=0.8, delay_feedback=0.45)
|
|
|
|
# Strike at key structural moments
|
|
bowl_bars = [1, 9, 17, 25, 33, 41, 49, 57, 73]
|
|
bar = 1
|
|
for b in range(80):
|
|
bar = b + 1
|
|
if bar in bowl_bars:
|
|
vel = 75 if bar <= 57 else 55
|
|
bowl.add(Sa.add(-24), Duration.WHOLE, velocity=vel)
|
|
else:
|
|
bowl.rest(Duration.WHOLE)
|
|
|
|
# ── SUB DRONE — felt not heard ─────────────────────────────────
|
|
sub = score.part("sub", synth="sine", envelope="pad", volume=0.15,
|
|
lowpass=80, saturation=0.1)
|
|
|
|
for _ in range(8):
|
|
sub.rest(Duration.WHOLE)
|
|
for _ in range(64):
|
|
sub.add(Sa.add(-36), Duration.WHOLE, velocity=55)
|
|
for vel in [45, 35, 25, 18, 12, 8, 4, 0]:
|
|
if vel > 0:
|
|
sub.add(Sa.add(-36), Duration.WHOLE, velocity=vel)
|
|
else:
|
|
sub.rest(Duration.WHOLE)
|
|
|
|
# ── SITAR — the human voice ────────────────────────────────────
|
|
sitar = score.part("sitar", instrument="sitar", volume=0.7,
|
|
reverb=0.35, reverb_type="taj_mahal",
|
|
delay=0.25, delay_time=0.4, delay_feedback=0.3,
|
|
pan=-0.25, saturation=0.25, humanize=0.12)
|
|
|
|
# Bars 1-8: silent — waiting
|
|
for _ in range(8):
|
|
sitar.rest(Duration.WHOLE)
|
|
|
|
# Bars 9-16: SITAR ALONE — tentative, exploring
|
|
# Phrase 1: simple, feeling the space
|
|
sitar.add(Sa, Duration.WHOLE, velocity=75, bend=-0.15)
|
|
sitar.rest(Duration.WHOLE)
|
|
sitar.add(Re, Duration.HALF, velocity=70)
|
|
sitar.add(Sa, Duration.HALF, velocity=78)
|
|
sitar.rest(Duration.WHOLE)
|
|
|
|
# Phrase 2: reaching a little further
|
|
sitar.add(Ga, Duration.DOTTED_HALF, velocity=80)
|
|
sitar.rest(Duration.QUARTER)
|
|
sitar.add(Ma, Duration.QUARTER, velocity=75)
|
|
sitar.add(Ga, Duration.QUARTER, velocity=70)
|
|
sitar.add(Re, Duration.QUARTER, velocity=68)
|
|
sitar.add(Sa, Duration.QUARTER, velocity=72)
|
|
sitar.rest(Duration.WHOLE)
|
|
|
|
# Bars 17-24: silent while theremin speaks
|
|
for _ in range(8):
|
|
sitar.rest(Duration.WHOLE)
|
|
|
|
# Bars 25-32: CALL AND RESPONSE — sitar calls
|
|
# Bar 25-26: sitar phrase
|
|
sitar.add(Sa, Duration.QUARTER, velocity=85)
|
|
sitar.add(Ga, Duration.QUARTER, velocity=80)
|
|
sitar.add(Pa, Duration.HALF, velocity=88, bend=-0.15)
|
|
sitar.rest(Duration.WHOLE)
|
|
# Bar 27-28: rest while theremin responds
|
|
sitar.rest(Duration.WHOLE)
|
|
sitar.rest(Duration.WHOLE)
|
|
# Bar 29-30: sitar answers back, climbing higher
|
|
sitar.add(Pa, Duration.QUARTER, velocity=90)
|
|
sitar.add(Dha, Duration.QUARTER, velocity=85)
|
|
sitar.add(Ni, Duration.HALF, velocity=92, bend=-0.2)
|
|
sitar.rest(Duration.WHOLE)
|
|
# Bar 31-32: rest
|
|
sitar.rest(Duration.WHOLE)
|
|
sitar.rest(Duration.WHOLE)
|
|
|
|
# Bars 33-40: WEAVING — phrases start overlapping
|
|
sitar.add(Sa, Duration.EIGHTH, velocity=88)
|
|
sitar.add(Re, Duration.EIGHTH, velocity=82)
|
|
sitar.add(Ga, Duration.QUARTER, velocity=90)
|
|
sitar.add(Ma, Duration.HALF, velocity=85)
|
|
sitar.add(Pa, Duration.QUARTER, velocity=92)
|
|
sitar.add(Ma, Duration.EIGHTH, velocity=82)
|
|
sitar.add(Ga, Duration.EIGHTH, velocity=78)
|
|
sitar.add(Re, Duration.HALF, velocity=80)
|
|
sitar.rest(Duration.WHOLE)
|
|
sitar.add(Ga, Duration.QUARTER, velocity=85)
|
|
sitar.add(Pa, Duration.QUARTER, velocity=90)
|
|
sitar.add(Dha, Duration.HALF, velocity=95, bend=-0.15)
|
|
sitar.add(Pa, Duration.QUARTER, velocity=88)
|
|
sitar.add(Ma, Duration.QUARTER, velocity=82)
|
|
sitar.add(Ga, Duration.QUARTER, velocity=78)
|
|
sitar.add(Sa, Duration.QUARTER, velocity=75)
|
|
sitar.rest(Duration.WHOLE)
|
|
sitar.rest(Duration.WHOLE)
|
|
|
|
# Bars 41-48: SHARED PULSE — more confident, rhythmic
|
|
sitar.set(volume=0.8)
|
|
for _ in range(2):
|
|
sitar.add(Sa, Duration.EIGHTH, velocity=95)
|
|
sitar.add(Ga, Duration.EIGHTH, velocity=88)
|
|
sitar.add(Pa, Duration.QUARTER, velocity=100)
|
|
sitar.add(Dha, Duration.EIGHTH, velocity=92)
|
|
sitar.add(Pa, Duration.EIGHTH, velocity=88)
|
|
sitar.add(Ma, Duration.QUARTER, velocity=85)
|
|
sitar.add(Ga, Duration.EIGHTH, velocity=82)
|
|
sitar.add(Ma, Duration.EIGHTH, velocity=85)
|
|
sitar.add(Pa, Duration.QUARTER, velocity=95)
|
|
sitar.add(Ma, Duration.EIGHTH, velocity=80)
|
|
sitar.add(Ga, Duration.EIGHTH, velocity=78)
|
|
sitar.add(Re, Duration.QUARTER, velocity=82)
|
|
sitar.add(Sa, Duration.HALF, velocity=88, bend=-0.15)
|
|
sitar.rest(Duration.HALF)
|
|
|
|
# Bars 49-56: DEEPENING — sitar plays fuller, more ornamental
|
|
for _ in range(2):
|
|
sitar.add(Sa, Duration.EIGHTH, velocity=100)
|
|
sitar.add(Re, Duration.SIXTEENTH, velocity=85)
|
|
sitar.add(Ga, Duration.SIXTEENTH, velocity=88)
|
|
sitar.add(Ma, Duration.QUARTER, velocity=98)
|
|
sitar.add(Pa, Duration.HALF, velocity=105, bend=-0.15)
|
|
sitar.add(Dha, Duration.QUARTER, velocity=95)
|
|
sitar.add(Pa, Duration.EIGHTH, velocity=90)
|
|
sitar.add(Ma, Duration.EIGHTH, velocity=85)
|
|
sitar.add(Ga, Duration.QUARTER, velocity=88)
|
|
sitar.add(Re, Duration.HALF, velocity=82)
|
|
sitar.add(Sa, Duration.HALF, velocity=90, bend=-0.15)
|
|
sitar.rest(Duration.HALF)
|
|
|
|
# Bars 57-64: THE PEAK — jhala, full power
|
|
sitar.set(volume=0.95)
|
|
# 16th note runs
|
|
for _ in range(2):
|
|
for note, vel in [(Sa,115),(Pa.add(-12),80),(Sa,112),(Pa.add(-12),78),
|
|
(Re,108),(Pa.add(-12),80),(Ga,110),(Pa.add(-12),78),
|
|
(Ma,112),(Pa.add(-12),80),(Pa,115),(Pa.add(-12),82),
|
|
(Dha,118),(Pa.add(-12),80),(Ni,120),(Pa.add(-12),82)]:
|
|
sitar.add(note, Duration.SIXTEENTH, velocity=vel)
|
|
# 32nd note shred — pull reverb back so the notes cut through
|
|
sitar.set(reverb=0.1, delay=0.08)
|
|
for note in [Sa, Re, Ga, Ma, Pa, Dha, Ni, Sa.add(12),
|
|
Sa.add(12), Ni, Dha, Pa, Ma, Ga, Re, Sa]:
|
|
sitar.add(note, 0.125, velocity=125)
|
|
# Descending 32nd
|
|
for note in [Ni, Dha, Pa, Ma, Ga, Re, Sa, Pa.add(-12),
|
|
Sa, Re, Ga, Ma, Pa, Dha, Ni, Sa.add(12)]:
|
|
sitar.add(note, 0.125, velocity=120)
|
|
# Held peak note — reverb back for the sustain
|
|
sitar.set(reverb=0.35, delay=0.25)
|
|
sitar.add(Sa.add(12), Duration.HALF, velocity=127, bend=-0.2)
|
|
sitar.add(Pa, Duration.HALF, velocity=110)
|
|
sitar.add(Sa, Duration.WHOLE, velocity=100, bend=-0.15)
|
|
sitar.rest(Duration.WHOLE)
|
|
|
|
# Bars 65-72: UNWINDING — slower, changed
|
|
sitar.set(volume=0.6)
|
|
sitar.add(Sa, Duration.WHOLE, velocity=75, bend=-0.1)
|
|
sitar.rest(Duration.WHOLE)
|
|
sitar.add(Ga, Duration.HALF, velocity=70)
|
|
sitar.add(Re, Duration.HALF, velocity=68)
|
|
sitar.add(Sa, Duration.WHOLE, velocity=72, bend=-0.15)
|
|
sitar.rest(Duration.WHOLE)
|
|
sitar.add(Pa.add(-12), Duration.HALF, velocity=65)
|
|
sitar.add(Sa, Duration.HALF, velocity=70)
|
|
sitar.rest(Duration.WHOLE)
|
|
sitar.rest(Duration.WHOLE)
|
|
|
|
# Bars 73-80: silence
|
|
for _ in range(8):
|
|
sitar.rest(Duration.WHOLE)
|
|
|
|
# ── THEREMIN — the machine voice ───────────────────────────────
|
|
theremin = score.part("theremin", instrument="theremin", volume=0.42,
|
|
reverb=0.6, reverb_type="taj_mahal",
|
|
delay=0.35, delay_time=0.533, delay_feedback=0.4,
|
|
pan=0.25, humanize=0.04)
|
|
|
|
# Bars 1-16: silent — listening
|
|
for _ in range(16):
|
|
theremin.rest(Duration.WHOLE)
|
|
|
|
# Bars 17-24: THEREMIN ALONE — curious, probing, different phrasing
|
|
# Not trying to sound like sitar — it has its own voice
|
|
theremin.add(Pa.add(12), Duration.WHOLE, velocity=70, bend=1.0)
|
|
theremin.rest(Duration.WHOLE)
|
|
theremin.add(Ma.add(12), Duration.HALF, velocity=65, bend=-0.5)
|
|
theremin.add(Pa.add(12), Duration.HALF, velocity=72, bend=0.5)
|
|
theremin.rest(Duration.WHOLE)
|
|
|
|
theremin.add(Sa.add(24), Duration.HALF, velocity=78, bend=-1.0)
|
|
theremin.add(Ni.add(12), Duration.HALF, velocity=72, bend=0.5)
|
|
theremin.add(Dha.add(12), Duration.HALF, velocity=68, bend=-0.5)
|
|
theremin.add(Pa.add(12), Duration.HALF, velocity=75, bend=0.25)
|
|
theremin.rest(Duration.WHOLE)
|
|
theremin.rest(Duration.WHOLE)
|
|
|
|
# Bars 25-32: CALL AND RESPONSE — theremin responds
|
|
# Bar 25-26: rest while sitar calls
|
|
theremin.rest(Duration.WHOLE)
|
|
theremin.rest(Duration.WHOLE)
|
|
# Bar 27-28: theremin responds — echoing the sitar's phrase but different
|
|
theremin.add(Sa.add(12), Duration.QUARTER, velocity=80, bend=0.5)
|
|
theremin.add(Ga.add(12), Duration.QUARTER, velocity=75, bend=-0.25)
|
|
theremin.add(Pa.add(12), Duration.HALF, velocity=85, bend=1.0)
|
|
theremin.rest(Duration.WHOLE)
|
|
# Bar 29-30: rest while sitar plays
|
|
theremin.rest(Duration.WHOLE)
|
|
theremin.rest(Duration.WHOLE)
|
|
# Bar 31-32: theremin responds to the higher phrase
|
|
theremin.add(Pa.add(12), Duration.QUARTER, velocity=85, bend=0.5)
|
|
theremin.add(Dha.add(12), Duration.QUARTER, velocity=82, bend=-0.5)
|
|
theremin.add(Ni.add(12), Duration.HALF, velocity=90, bend=1.5)
|
|
theremin.rest(Duration.WHOLE)
|
|
|
|
# Bars 33-40: WEAVING — overlapping with sitar
|
|
theremin.rest(Duration.WHOLE)
|
|
theremin.add(Pa.add(12), Duration.HALF, velocity=85, bend=0.5)
|
|
theremin.add(Dha.add(12), Duration.HALF, velocity=80, bend=-0.25)
|
|
theremin.add(Ni.add(12), Duration.QUARTER, velocity=88, bend=0.5)
|
|
theremin.add(Sa.add(24), Duration.QUARTER, velocity=92, bend=-0.5)
|
|
theremin.add(Ni.add(12), Duration.HALF, velocity=85, bend=0.25)
|
|
theremin.rest(Duration.WHOLE)
|
|
theremin.add(Ma.add(12), Duration.HALF, velocity=82, bend=0.5)
|
|
theremin.add(Pa.add(12), Duration.HALF, velocity=88, bend=-0.25)
|
|
theremin.add(Dha.add(12), Duration.WHOLE, velocity=85, bend=1.0)
|
|
theremin.rest(Duration.WHOLE)
|
|
theremin.rest(Duration.WHOLE)
|
|
|
|
# Bars 41-48: SHARED PULSE — theremin finds the rhythm
|
|
theremin.set(volume=0.6)
|
|
for _ in range(2):
|
|
theremin.add(Pa.add(12), Duration.QUARTER, velocity=95, bend=0.25)
|
|
theremin.add(Dha.add(12), Duration.QUARTER, velocity=88, bend=-0.15)
|
|
theremin.add(Sa.add(24), Duration.HALF, velocity=100, bend=0.5)
|
|
theremin.add(Ni.add(12), Duration.QUARTER, velocity=90, bend=-0.25)
|
|
theremin.add(Dha.add(12), Duration.QUARTER, velocity=85)
|
|
theremin.add(Pa.add(12), Duration.HALF, velocity=88, bend=0.15)
|
|
theremin.rest(Duration.WHOLE)
|
|
theremin.rest(Duration.WHOLE)
|
|
|
|
# Bars 49-56: DEEPENING — theremin sings more freely
|
|
theremin.set(volume=0.65)
|
|
theremin.add(Sa.add(24), Duration.HALF, velocity=100, bend=1.0)
|
|
theremin.add(Ni.add(12), Duration.QUARTER, velocity=92, bend=-0.5)
|
|
theremin.add(Dha.add(12), Duration.QUARTER, velocity=88)
|
|
theremin.add(Pa.add(12), Duration.WHOLE, velocity=95, bend=0.5)
|
|
theremin.rest(Duration.WHOLE)
|
|
theremin.add(Dha.add(12), Duration.QUARTER, velocity=95, bend=0.5)
|
|
theremin.add(Sa.add(24), Duration.QUARTER, velocity=105, bend=-0.25)
|
|
theremin.add(Ni.add(12), Duration.HALF, velocity=98, bend=1.0)
|
|
theremin.add(Dha.add(12), Duration.QUARTER, velocity=90)
|
|
theremin.add(Pa.add(12), Duration.QUARTER, velocity=85, bend=-0.25)
|
|
theremin.add(Ma.add(12), Duration.HALF, velocity=82, bend=0.5)
|
|
theremin.rest(Duration.WHOLE)
|
|
theremin.rest(Duration.WHOLE)
|
|
|
|
# Bars 57-64: THE PEAK — theremin soars above everything
|
|
theremin.set(volume=0.7)
|
|
theremin.add(Sa.add(24), Duration.QUARTER, velocity=110, bend=1.5)
|
|
theremin.add(Ni.add(12), Duration.EIGHTH, velocity=100)
|
|
theremin.add(Sa.add(24), Duration.EIGHTH, velocity=108, bend=-0.5)
|
|
theremin.add(Re.add(24), Duration.HALF, velocity=115, bend=2.0)
|
|
theremin.add(Sa.add(24), Duration.HALF, velocity=108, bend=-1.0)
|
|
theremin.add(Ni.add(12), Duration.HALF, velocity=105, bend=0.5)
|
|
# The cry — highest point
|
|
theremin.add(Re.add(24), Duration.QUARTER, velocity=120, bend=2.5)
|
|
theremin.add(Sa.add(24), Duration.QUARTER, velocity=115, bend=-1.0)
|
|
theremin.add(Ni.add(12), Duration.QUARTER, velocity=110, bend=0.5)
|
|
theremin.add(Sa.add(24), Duration.QUARTER, velocity=118, bend=1.5)
|
|
# Descending together with sitar
|
|
theremin.add(Dha.add(12), Duration.QUARTER, velocity=105, bend=0.5)
|
|
theremin.add(Pa.add(12), Duration.QUARTER, velocity=98)
|
|
theremin.add(Ma.add(12), Duration.QUARTER, velocity=90, bend=-0.25)
|
|
theremin.add(Ga.add(12), Duration.QUARTER, velocity=82)
|
|
theremin.add(Sa.add(12), Duration.WHOLE, velocity=88, bend=0.25)
|
|
theremin.rest(Duration.WHOLE)
|
|
theremin.rest(Duration.WHOLE)
|
|
theremin.rest(Duration.WHOLE)
|
|
|
|
# Bars 65-72: UNWINDING — changed by the encounter
|
|
theremin.set(volume=0.45)
|
|
theremin.rest(Duration.WHOLE)
|
|
theremin.add(Pa.add(12), Duration.WHOLE, velocity=65, bend=0.25)
|
|
theremin.rest(Duration.WHOLE)
|
|
theremin.add(Sa.add(12), Duration.WHOLE, velocity=60, bend=-0.15)
|
|
theremin.rest(Duration.WHOLE)
|
|
theremin.add(Ga.add(12), Duration.HALF, velocity=55, bend=0.25)
|
|
theremin.add(Sa.add(12), Duration.HALF, velocity=52, bend=-0.1)
|
|
theremin.rest(Duration.WHOLE)
|
|
theremin.rest(Duration.WHOLE)
|
|
|
|
# Bars 73-80: one last note — then gone
|
|
theremin.add(Sa.add(12), Duration.WHOLE, velocity=40, bend=0.15)
|
|
for _ in range(7):
|
|
theremin.rest(Duration.WHOLE)
|
|
|
|
# ── HOUSE BEAT — the machine brings rhythm ─────────────────────
|
|
K = DrumSound.KICK
|
|
CH = DrumSound.CLOSED_HAT
|
|
OH = DrumSound.OPEN_HAT
|
|
CL = DrumSound.CLAP
|
|
|
|
kick = score.part("kick", volume=0.5, humanize=0.03)
|
|
hats = score.part("hats", volume=0.25, humanize=0.04)
|
|
clap = score.part("clap", volume=0.25, reverb=0.2, humanize=0.04)
|
|
|
|
# Bars 1-40: silent
|
|
for _ in range(40):
|
|
kick.rest(Duration.WHOLE)
|
|
hats.rest(Duration.WHOLE)
|
|
clap.rest(Duration.WHOLE)
|
|
|
|
# Bars 41-48: kick enters — just the pulse, minimal
|
|
for _ in range(8):
|
|
kick.hit(K, Duration.QUARTER, velocity=100)
|
|
kick.rest(Duration.DOTTED_HALF)
|
|
hats.rest(Duration.WHOLE)
|
|
clap.rest(Duration.WHOLE)
|
|
|
|
# Bars 49-56: full four-on-the-floor + offbeat hats + clap on 2&4
|
|
for _ in range(8):
|
|
for beat in range(4):
|
|
kick.hit(K, Duration.QUARTER, velocity=108)
|
|
for beat in range(4):
|
|
hats.rest(Duration.EIGHTH)
|
|
hats.hit(CH, Duration.EIGHTH, velocity=65)
|
|
clap.rest(Duration.QUARTER)
|
|
clap.hit(CL, Duration.QUARTER, velocity=90)
|
|
clap.rest(Duration.QUARTER)
|
|
clap.hit(CL, Duration.QUARTER, velocity=92)
|
|
|
|
# Bars 57-64: peak — driving, open hat on the &
|
|
for _ in range(8):
|
|
for beat in range(4):
|
|
kick.hit(K, Duration.QUARTER, velocity=115)
|
|
for beat in range(4):
|
|
hats.rest(Duration.EIGHTH)
|
|
if beat % 2 == 1:
|
|
hats.hit(OH, Duration.EIGHTH, velocity=62)
|
|
else:
|
|
hats.hit(CH, Duration.EIGHTH, velocity=68)
|
|
clap.rest(Duration.QUARTER)
|
|
clap.hit(CL, Duration.QUARTER, velocity=95)
|
|
clap.rest(Duration.QUARTER)
|
|
clap.hit(CL, Duration.QUARTER, velocity=98)
|
|
|
|
# Bars 65-72: beat thins out
|
|
for bar in range(8):
|
|
vel = max(25, 105 - bar * 10)
|
|
kick.hit(K, Duration.QUARTER, velocity=vel)
|
|
kick.rest(Duration.DOTTED_HALF)
|
|
hats.rest(Duration.WHOLE)
|
|
vel_c = max(20, 85 - bar * 10)
|
|
if bar < 4:
|
|
clap.rest(Duration.QUARTER)
|
|
clap.hit(CL, Duration.QUARTER, velocity=vel_c)
|
|
clap.rest(Duration.HALF)
|
|
else:
|
|
clap.rest(Duration.WHOLE)
|
|
|
|
# Bars 73-80: silence
|
|
for _ in range(8):
|
|
kick.rest(Duration.WHOLE)
|
|
hats.rest(Duration.WHOLE)
|
|
clap.rest(Duration.WHOLE)
|
|
|
|
# ── TABLA — enters when they find shared rhythm ────────────────
|
|
NA = DrumSound.TABLA_NA
|
|
TIN = DrumSound.TABLA_TIN
|
|
GE = DrumSound.TABLA_GE
|
|
tDHA = DrumSound.TABLA_DHA
|
|
TIT = DrumSound.TABLA_TIT
|
|
KE = DrumSound.TABLA_KE
|
|
GEB = DrumSound.TABLA_GE_BEND
|
|
|
|
tabla = score.part("tabla", volume=0.45,
|
|
reverb=0.4, reverb_type="cathedral", reverb_decay=2.0,
|
|
humanize=0.1)
|
|
|
|
# Bars 1-40: silent — no shared pulse yet
|
|
for _ in range(40):
|
|
tabla.rest(Duration.WHOLE)
|
|
|
|
# Bars 41-56: gentle groove — they've found each other
|
|
for bar in range(16):
|
|
if bar % 8 == 7:
|
|
# Fill
|
|
tabla.hit(tDHA, Duration.EIGHTH, velocity=90, articulation="accent")
|
|
tabla.hit(GEB, Duration.EIGHTH, velocity=100)
|
|
tabla.hit(NA, Duration.EIGHTH, velocity=72)
|
|
tabla.hit(GEB, Duration.EIGHTH, velocity=95)
|
|
tabla.hit(tDHA, Duration.EIGHTH, velocity=88, articulation="accent")
|
|
tabla.hit(NA, Duration.SIXTEENTH, velocity=65)
|
|
tabla.hit(TIT, Duration.SIXTEENTH, velocity=50)
|
|
tabla.hit(GEB, Duration.QUARTER, velocity=105)
|
|
else:
|
|
tabla.hit(tDHA, Duration.EIGHTH, velocity=80, articulation="accent")
|
|
tabla.hit(GE, Duration.EIGHTH, velocity=55)
|
|
tabla.hit(NA, Duration.EIGHTH, velocity=65)
|
|
tabla.hit(TIT, Duration.EIGHTH, velocity=42)
|
|
tabla.hit(NA, Duration.EIGHTH, velocity=60)
|
|
tabla.hit(TIT, Duration.EIGHTH, velocity=40)
|
|
tabla.hit(tDHA, Duration.EIGHTH, velocity=78, articulation="accent")
|
|
tabla.hit(NA, Duration.EIGHTH, velocity=58)
|
|
|
|
# Bars 57-64: peak — driving, urgent
|
|
for bar in range(8):
|
|
tabla.hit(tDHA, Duration.SIXTEENTH, velocity=100, articulation="accent")
|
|
tabla.hit(TIT, Duration.SIXTEENTH, velocity=50)
|
|
tabla.hit(NA, Duration.SIXTEENTH, velocity=72)
|
|
tabla.hit(TIT, Duration.SIXTEENTH, velocity=48)
|
|
tabla.hit(tDHA, Duration.SIXTEENTH, velocity=98, articulation="accent")
|
|
tabla.hit(GEB, Duration.SIXTEENTH, velocity=95)
|
|
tabla.hit(NA, Duration.SIXTEENTH, velocity=68)
|
|
tabla.hit(TIT, Duration.SIXTEENTH, velocity=48)
|
|
tabla.hit(GEB, Duration.SIXTEENTH, velocity=102, articulation="accent")
|
|
tabla.hit(NA, Duration.SIXTEENTH, velocity=70)
|
|
tabla.hit(tDHA, Duration.SIXTEENTH, velocity=98)
|
|
tabla.hit(TIT, Duration.SIXTEENTH, velocity=50)
|
|
tabla.hit(tDHA, Duration.QUARTER, velocity=105, articulation="accent")
|
|
|
|
# Bars 65-72: softening
|
|
for bar in range(8):
|
|
vel = max(35, 75 - bar * 5)
|
|
tabla.hit(tDHA, Duration.QUARTER, velocity=vel)
|
|
tabla.hit(TIT, Duration.EIGHTH, velocity=max(20, vel - 30))
|
|
tabla.hit(NA, Duration.EIGHTH, velocity=max(25, vel - 15))
|
|
tabla.hit(tDHA, Duration.QUARTER, velocity=max(30, vel - 5))
|
|
tabla.hit(TIT, Duration.EIGHTH, velocity=max(20, vel - 32))
|
|
tabla.hit(NA, Duration.EIGHTH, velocity=max(25, vel - 18))
|
|
|
|
# Bars 73-80: silence
|
|
for _ in range(8):
|
|
tabla.rest(Duration.WHOLE)
|
|
|
|
# ── HARMONIUM — emerges when harmony is found ──────────────────
|
|
harmonium = score.part("harmonium", instrument="harmonium", volume=0.12,
|
|
reverb=0.75, reverb_type="taj_mahal",
|
|
chorus=0.2, chorus_rate=0.1, chorus_depth=0.006,
|
|
humanize=0.08)
|
|
|
|
# Bars 1-48: silent
|
|
for _ in range(48):
|
|
harmonium.rest(Duration.WHOLE)
|
|
|
|
# Bars 49-64: the harmony that emerges from dialogue
|
|
harm_prog = key.progression("i", "iv", "VI", "v")
|
|
for _ in range(4):
|
|
for chord in harm_prog:
|
|
harmonium.add(chord, Duration.WHOLE, velocity=55)
|
|
|
|
# Bars 65-72: fading
|
|
for chord in harm_prog:
|
|
harmonium.add(chord, Duration.WHOLE, velocity=42)
|
|
for chord in harm_prog:
|
|
harmonium.add(chord, Duration.WHOLE, velocity=30)
|
|
|
|
# Bars 73-80: silence
|
|
for _ in range(8):
|
|
harmonium.rest(Duration.WHOLE)
|
|
|
|
# ── PAD — the shared understanding ─────────────────────────────
|
|
pad = score.part("pad", synth="drift", envelope="pad", volume=0.1,
|
|
reverb=0.7, reverb_type="taj_mahal",
|
|
chorus=0.4, chorus_rate=0.15, chorus_depth=0.01,
|
|
lowpass=1500)
|
|
|
|
# Bars 1-48: silent
|
|
for _ in range(48):
|
|
pad.rest(Duration.WHOLE)
|
|
|
|
# Bars 49-64: swells — the shared understanding
|
|
for _ in range(4):
|
|
for chord in harm_prog:
|
|
pad.add(chord, Duration.WHOLE, velocity=55)
|
|
|
|
# Bars 65-72: fading
|
|
for vel in [45, 38, 30, 22, 15, 10, 5, 0]:
|
|
if vel > 0:
|
|
pad.add(harm_prog[0], Duration.WHOLE, velocity=vel)
|
|
else:
|
|
pad.rest(Duration.WHOLE)
|
|
|
|
# Bars 73-80: silence
|
|
for _ in range(8):
|
|
pad.rest(Duration.WHOLE)
|
|
|
|
# ── MELLOTRON — ghostly flute underneath the shared understanding ──
|
|
mello = score.part("mellotron", instrument="mellotron_flute", volume=0.12,
|
|
reverb=0.3, reverb_type="taj_mahal",
|
|
pan=-0.15)
|
|
|
|
# Bars 1-64: silent
|
|
for _ in range(64):
|
|
mello.rest(Duration.WHOLE)
|
|
|
|
# Bars 65-72: plays the progression as whole notes
|
|
mello_prog = key.progression("i", "VII", "VI", "iv")
|
|
for _ in range(2):
|
|
for chord in mello_prog:
|
|
mello.add(chord, Duration.WHOLE, velocity=42)
|
|
|
|
# Bars 73-80: silence
|
|
for _ in range(8):
|
|
mello.rest(Duration.WHOLE)
|
|
|
|
# ── ROOM TONE — the space itself ───────────────────────────────
|
|
room = score.part("room", synth="noise", envelope="pad", volume=0.025,
|
|
reverb=1.0, reverb_type="taj_mahal",
|
|
lowpass=300)
|
|
room.lfo("lowpass", rate=0.008, min=150, max=500, bars=80, shape="sine")
|
|
room.lfo("volume", rate=0.006, min=0.01, max=0.035, bars=80, shape="triangle")
|
|
|
|
for _ in range(80):
|
|
room.add(Sa, Duration.WHOLE, velocity=25)
|
|
|
|
# ── TINGSHA — punctuation at the very start and end ─────────────
|
|
tingsha = score.part("tingsha", instrument="tingsha", volume=0.25,
|
|
reverb=0.9, reverb_type="taj_mahal")
|
|
|
|
# First bar: announces the beginning
|
|
tingsha.add(Sa.add(12), Duration.WHOLE, velocity=60)
|
|
for _ in range(78):
|
|
tingsha.rest(Duration.WHOLE)
|
|
# Last bar: closes the circle
|
|
tingsha.add(Sa.add(12), Duration.WHOLE, velocity=50)
|
|
|
|
# ═════════════════════════════════════════════════════════════════
|
|
import sys
|
|
|
|
print(f"Key: {key}")
|
|
print(f"Temperament: shruti / just intonation / A=432 Hz")
|
|
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 THE DIALOGUE (live engine)...")
|
|
from pytheory_live.live import LiveEngine
|
|
engine = LiveEngine(buffer_size=1024)
|
|
engine.play_score(score)
|
|
else:
|
|
print("Playing THE DIALOGUE...")
|
|
play_score(score)
|