From 8a4a2df1aac1a33f8d3fc0b04d40edfd083764bb Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Fri, 27 Mar 2026 02:37:34 -0400 Subject: [PATCH] Song #23: Tabla Solo in Raga Yaman (22-shruti) Tanpura drone intro, quiet sitar Yaman phrases, tabla solo building from gentle theka through ghost notes to blazing tiri kita with bayan pitch bends, tihai, dramatic silence, slam finish. Taj Mahal reverb throughout. Co-Authored-By: Claude Opus 4.6 (1M context) --- examples/songs.py | 108 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 106 insertions(+), 2 deletions(-) diff --git a/examples/songs.py b/examples/songs.py index e8a2c4e..0e7cf62 100644 --- a/examples/songs.py +++ b/examples/songs.py @@ -15,7 +15,8 @@ Usage: import sounddevice as sd -from pytheory import Chord, Key, Pattern, Duration, Score +from pytheory import Chord, Key, Pattern, Duration, Score, Tone, TonedScale, SYSTEMS +from pytheory.rhythm import DrumSound, _Hit from pytheory.play import render_score, SAMPLE_RATE @@ -1199,6 +1200,108 @@ def greensleeves(): play_song(score, "Greensleeves — Renaissance Lute (Meantone, A=415)") +def tabla_solo_yaman(): + """Tabla solo with tanpura drone, sitar, and Raga Yaman — 22-shruti tuning.""" + shruti = SYSTEMS["shruti"] + score = Score("4/4", bpm=160, system=shruti) + h = _Hit + + NA = DrumSound.TABLA_NA + TI = DrumSound.TABLA_TIN + GE = DrumSound.TABLA_GE + DH = DrumSound.TABLA_DHA + TT = DrumSound.TABLA_TIT + KE = DrumSound.TABLA_KE + GB = DrumSound.TABLA_GE_BEND + + # Tanpura drone — Sa + Pa + tanpura_sa = score.part("tanpura_sa", synth="strings_synth", envelope="pad", + detune=3, lowpass=1000, volume=0.18, + reverb=0.5, reverb_type="taj_mahal") + tanpura_pa = score.part("tanpura_pa", synth="strings_synth", envelope="pad", + detune=3, lowpass=1400, volume=0.14, + reverb=0.5, reverb_type="taj_mahal") + sa3 = Tone("Sa", octave=3, system=shruti) + pa3 = Tone("Pa", octave=3, system=shruti) + for _ in range(16): + tanpura_sa.add(sa3, Duration.WHOLE) + tanpura_pa.add(pa3, Duration.WHOLE) + + # Quiet sitar — Raga Yaman (Kalyan thaat) + sitar = score.part("sitar", instrument="sitar", volume=0.12, + reverb=0.4, reverb_type="taj_mahal") + ts = TonedScale(system=shruti, tonic=Tone("Sa", octave=4, system=shruti)) + y = list(ts["kalyan"].tones) + S, R, G, M, P, D, N, S2 = y + sitar.rest(Duration.WHOLE) + sitar.rest(Duration.WHOLE) + for tone, dur, vel in [ + (S, 3.0, 55), (R, 1.0, 50), (G, 3.0, 58), (R, 1.0, 48), + (S, 4.0, 55), (G, 1.0, 50), (M, 1.0, 52), (P, 3.0, 58), + (M, 1.0, 48), (G, 1.0, 50), (R, 1.0, 48), (S, 4.0, 55), + (P, 2.0, 52), (D, 1.0, 55), (N, 2.0, 58), (S2, 3.0, 60), + (N, 1.0, 52), (D, 1.0, 50), (P, 1.0, 52), (G, 1.0, 48), + (R, 1.0, 48), (S, 4.0, 55), + ]: + sitar.add(tone, dur, velocity=vel) + + # 4 bars drone intro (silence for drums) + silence = Pattern(name="silence", time_signature="4/4", beats=16.0, hits=[]) + score.add_pattern(silence, repeats=1) + + # Gentle opening + p1 = Pattern(name="gentle", time_signature="4/4", beats=8.0, hits=[ + h(DH, 0.0, 80), h(NA, 2.0, 60), + h(DH, 4.0, 85), h(NA, 5.0, 55), h(NA, 6.0, 60), h(DH, 7.0, 80), + ]) + + # Building with ghost notes + p2 = Pattern(name="build", time_signature="4/4", beats=16.0, hits=[ + h(DH, 0.0, 95), h(TT, 0.5, 35), h(NA, 1.0, 70), h(TT, 1.5, 30), + h(NA, 2.0, 65), h(DH, 3.0, 90), + h(DH, 4.0, 100), h(TT, 4.25, 35), h(TT, 4.5, 40), h(NA, 5.0, 75), + h(TT, 5.5, 35), h(NA, 6.0, 70), h(TT, 6.5, 30), h(DH, 7.0, 95), + h(DH, 8.0, 95), h(TI, 9.0, 70), h(TI, 10.0, 72), h(NA, 11.0, 80), + h(TT, 11.25, 40), h(TT, 11.5, 42), h(KE, 11.75, 45), + h(TT, 12.0, 50), h(TT, 12.25, 55), h(KE, 12.5, 58), h(NA, 12.75, 70), + h(DH, 13.0, 100), h(TT, 13.25, 40), h(TT, 13.5, 45), h(KE, 13.75, 50), + h(NA, 14.0, 75), h(KE, 14.25, 50), h(DH, 14.5, 85), h(NA, 14.75, 70), + h(DH, 15.0, 110), h(GB, 15.5, 100), + ]) + + # Full intensity + p3 = Pattern(name="fire", time_signature="4/4", beats=16.0, hits=[ + h(TT, 0.0, 50), h(TT, 0.125, 35), h(TT, 0.25, 45), h(KE, 0.5, 55), + h(NA, 0.75, 85), + h(DH, 1.0, 115), h(TT, 1.25, 38), h(DH, 1.5, 70), h(NA, 1.75, 60), + h(TT, 2.0, 50), h(TT, 2.125, 35), h(TT, 2.25, 48), h(KE, 2.5, 55), + h(NA, 2.75, 88), + h(DH, 3.0, 115), h(GB, 3.5, 105), h(NA, 3.75, 72), + h(NA, 4.0, 115), h(NA, 4.25, 60), h(TT, 4.5, 40), h(NA, 4.75, 105), + h(GE, 5.0, 105), h(GE, 5.25, 55), h(GB, 5.5, 95), h(GE, 5.75, 50), + h(NA, 6.0, 115), h(TT, 6.125, 30), h(TT, 6.25, 38), h(NA, 6.5, 100), + h(TT, 6.625, 32), h(TT, 6.75, 42), + h(GB, 7.0, 115), h(KE, 7.25, 52), h(GE, 7.5, 72), h(KE, 7.75, 48), + # Tihai + h(DH, 8.0, 115), h(NA, 8.25, 78), h(TT, 8.5, 52), h(KE, 8.75, 58), + h(DH, 9.0, 105), + h(DH, 9.5, 110), h(NA, 9.75, 78), h(TT, 10.0, 52), h(KE, 10.25, 58), + h(DH, 10.5, 105), + h(DH, 11.0, 120), h(NA, 11.25, 82), h(TT, 11.5, 58), h(KE, 11.75, 62), + h(DH, 12.0, 120), + # Silence... then finish + h(GB, 14.5, 120), + h(DH, 15.5, 127), h(DH, 15.75, 127), + ]) + + score.add_pattern(p1, repeats=1) + score.add_pattern(p2, repeats=1) + score.add_pattern(p3, repeats=1) + score.set_drum_effects(reverb=0.4, reverb_type="taj_mahal") + + play_song(score, "Tabla Solo — Raga Yaman (22-Shruti, Taj Mahal)") + + SONGS = { "1": ("Bossa Nova in A minor", bossa_nova_girl), "2": ("Bebop in Bb major", bebop_in_bb), @@ -1222,6 +1325,7 @@ SONGS = { "20": ("Temple Bell (Japanese)", temple_bell), "21": ("Cinematic Showcase (Orchestral)", cinematic_showcase), "22": ("Greensleeves (Renaissance Lute)", greensleeves), + "23": ("Tabla Solo (Raga Yaman)", tabla_solo_yaman), } if __name__ == "__main__": @@ -1235,7 +1339,7 @@ if __name__ == "__main__": print(f" {key:>2}. {name}") print() - choice = input(" Pick a song (1-22, or 'all'): ").strip() + choice = input(" Pick a song (1-23, or 'all'): ").strip() print() if choice == "all":