Song #27: Ascent (Deep → Sky → Theremin Solo → Tabla Solo)

Didgeridoo drone throughout, granular abyss, kalimba light,
cello surfacing, piano + quiet uke, pedal steel + theremin solo
(searching → building → soaring peak), strings/flute/harp/timpani
at the peak, 4-part tabla solo finale (whisper → ghosts → 9-tuplet
call-response → 32nd triplet cascade + grand tihai).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-27 23:09:34 -04:00
parent f06c6f77d1
commit 92cb855a49
+186 -1
View File
@@ -1843,6 +1843,190 @@ def acoustic_ensemble():
play_song(score, "Acoustic Ensemble — Guitar, Uke, Mandolin, Cajón")
def ascent():
"""Ascent — from the deep to the sky, theremin solo, tabla solo."""
import random
from pytheory import Fretboard
random.seed(13)
score = Score("4/4", bpm=80)
REV = "cathedral"
T3 = 1.0 / 12.0
T9 = 1.0 / 9.0
NA = DrumSound.TABLA_NA; DH_ = DrumSound.TABLA_DHA
TT_ = DrumSound.TABLA_TIT; KE_ = DrumSound.TABLA_KE
GB_ = DrumSound.TABLA_GE_BEND; GE_ = DrumSound.TABLA_GE
DJB_ = DrumSound.DJEMBE_BASS; DJT_ = DrumSound.DJEMBE_TONE
DJS_ = DrumSound.DJEMBE_SLAP
CB_ = DrumSound.CAJON_BASS; CSL_ = DrumSound.CAJON_SLAP
CT_ = DrumSound.CAJON_TAP
# Didgeridoo drone
didg = score.part("didg", instrument="didgeridoo", volume=0.15)
for _ in range(32):
didg.add("E1", 4.0, velocity=52)
# 1: THE DEEP (1-4)
grain = score.part("grain", synth="granular_synth", envelope="pad",
lowpass=800, reverb=0.55, reverb_type="cave", volume=0.12)
for note in ["E2", "B2", "E2", "G2"]:
grain.add(note, 4.0, velocity=40)
# 2: LIGHT (3-6)
kal = score.part("kalimba", instrument="kalimba", volume=0.2,
delay=0.2, delay_time=0.375, delay_feedback=0.4,
reverb=0.45, reverb_type=REV)
kal.rest(8.0)
for note, vel in [("B4",58),("E5",62),("G5",65),("B5",68),
("G5",62),("E5",58),("B4",55),("E4",52)]:
kal.add(note, Duration.QUARTER, velocity=vel)
kal.rest(4.0)
for note, vel in [("E5",60),("G5",65),("B5",70),("E6",72),
("B5",65),("G5",60),("E5",58),("B4",55)]:
kal.add(note, Duration.QUARTER, velocity=vel)
# 3: SURFACING (5-8)
cello = score.part("cello", instrument="cello", volume=0.22,
reverb=0.4, reverb_type=REV)
cello.rest(16.0)
for note, dur, vel in [("E2",4.0,52),("G2",4.0,55),("B2",4.0,58),("E3",4.0,62)]:
cello.add(note, dur, velocity=vel)
# 4: AIR (7-10) — piano + quiet uke
piano = score.part("piano", instrument="piano", volume=0.28,
reverb=0.35, reverb_type=REV)
piano.rest(24.0)
for notes in [
["E3","B3","E4","G4","B4","G4","E4","B3"],
["C3","G3","C4","E4","G4","E4","C4","G3"],
["A2","E3","A3","C4","E4","C4","A3","E3"],
["B2","F#3","B3","D4","F#4","D4","B3","F#3"],
]:
for n in notes:
piano.add(n, Duration.EIGHTH, velocity=random.randint(58, 70))
fb = Fretboard.ukulele()
uke = score.part("uke", instrument="ukulele", fretboard=fb,
reverb=0.4, reverb_type=REV, humanize=0.2,
pan=-0.2, volume=0.15)
uke.rest(28.0)
for sym in ["Em", "C", "Am", "B"]:
vd = random.randint(60, 75)
vu = random.randint(45, 62)
uke.strum(sym, Duration.QUARTER, direction="down", velocity=vd)
uke.strum(sym, Duration.EIGHTH, direction="up", velocity=vu)
uke.strum(sym, Duration.EIGHTH, direction="down", velocity=vd - 8)
uke.strum(sym, Duration.QUARTER, direction="up", velocity=vu)
uke.strum(sym, Duration.QUARTER, direction="down", velocity=vd)
# 5: THEREMIN SOLO (11-16)
steel = score.part("steel", instrument="pedal_steel", volume=0.16,
reverb=0.4, reverb_type=REV, pan=0.2)
steel.rest(36.0)
for note, dur, vel in [("B4",3.0,58),("A4",1.0,50),("G4",2.0,55),("E4",2.0,52)]:
steel.add(note, dur, velocity=vel)
theremin = score.part("theremin", instrument="theremin", volume=0.3,
reverb=0.45, reverb_type=REV,
delay=0.15, delay_time=0.375, delay_feedback=0.3)
theremin.rest(40.0)
for note, dur, vel in [
("E4",2.0,62),("G4",1.0,58),("B4",1.0,62),
("A4",2.0,65),("G4",1.0,58),("E4",1.0,55),("D4",3.0,60),("E4",1.0,58),
("G4",1.0,62),("B4",1.5,68),("D5",0.5,65),
("E5",2.0,72),("D5",1.0,65),("B4",1.0,62),
("G4",1.0,60),("A4",1.0,62),("B4",2.0,68),
("E5",1.5,75),("G5",1.5,80),("B5",2.0,85),
("A5",1.0,78),("G5",1.0,72),("E5",2.0,75),
("D5",1.0,68),("B4",1.0,62),("E4",4.0,70),
]:
theremin.add(note, dur, velocity=vel)
strings = score.part("strings", instrument="string_ensemble", volume=0.15,
reverb=0.45, reverb_type=REV)
strings.rest(40.0)
for sym, vel in [("Em",52),("C",55),("Am",58),("B",55),("Em",60),("C",62)]:
strings.add(Chord.from_symbol(sym), 4.0, velocity=vel)
# 6: THE PEAK (17-18)
flute = score.part("flute", instrument="flute", volume=0.2, reverb=0.4, reverb_type=REV)
flute.rest(64.0)
for note, dur, vel in [
("B5",2.0,55),("A5",1.0,50),("G5",1.0,52),
("E5",2.0,55),("D5",1.0,50),("E5",1.0,52),
]:
flute.add(note, dur, velocity=vel)
harp = score.part("harp", instrument="harp", volume=0.16, reverb=0.4, reverb_type=REV)
harp.rest(68.0)
for n in ["B5","G5","E5","B4","G4","E4","B3","E3"]:
harp.add(n, Duration.QUARTER, velocity=random.randint(48, 58))
timp = score.part("timp", instrument="timpani")
timp.rest(64.0)
timp.roll("E2", 4.0, velocity_start=20, velocity_end=95, speed=0.125)
timp.add("E2", 4.0, velocity=105)
# Drums: silence → cajón → djembe → tabla solo
score.add_pattern(Pattern(name="s", time_signature="4/4", beats=16.0, hits=[]),
repeats=1)
p_caj = Pattern(name="caj", time_signature="4/4", beats=4.0, hits=[
_Hit(CB_, 0.0, 58), _Hit(CT_, 0.5, 22), _Hit(CSL_, 1.0, 50),
_Hit(CT_, 1.5, 20), _Hit(CB_, 2.0, 55), _Hit(CT_, 2.5, 22),
_Hit(CSL_, 3.0, 52),
])
score.add_pattern(p_caj, repeats=4)
p_dj = Pattern(name="dj", time_signature="4/4", beats=4.0, hits=[
_Hit(DJB_, 0.0, 42), _Hit(DJT_, 1.0, 35), _Hit(DJT_, 1.5, 30),
_Hit(DJS_, 2.0, 38), _Hit(DJT_, 3.0, 35),
])
score.add_pattern(p_dj, repeats=10)
# 7: TABLA SOLO (bars 19-26)
score.add_pattern(Pattern(name="ts1", time_signature="4/4", beats=8.0, hits=[
_Hit(DH_, 0.0, 72), _Hit(NA, 2.5, 48),
_Hit(DH_, 4.0, 75), _Hit(TT_, 5.5, 25), _Hit(NA, 6.0, 45),
_Hit(DH_, 7.5, 72),
]), repeats=1)
score.add_pattern(Pattern(name="ts2", time_signature="4/4", beats=8.0, hits=[
_Hit(DH_, 0.0, 85), _Hit(TT_, 0.25, 30), _Hit(TT_, 0.5, 32),
_Hit(NA, 1.0, 62), _Hit(TT_, 1.25, 25), _Hit(NA, 2.0, 58),
_Hit(TT_, 2.5, 28), _Hit(DH_, 3.0, 82),
_Hit(DH_, 4.0, 90), _Hit(TT_, 4.25, 32), _Hit(TT_, 4.5, 35),
_Hit(NA, 5.0, 68), _Hit(KE_, 5.5, 35), _Hit(NA, 6.0, 62),
_Hit(KE_, 6.5, 38), _Hit(DH_, 7.0, 92), _Hit(GB_, 7.5, 85),
]), repeats=1)
score.add_pattern(Pattern(name="ts3", time_signature="4/4", beats=8.0, hits=[
_Hit(NA, 0.0, 108), _Hit(NA, 0.25, 52), _Hit(TT_, 0.5, 35),
_Hit(NA, 0.75, 100),
_Hit(GE_, 1.0, 98), _Hit(GE_, 1.25, 48), _Hit(GB_, 1.5, 90),
_Hit(GE_, 1.75, 42),
_Hit(NA, 2.0, 110), _Hit(TT_, 2.125, 28), _Hit(TT_, 2.25, 32),
_Hit(NA, 2.5, 102), _Hit(TT_, 2.625, 30), _Hit(TT_, 2.75, 35),
_Hit(GB_, 3.0, 110), _Hit(KE_, 3.25, 45), _Hit(GE_, 3.5, 65),
_Hit(DH_, 4.0, 112),
*[_Hit(TT_ if i % 2 == 0 else KE_, 5.0 + i * T9, 35 + i * 5)
for i in range(9)],
_Hit(DH_, 7.0, 115),
]), repeats=1)
score.add_pattern(Pattern(name="ts4", time_signature="4/4", beats=8.0, hits=[
*[_Hit(TT_, i * T3, 32 + i * 2) for i in range(12)],
_Hit(DH_, 1.0, 115), _Hit(GB_, 1.5, 105),
_Hit(NA, 2.0, 108), _Hit(KE_, 2.125, 42), _Hit(NA, 2.25, 102),
_Hit(KE_, 2.375, 45), _Hit(NA, 2.5, 105), _Hit(KE_, 2.625, 48),
_Hit(NA, 2.75, 110), _Hit(DH_, 3.0, 118),
*[_Hit(TT_, 3.5 + i * T3, 30 + i * 4) for i in range(12)],
_Hit(DH_, 4.5, 120), _Hit(DH_, 4.75, 115), _Hit(GB_, 5.0, 112),
_Hit(GE_, 5.5, 85), _Hit(GE_, 6.5, 82),
*[_Hit(NA if i % 3 == 0 else TT_, 5.5 + i * (2.0 / 9.0),
40 + (i % 3) * 12) for i in range(9)],
_Hit(DH_, 7.5, 127), _Hit(GB_, 7.875, 127),
]), repeats=1)
score.set_drum_effects(reverb=0.3, reverb_type=REV)
play_song(score, "Ascent — Deep → Sky → Theremin Solo → Tabla Solo")
SONGS = {
"1": ("Bossa Nova in A minor", bossa_nova_girl),
"2": ("Bebop in Bb major", bebop_in_bb),
@@ -1870,6 +2054,7 @@ SONGS = {
"24": ("Journey (Western → World → Indian)", journey),
"25": ("Epic Bhairav (Orchestral + Tabla)", epic_bhairav),
"26": ("Acoustic Ensemble (Guitar+Uke+Mando+Cajón)", acoustic_ensemble),
"27": ("Ascent (Deep → Sky → Tabla Solo)", ascent),
}
if __name__ == "__main__":
@@ -1883,7 +2068,7 @@ if __name__ == "__main__":
print(f" {key:>2}. {name}")
print()
choice = input(" Pick a song (1-26, or 'all'): ").strip()
choice = input(" Pick a song (1-27, or 'all'): ").strip()
print()
if choice == "all":