mirror of
https://github.com/kennethreitz/pytheory.git
synced 2026-06-05 23:00:20 +00:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 92ade3ee3d | |||
| 833867329e | |||
| 93b9fe9ced | |||
| 88a1171bbe | |||
| 3ca0842b7a | |||
| 00de5eb354 |
+215
-184
@@ -52,24 +52,26 @@ def bossa_nova_girl():
|
||||
lead = score.part("lead", instrument="flute",
|
||||
volume=0.45, pan=0.3,
|
||||
delay=0.25, delay_time=0.32, delay_feedback=0.35,
|
||||
reverb=0.2, reverb_type="plate")
|
||||
reverb=0.2, reverb_type="plate",
|
||||
humanize=0.2)
|
||||
bass = score.part("bass", instrument="upright_bass",
|
||||
volume=0.45, pan=0.0, lowpass=600)
|
||||
volume=0.45, pan=0.0, lowpass=600,
|
||||
humanize=0.2, reverb=0.2)
|
||||
|
||||
for sym in ["Am", "Am", "Dm", "Dm", "E7", "E7", "Am", "Am"]:
|
||||
rhodes.add(Chord.from_symbol(sym), Duration.WHOLE)
|
||||
|
||||
for n, d in [
|
||||
("E5",.67),("D5",.33),("C5",.67),("B4",.33),("A4",1),("C5",.67),("E5",.33),
|
||||
("D5",.67),("C5",.33),("A4",1),(None,1),
|
||||
("F5",.67),("E5",.33),("D5",.67),("C5",.33),("D5",1),("F5",.67),("A5",.33),
|
||||
("G5",.67),("F5",.33),("D5",1),(None,1),
|
||||
("G#5",.67),("F5",.33),("E5",.67),("D5",.33),("E5",1),(None,.5),("B4",.5),
|
||||
("D5",.67),("E5",.33),("G#4",1),(None,1),
|
||||
("A4",1),("C5",.67),("E5",.33),("A5",1.5),(None,.5),
|
||||
("G5",.67),("E5",.33),("C5",.67),("A4",.33),("A4",2),
|
||||
for n, d, v in [
|
||||
("E5",.67,85),("D5",.33,75),("C5",.67,80),("B4",.33,70),("A4",1,85),("C5",.67,78),("E5",.33,82),
|
||||
("D5",.67,78),("C5",.33,72),("A4",1,80),(None,1,0),
|
||||
("F5",.67,88),("E5",.33,78),("D5",.67,82),("C5",.33,72),("D5",1,80),("F5",.67,85),("A5",.33,90),
|
||||
("G5",.67,82),("F5",.33,75),("D5",1,78),(None,1,0),
|
||||
("G#5",.67,92),("F5",.33,78),("E5",.67,85),("D5",.33,75),("E5",1,82),(None,.5,0),("B4",.5,72),
|
||||
("D5",.67,78),("E5",.33,82),("G#4",1,75),(None,1,0),
|
||||
("A4",1,80),("C5",.67,78),("E5",.33,85),("A5",1.5,95),(None,.5,0),
|
||||
("G5",.67,82),("E5",.33,78),("C5",.67,75),("A4",.33,70),("A4",2,85),
|
||||
]:
|
||||
lead.rest(d) if n is None else lead.add(n, d)
|
||||
lead.rest(d) if n is None else lead.add(n, d, velocity=v)
|
||||
|
||||
for n in ["A2","E2","A2","C3","D2","A2","D2","F2",
|
||||
"E2","B2","E2","G#2","A2","E2","A2","C3",
|
||||
@@ -95,32 +97,34 @@ def bebop_in_bb():
|
||||
volume=0.4, pan=0.25,
|
||||
lowpass=4000, lowpass_q=1.1,
|
||||
delay=0.15, delay_time=0.19, delay_feedback=0.25,
|
||||
reverb=0.15, reverb_type="plate")
|
||||
reverb=0.15, reverb_type="plate",
|
||||
humanize=0.2)
|
||||
bass = score.part("bass", instrument="upright_bass",
|
||||
volume=0.4, pan=0.0, lowpass=500)
|
||||
volume=0.4, pan=0.0, lowpass=500,
|
||||
humanize=0.2, reverb=0.2)
|
||||
|
||||
for sym in ["Bb", "Gm", "Cm", "F7"] * 2:
|
||||
rhodes.add(Chord.from_symbol(sym), Duration.WHOLE)
|
||||
|
||||
for n, d in [
|
||||
("Bb4",.67),("D5",.33),("F5",.67),("D5",.33),
|
||||
("Bb4",.67),("C5",.33),("D5",.67),("F5",.33),
|
||||
("G5",.67),("F5",.33),("D5",.67),("Bb4",.33),
|
||||
("A4",.67),("Bb4",.33),("D5",.67),("G4",.33),
|
||||
("C5",.67),("Eb5",.33),("G5",.67),("Eb5",.33),
|
||||
("C5",.67),("D5",.33),("Eb5",.67),("F5",.33),
|
||||
("A5",.67),("G5",.33),("F5",.67),("Eb5",.33),
|
||||
("D5",.67),("C5",.33),("A4",.5),(None,.5),
|
||||
("Bb4",1),("D5",.67),("F5",.33),
|
||||
("G5",.67),("F5",.33),("D5",.67),("Bb4",.33),
|
||||
("Bb5",.67),("A5",.33),("G5",.67),("F5",.33),
|
||||
("Eb5",.67),("D5",.33),("Bb4",.67),("G4",.33),
|
||||
("C5",.5),(None,.5),("Eb5",.67),("G5",.33),
|
||||
("F5",.67),("Eb5",.33),("D5",.67),("C5",.33),
|
||||
("A4",.67),("C5",.33),("Eb5",.67),("F5",.33),
|
||||
("G5",.67),("A5",.33),("Bb5",1),
|
||||
for n, d, v in [
|
||||
("Bb4",.67,82),("D5",.33,75),("F5",.67,88),("D5",.33,78),
|
||||
("Bb4",.67,80),("C5",.33,72),("D5",.67,82),("F5",.33,85),
|
||||
("G5",.67,90),("F5",.33,78),("D5",.67,82),("Bb4",.33,72),
|
||||
("A4",.67,78),("Bb4",.33,72),("D5",.67,85),("G4",.33,70),
|
||||
("C5",.67,82),("Eb5",.33,78),("G5",.67,92),("Eb5",.33,80),
|
||||
("C5",.67,78),("D5",.33,75),("Eb5",.67,82),("F5",.33,85),
|
||||
("A5",.67,95),("G5",.33,82),("F5",.67,85),("Eb5",.33,78),
|
||||
("D5",.67,80),("C5",.33,72),("A4",.5,75),(None,.5,0),
|
||||
("Bb4",1,85),("D5",.67,80),("F5",.33,88),
|
||||
("G5",.67,90),("F5",.33,82),("D5",.67,78),("Bb4",.33,72),
|
||||
("Bb5",.67,95),("A5",.33,85),("G5",.67,88),("F5",.33,80),
|
||||
("Eb5",.67,82),("D5",.33,75),("Bb4",.67,78),("G4",.33,70),
|
||||
("C5",.5,78),(None,.5,0),("Eb5",.67,82),("G5",.33,88),
|
||||
("F5",.67,85),("Eb5",.33,78),("D5",.67,82),("C5",.33,75),
|
||||
("A4",.67,78),("C5",.33,80),("Eb5",.67,85),("F5",.33,88),
|
||||
("G5",.67,92),("A5",.33,88),("Bb5",1,95),
|
||||
]:
|
||||
lead.rest(d) if n is None else lead.add(n, d)
|
||||
lead.rest(d) if n is None else lead.add(n, d, velocity=v)
|
||||
|
||||
for n in ["Bb2","D3","F3","A3","G3","F3","D3","Bb2",
|
||||
"C3","Eb3","G3","Bb3","F3","A3","C4","Eb3",
|
||||
@@ -146,29 +150,31 @@ def salsa_descarga():
|
||||
lead = score.part("lead", instrument="trumpet",
|
||||
volume=0.4, pan=0.3,
|
||||
delay=0.2, delay_time=0.167, delay_feedback=0.3,
|
||||
reverb=0.15, reverb_type="plate")
|
||||
reverb=0.15, reverb_type="plate",
|
||||
humanize=0.2)
|
||||
bass = score.part("bass", instrument="synth_bass",
|
||||
volume=0.45, pan=0.0, lowpass=500, lowpass_q=1.3)
|
||||
volume=0.45, pan=0.0, lowpass=500, lowpass_q=1.3,
|
||||
humanize=0.2, reverb=0.2)
|
||||
|
||||
for sym in ["Em7b5", "A7", "Dm7", "Bbmaj7"] * 2:
|
||||
pads.add(Chord.from_symbol(sym), Duration.WHOLE)
|
||||
|
||||
for n, d in [
|
||||
("E5",.67),("G5",.33),("Bb5",.67),("A5",.33),
|
||||
("G5",.67),("F5",.33),("E5",.67),("D5",.33),
|
||||
("C#5",.67),("D5",.33),("E5",.67),("G5",.33),
|
||||
("F5",.67),("E5",.33),("C#5",.5),(None,.5),
|
||||
("D5",.5),(None,.17),("F5",.67),("A5",.33),
|
||||
("G5",.67),("F5",.33),("E5",.67),("D5",.33),
|
||||
("Bb4",1),("D5",.67),("F5",.33),("A5",1),(None,1),
|
||||
("E5",.5),("F5",.5),("G5",.67),("A5",.33),
|
||||
("Bb5",.67),("A5",.33),("G5",.67),("E5",.33),
|
||||
("C#5",.67),("E5",.33),("A5",.67),("G5",.33),
|
||||
("F5",.67),("E5",.33),("C#5",.67),("A4",.33),
|
||||
("D5",1),("F5",.67),("A5",.33),("G5",.67),("F5",.33),("D5",1),(None,1),
|
||||
("Bb4",.67),("D5",.33),("F5",.67),("Bb5",.33),("A5",1.5),(None,.5),
|
||||
for n, d, v in [
|
||||
("E5",.67,85),("G5",.33,78),("Bb5",.67,92),("A5",.33,82),
|
||||
("G5",.67,85),("F5",.33,78),("E5",.67,82),("D5",.33,75),
|
||||
("C#5",.67,80),("D5",.33,75),("E5",.67,85),("G5",.33,80),
|
||||
("F5",.67,82),("E5",.33,78),("C#5",.5,75),(None,.5,0),
|
||||
("D5",.5,78),(None,.17,0),("F5",.67,85),("A5",.33,90),
|
||||
("G5",.67,88),("F5",.33,80),("E5",.67,82),("D5",.33,75),
|
||||
("Bb4",1,78),("D5",.67,82),("F5",.33,88),("A5",1,95),(None,1,0),
|
||||
("E5",.5,80),("F5",.5,82),("G5",.67,88),("A5",.33,85),
|
||||
("Bb5",.67,95),("A5",.33,85),("G5",.67,88),("E5",.33,78),
|
||||
("C#5",.67,80),("E5",.33,82),("A5",.67,92),("G5",.33,85),
|
||||
("F5",.67,82),("E5",.33,78),("C#5",.67,75),("A4",.33,70),
|
||||
("D5",1,82),("F5",.67,85),("A5",.33,92),("G5",.67,88),("F5",.33,80),("D5",1,78),(None,1,0),
|
||||
("Bb4",.67,75),("D5",.33,80),("F5",.67,88),("Bb5",.33,95),("A5",1.5,90),(None,.5,0),
|
||||
]:
|
||||
lead.rest(d) if n is None else lead.add(n, d)
|
||||
lead.rest(d) if n is None else lead.add(n, d, velocity=v)
|
||||
|
||||
for n in ["E2","E3","A2","A3","D2","D3","Bb2","Bb3"] * 4:
|
||||
bass.add(n, Duration.QUARTER)
|
||||
@@ -192,23 +198,25 @@ def afrobeat_groove():
|
||||
volume=0.4, pan=0.3,
|
||||
lowpass=3000, lowpass_q=1.0,
|
||||
delay=0.2, delay_time=0.26, delay_feedback=0.3,
|
||||
reverb=0.15, reverb_type="plate")
|
||||
reverb=0.15, reverb_type="plate",
|
||||
humanize=0.2)
|
||||
bass = score.part("bass", instrument="bass_guitar",
|
||||
volume=0.5, pan=0.0, lowpass=500)
|
||||
volume=0.5, pan=0.0, lowpass=500,
|
||||
humanize=0.2, reverb=0.2)
|
||||
|
||||
for sym in ["Em", "Am", "D", "C"] * 2:
|
||||
pads.add(Chord.from_symbol(sym), Duration.WHOLE)
|
||||
|
||||
riff = [("E5",.5),("G5",.5),("A5",.5),("G5",.5),
|
||||
("E5",.5),("D5",.5),("E5",1),
|
||||
("E5",.5),("G5",.5),("A5",.5),("B5",.5),
|
||||
("A5",.5),("G5",.5),("E5",1),
|
||||
(None,.5),("A5",.5),("G5",.5),("E5",.5),
|
||||
("D5",1),("E5",.5),("G5",.5),
|
||||
("A5",.5),("B5",.5),("A5",.5),("G5",.5),
|
||||
("E5",1.5),(None,.5)]
|
||||
for n, d in riff * 2:
|
||||
lead.rest(d) if n is None else lead.add(n, d)
|
||||
riff = [("E5",.5,82),("G5",.5,78),("A5",.5,88),("G5",.5,80),
|
||||
("E5",.5,78),("D5",.5,72),("E5",1,85),
|
||||
("E5",.5,80),("G5",.5,78),("A5",.5,88),("B5",.5,92),
|
||||
("A5",.5,85),("G5",.5,78),("E5",1,82),
|
||||
(None,.5,0),("A5",.5,85),("G5",.5,80),("E5",.5,75),
|
||||
("D5",1,78),("E5",.5,80),("G5",.5,82),
|
||||
("A5",.5,88),("B5",.5,92),("A5",.5,85),("G5",.5,80),
|
||||
("E5",1.5,82),(None,.5,0)]
|
||||
for n, d, v in riff * 2:
|
||||
lead.rest(d) if n is None else lead.add(n, d, velocity=v)
|
||||
|
||||
for n in ["E2","E2","G2","A2","A2","G2","E2","D2",
|
||||
"D2","D2","F#2","A2","C3","C3","B2","G2"] * 2:
|
||||
@@ -234,24 +242,26 @@ def reggae_one_drop():
|
||||
lead = score.part("lead", instrument="flute",
|
||||
volume=0.4, pan=0.3,
|
||||
delay=0.35, delay_time=0.5625, delay_feedback=0.45,
|
||||
reverb=0.3, reverb_type="cathedral")
|
||||
reverb=0.3, reverb_type="cathedral",
|
||||
humanize=0.2)
|
||||
bass = score.part("bass", instrument="bass_guitar",
|
||||
volume=0.55, pan=0.0, lowpass=400, lowpass_q=1.3)
|
||||
volume=0.55, pan=0.0, lowpass=400, lowpass_q=1.3,
|
||||
humanize=0.2, reverb=0.2)
|
||||
|
||||
for sym in ["G", "C", "D", "C"] * 2:
|
||||
chords.add(Chord.from_symbol(sym), Duration.WHOLE)
|
||||
|
||||
for n, d in [
|
||||
("G5",1.5),(None,.5),("B5",1),("A5",1),
|
||||
("G5",2),("E5",1),("D5",1),
|
||||
("C5",1.5),(None,.5),("E5",1),("G5",1),
|
||||
("A5",1.5),(None,.5),("G5",2),
|
||||
("D5",1.5),(None,.5),("E5",1),("G5",1),
|
||||
("A5",2),("B5",1),("A5",1),
|
||||
("G5",1.5),(None,.5),("E5",1),("D5",1),
|
||||
("G4",3),(None,1),
|
||||
for n, d, v in [
|
||||
("G5",1.5,85),(None,.5,0),("B5",1,90),("A5",1,82),
|
||||
("G5",2,80),("E5",1,75),("D5",1,72),
|
||||
("C5",1.5,78),(None,.5,0),("E5",1,80),("G5",1,85),
|
||||
("A5",1.5,88),(None,.5,0),("G5",2,82),
|
||||
("D5",1.5,78),(None,.5,0),("E5",1,80),("G5",1,85),
|
||||
("A5",2,90),("B5",1,92),("A5",1,85),
|
||||
("G5",1.5,82),(None,.5,0),("E5",1,78),("D5",1,72),
|
||||
("G4",3,75),(None,1,0),
|
||||
]:
|
||||
lead.rest(d) if n is None else lead.add(n, d)
|
||||
lead.rest(d) if n is None else lead.add(n, d, velocity=v)
|
||||
|
||||
for n in ["G2","G2","B2","D3","C3","C3","E3","G3",
|
||||
"D3","D3","F#3","A3","C3","C3","E3","G3",
|
||||
@@ -278,30 +288,32 @@ def funk_workout():
|
||||
volume=0.4, pan=0.35,
|
||||
lowpass=3500, lowpass_q=1.5,
|
||||
delay=0.15, delay_time=0.15, delay_feedback=0.25,
|
||||
reverb=0.1, reverb_type="plate")
|
||||
reverb=0.1, reverb_type="plate",
|
||||
humanize=0.2)
|
||||
bass = score.part("bass", instrument="synth_bass",
|
||||
volume=0.5, pan=0.0, lowpass=600, lowpass_q=1.2)
|
||||
volume=0.5, pan=0.0, lowpass=600, lowpass_q=1.2,
|
||||
humanize=0.2, reverb=0.15)
|
||||
|
||||
for sym in ["Em", "Am", "D", "B7"] * 2:
|
||||
chords.add(Chord.from_symbol(sym), Duration.WHOLE)
|
||||
|
||||
for n, d in [
|
||||
("E5",.25),("E5",.25),(None,.25),("G5",.25),
|
||||
(None,.25),("A5",.25),("G5",.25),("E5",.25),
|
||||
("D5",.5),("E5",.5),(None,.5),("B4",.5),
|
||||
("E5",.25),("E5",.25),(None,.25),("G5",.25),
|
||||
(None,.25),("A5",.25),("B5",.25),("A5",.25),
|
||||
("G5",.5),("E5",.5),(None,1),
|
||||
("A4",.25),("C5",.25),("E5",.25),("A5",.25),
|
||||
("G5",.5),("E5",.5),(None,.5),("C5",.5),
|
||||
("A4",.5),("C5",.5),("D5",.5),("E5",.5),
|
||||
("E5",1),(None,1),
|
||||
("D5",.25),("F#5",.25),("A5",.25),("D5",.25),
|
||||
("F#5",.5),("D5",.5),("A4",.5),("D5",.5),
|
||||
("D#5",.5),("F#5",.5),("B4",.5),("D#5",.5),
|
||||
("F#5",1),(None,1),
|
||||
for n, d, v in [
|
||||
("E5",.25,90),("E5",.25,78),(None,.25,0),("G5",.25,85),
|
||||
(None,.25,0),("A5",.25,88),("G5",.25,82),("E5",.25,78),
|
||||
("D5",.5,80),("E5",.5,85),(None,.5,0),("B4",.5,72),
|
||||
("E5",.25,88),("E5",.25,78),(None,.25,0),("G5",.25,85),
|
||||
(None,.25,0),("A5",.25,90),("B5",.25,92),("A5",.25,85),
|
||||
("G5",.5,82),("E5",.5,78),(None,1,0),
|
||||
("A4",.25,80),("C5",.25,82),("E5",.25,88),("A5",.25,92),
|
||||
("G5",.5,85),("E5",.5,78),(None,.5,0),("C5",.5,75),
|
||||
("A4",.5,78),("C5",.5,80),("D5",.5,82),("E5",.5,85),
|
||||
("E5",1,82),(None,1,0),
|
||||
("D5",.25,82),("F#5",.25,85),("A5",.25,90),("D5",.25,78),
|
||||
("F#5",.5,85),("D5",.5,78),("A4",.5,75),("D5",.5,80),
|
||||
("D#5",.5,82),("F#5",.5,88),("B4",.5,78),("D#5",.5,82),
|
||||
("F#5",1,85),(None,1,0),
|
||||
]:
|
||||
lead.rest(d) if n is None else lead.add(n, d)
|
||||
lead.rest(d) if n is None else lead.add(n, d, velocity=v)
|
||||
|
||||
for n in ["E2","E2","G2","E2","A2","A2","C3","A2",
|
||||
"D2","D2","F#2","D2","B1","B1","D#2","F#2"] * 2:
|
||||
@@ -313,7 +325,7 @@ def funk_workout():
|
||||
def blues_shuffle():
|
||||
"""12/8 blues in A — slow shuffle with wailing lead."""
|
||||
print(" 12/8 Blues Shuffle in A")
|
||||
print(" 12/8 blues drums | saw lead + reverb + delay | sine bass + LP 500Hz")
|
||||
print(" 12/8 blues drums | saxophone lead + reverb + delay | upright bass + LP 500Hz")
|
||||
|
||||
score = Score("12/8", bpm=70)
|
||||
score.drums("12/8 blues", repeats=6)
|
||||
@@ -321,32 +333,34 @@ def blues_shuffle():
|
||||
chords = score.part("chords", instrument="electric_piano",
|
||||
volume=0.3, pan=-0.3,
|
||||
reverb=0.3, reverb_decay=1.5, reverb_type="plate")
|
||||
lead = score.part("lead", instrument="trumpet",
|
||||
lead = score.part("lead", instrument="saxophone",
|
||||
volume=0.45, pan=0.25,
|
||||
reverb=0.3, reverb_decay=1.2, reverb_type="plate",
|
||||
delay=0.2, delay_time=0.43, delay_feedback=0.3,
|
||||
lowpass=3500)
|
||||
lowpass=3500,
|
||||
humanize=0.2)
|
||||
bass = score.part("bass", instrument="upright_bass",
|
||||
volume=0.5, pan=0.0, lowpass=500)
|
||||
volume=0.5, pan=0.0, lowpass=500,
|
||||
humanize=0.2, reverb=0.2)
|
||||
|
||||
for sym in ["A", "A", "D", "D", "E7", "A"]:
|
||||
chords.add(Chord.from_symbol(sym), Duration.DOTTED_HALF)
|
||||
chords.add(Chord.from_symbol(sym), Duration.DOTTED_HALF)
|
||||
|
||||
for n, d in [
|
||||
("A4",1),("C5",.67),("A4",.33),("E4",1),
|
||||
(None,.5),("A4",.5),("C5",.67),("D5",.33),
|
||||
("E5",1.5),("D5",.5),("C5",.5),("A4",.5),
|
||||
("E4",1.5),(None,.5),("A4",1),
|
||||
("D5",1),("F5",.67),("D5",.33),("A4",1),
|
||||
(None,1),("D5",.67),("F5",.33),("A5",1),
|
||||
("G5",.67),("F5",.33),("D5",1),(None,1),
|
||||
("E5",.67),("G#4",.33),("B4",.67),("E5",.33),
|
||||
("D5",1),("A4",1),(None,1),
|
||||
("A4",.67),("C5",.33),("E5",.67),("A5",.33),
|
||||
("A5",2),(None,1),
|
||||
for n, d, v in [
|
||||
("A4",1,80),("C5",.67,85),("A4",.33,75),("E4",1,78),
|
||||
(None,.5,0),("A4",.5,80),("C5",.67,85),("D5",.33,82),
|
||||
("E5",1.5,92),("D5",.5,80),("C5",.5,78),("A4",.5,75),
|
||||
("E4",1.5,72),(None,.5,0),("A4",1,80),
|
||||
("D5",1,85),("F5",.67,90),("D5",.33,78),("A4",1,80),
|
||||
(None,1,0),("D5",.67,82),("F5",.33,88),("A5",1,95),
|
||||
("G5",.67,88),("F5",.33,80),("D5",1,78),(None,1,0),
|
||||
("E5",.67,85),("G#4",.33,72),("B4",.67,80),("E5",.33,85),
|
||||
("D5",1,82),("A4",1,78),(None,1,0),
|
||||
("A4",.67,78),("C5",.33,82),("E5",.67,90),("A5",.33,95),
|
||||
("A5",2,92),(None,1,0),
|
||||
]:
|
||||
lead.rest(d) if n is None else lead.add(n, d)
|
||||
lead.rest(d) if n is None else lead.add(n, d, velocity=v)
|
||||
|
||||
for n in ["A1","A1","E2","A2","A1","A1","E2","A2","A1","A1","E2","A2",
|
||||
"D2","D2","A2","D2","D2","D2","A2","D2",
|
||||
@@ -372,25 +386,27 @@ def samba_de_janeiro():
|
||||
lead = score.part("lead", instrument="flute",
|
||||
volume=0.45, pan=0.3,
|
||||
delay=0.2, delay_time=0.176, delay_feedback=0.3,
|
||||
reverb=0.15, reverb_type="plate")
|
||||
reverb=0.15, reverb_type="plate",
|
||||
humanize=0.2)
|
||||
bass = score.part("bass", instrument="bass_guitar",
|
||||
volume=0.45, pan=0.0, lowpass=500)
|
||||
volume=0.45, pan=0.0, lowpass=500,
|
||||
humanize=0.2, reverb=0.2)
|
||||
|
||||
for sym in ["G", "Em", "Am", "D7"] * 2:
|
||||
pads.add(Chord.from_symbol(sym), Duration.WHOLE)
|
||||
|
||||
for n, d in [
|
||||
("B5",.33),("A5",.33),("G5",.34),("F#5",.5),("E5",.5),
|
||||
("D5",.5),("G5",.5),("B5",.5),("A5",.5),
|
||||
("G5",.67),("E5",.33),("D5",.67),("B4",.33),("G4",1),(None,1),
|
||||
("E5",.5),("G5",.5),("B5",.5),("A5",.5),
|
||||
("G5",.67),("F#5",.33),("E5",.67),("D5",.33),("E5",1),(None,1),
|
||||
("A5",.5),("C6",.5),("B5",.5),("A5",.5),
|
||||
("G5",.67),("E5",.33),("C5",.67),("A4",.33),("A4",1),(None,1),
|
||||
("D5",.5),("F#5",.5),("A5",.5),("C5",.5),
|
||||
("B4",.67),("A4",.33),("G4",.67),("F#4",.33),("G4",2),(None,2),
|
||||
for n, d, v in [
|
||||
("B5",.33,88),("A5",.33,82),("G5",.34,78),("F#5",.5,82),("E5",.5,75),
|
||||
("D5",.5,72),("G5",.5,80),("B5",.5,88),("A5",.5,82),
|
||||
("G5",.67,85),("E5",.33,78),("D5",.67,75),("B4",.33,70),("G4",1,72),(None,1,0),
|
||||
("E5",.5,80),("G5",.5,85),("B5",.5,90),("A5",.5,82),
|
||||
("G5",.67,85),("F#5",.33,80),("E5",.67,78),("D5",.33,72),("E5",1,80),(None,1,0),
|
||||
("A5",.5,85),("C6",.5,92),("B5",.5,88),("A5",.5,82),
|
||||
("G5",.67,85),("E5",.33,78),("C5",.67,75),("A4",.33,70),("A4",1,72),(None,1,0),
|
||||
("D5",.5,78),("F#5",.5,85),("A5",.5,90),("C5",.5,75),
|
||||
("B4",.67,78),("A4",.33,72),("G4",.67,70),("F#4",.33,68),("G4",2,75),(None,2,0),
|
||||
]:
|
||||
lead.rest(d) if n is None else lead.add(n, d)
|
||||
lead.rest(d) if n is None else lead.add(n, d, velocity=v)
|
||||
|
||||
for n in ["G2","B2","D3","G2","E2","G2","B2","E2",
|
||||
"A2","C3","E3","A2","D2","F#2","A2","D3"] * 2:
|
||||
@@ -413,26 +429,28 @@ def jazz_waltz():
|
||||
lead = score.part("lead", instrument="flute",
|
||||
volume=0.4, pan=0.25,
|
||||
reverb=0.3, reverb_decay=1.5, reverb_type="plate",
|
||||
delay=0.2, delay_time=0.4, delay_feedback=0.3)
|
||||
delay=0.2, delay_time=0.4, delay_feedback=0.3,
|
||||
humanize=0.2)
|
||||
bass = score.part("bass", instrument="upright_bass",
|
||||
volume=0.4, pan=0.0, lowpass=500)
|
||||
volume=0.4, pan=0.0, lowpass=500,
|
||||
humanize=0.2, reverb=0.2)
|
||||
|
||||
for _ in range(2):
|
||||
for sym in ["Fmaj7", "Gm", "C7", "Fmaj7"]:
|
||||
for _ in range(4):
|
||||
rhodes.add(Chord.from_symbol(sym), Duration.DOTTED_HALF)
|
||||
|
||||
for n, d in [
|
||||
("A5",1.5),("G5",.5),("F5",1),("E5",1),("C5",1),("F5",1),
|
||||
("A5",2),(None,1),("G5",2),(None,1),
|
||||
("Bb5",1),("A5",.5),("G5",.5),("F5",1),("D5",1),("G5",1),
|
||||
("Bb5",2),(None,1),("A5",1.5),("G5",.5),("F5",1),
|
||||
("E5",1),("G5",1),("Bb5",1),("A5",1.5),("G5",.5),("E5",1),
|
||||
("C5",2),(None,1),("E5",1),("G5",1),("C5",1),
|
||||
("F5",2),("A5",1),("C6",2),(None,1),
|
||||
("A5",1),("F5",1),("C5",1),("F5",3),
|
||||
for n, d, v in [
|
||||
("A5",1.5,85),("G5",.5,78),("F5",1,80),("E5",1,75),("C5",1,72),("F5",1,80),
|
||||
("A5",2,88),(None,1,0),("G5",2,82),(None,1,0),
|
||||
("Bb5",1,90),("A5",.5,82),("G5",.5,78),("F5",1,80),("D5",1,75),("G5",1,82),
|
||||
("Bb5",2,90),(None,1,0),("A5",1.5,85),("G5",.5,78),("F5",1,80),
|
||||
("E5",1,78),("G5",1,82),("Bb5",1,88),("A5",1.5,85),("G5",.5,78),("E5",1,75),
|
||||
("C5",2,72),(None,1,0),("E5",1,78),("G5",1,82),("C5",1,72),
|
||||
("F5",2,82),("A5",1,88),("C6",2,92),(None,1,0),
|
||||
("A5",1,85),("F5",1,80),("C5",1,72),("F5",3,82),
|
||||
]:
|
||||
lead.rest(d) if n is None else lead.add(n, d)
|
||||
lead.rest(d) if n is None else lead.add(n, d, velocity=v)
|
||||
|
||||
for n in ["F2","A2","C3","G2","Bb2","D3","C2","E2","G2","F2","A2","C3"] * 4:
|
||||
bass.add(n, Duration.QUARTER)
|
||||
@@ -461,7 +479,8 @@ def house_anthem():
|
||||
reverb=0.15, reverb_type="plate")
|
||||
bass = score.part("bass", instrument="808_bass",
|
||||
volume=0.55, pan=0.0,
|
||||
sidechain=0.5)
|
||||
sidechain=0.5,
|
||||
reverb=0.1)
|
||||
|
||||
for sym in ["Cm", "Ab", "Bb", "Cm"] * 2:
|
||||
pads.add(Chord.from_symbol(sym), Duration.WHOLE)
|
||||
@@ -518,9 +537,11 @@ def dub_kingston():
|
||||
lead = score.part("lead", instrument="flute",
|
||||
volume=0.4, pan=0.3,
|
||||
delay=0.45, delay_time=0.625, delay_feedback=0.5,
|
||||
reverb=0.35, reverb_decay=2.0, reverb_type="cathedral")
|
||||
reverb=0.35, reverb_decay=2.0, reverb_type="cathedral",
|
||||
humanize=0.2)
|
||||
bass = score.part("bass", instrument="bass_guitar",
|
||||
volume=0.6, pan=0.0, lowpass=400, lowpass_q=1.5)
|
||||
volume=0.6, pan=0.0, lowpass=400, lowpass_q=1.5,
|
||||
humanize=0.2)
|
||||
siren = score.part("siren", synth="pwm_slow", envelope="pad",
|
||||
volume=0.15, pan=0.5,
|
||||
reverb=0.7, reverb_decay=3.0, reverb_type="cathedral",
|
||||
@@ -529,13 +550,13 @@ def dub_kingston():
|
||||
for sym in ["Am", "Am", "Dm", "Dm", "Am", "Am", "Em", "Am"]:
|
||||
chords.add(Chord.from_symbol(sym), Duration.WHOLE)
|
||||
|
||||
for n, d in [
|
||||
("A4", 2), (None, 2), ("C5", 1.5), (None, 2.5),
|
||||
("D5", 1), ("C5", 1), ("A4", 2), (None, 4),
|
||||
("E5", 2), (None, 2), ("D5", 1.5), ("C5", 1.5), (None, 3),
|
||||
("A4", 1), ("G4", 1), ("A4", 3), (None, 3),
|
||||
for n, d, v in [
|
||||
("A4", 2, 78), (None, 2, 0), ("C5", 1.5, 82), (None, 2.5, 0),
|
||||
("D5", 1, 85), ("C5", 1, 78), ("A4", 2, 75), (None, 4, 0),
|
||||
("E5", 2, 88), (None, 2, 0), ("D5", 1.5, 82), ("C5", 1.5, 78), (None, 3, 0),
|
||||
("A4", 1, 75), ("G4", 1, 70), ("A4", 3, 78), (None, 3, 0),
|
||||
]:
|
||||
lead.rest(d) if n is None else lead.add(n, d)
|
||||
lead.rest(d) if n is None else lead.add(n, d, velocity=v)
|
||||
|
||||
for n in ["A1","A1","A1","A1","D1","D1","D1","D1",
|
||||
"A1","A1","A1","A1","E1","E1","A1","A1"]:
|
||||
@@ -573,7 +594,8 @@ def techno_minimal():
|
||||
humanize=0.2)
|
||||
bass = score.part("bass", instrument="808_bass",
|
||||
volume=0.55, pan=0.0,
|
||||
sidechain=0.5)
|
||||
sidechain=0.5,
|
||||
reverb=0.1)
|
||||
|
||||
for sym in ["Fm", "Db", "Eb", "Fm"] * 2:
|
||||
pad.add(Chord.from_symbol(sym), Duration.WHOLE)
|
||||
@@ -605,31 +627,33 @@ def gospel_shuffle():
|
||||
lead = score.part("lead", instrument="flute",
|
||||
volume=0.4, pan=0.3,
|
||||
delay=0.2, delay_time=0.278, delay_feedback=0.3,
|
||||
reverb=0.2, reverb_type="plate")
|
||||
reverb=0.2, reverb_type="plate",
|
||||
humanize=0.2)
|
||||
bass = score.part("bass", instrument="upright_bass",
|
||||
volume=0.45, pan=0.0, lowpass=500)
|
||||
volume=0.45, pan=0.0, lowpass=500,
|
||||
humanize=0.2, reverb=0.2)
|
||||
|
||||
for sym in ["C", "Am", "F", "G"] * 2:
|
||||
organ.add(Chord.from_symbol(sym), Duration.WHOLE)
|
||||
|
||||
for n, d in [
|
||||
("E5",.67),("G5",.33),("C6",1),("B5",.67),("A5",.33),
|
||||
("G5",1),(None,1),
|
||||
("A5",.67),("C6",.33),("E5",1),("D5",.67),("C5",.33),
|
||||
("A4",1),(None,1),
|
||||
("F5",.67),("A5",.33),("C6",1),("B5",.67),("A5",.33),
|
||||
("G5",.67),("E5",.33),("C5",1),(None,1),
|
||||
("D5",.67),("E5",.33),("G5",.67),("B5",.33),
|
||||
("C6",2),(None,2),
|
||||
for n, d, v in [
|
||||
("E5",.67,82),("G5",.33,78),("C6",1,92),("B5",.67,85),("A5",.33,80),
|
||||
("G5",1,82),(None,1,0),
|
||||
("A5",.67,85),("C6",.33,88),("E5",1,80),("D5",.67,78),("C5",.33,72),
|
||||
("A4",1,75),(None,1,0),
|
||||
("F5",.67,82),("A5",.33,85),("C6",1,92),("B5",.67,88),("A5",.33,82),
|
||||
("G5",.67,80),("E5",.33,75),("C5",1,72),(None,1,0),
|
||||
("D5",.67,78),("E5",.33,80),("G5",.67,85),("B5",.33,88),
|
||||
("C6",2,92),(None,2,0),
|
||||
# Second half: more intense
|
||||
("C6",.67),("B5",.33),("A5",.67),("G5",.33),
|
||||
("E5",1),("C5",.67),("E5",.33),
|
||||
("A5",1),("G5",.67),("E5",.33),("C5",1),(None,1),
|
||||
("F5",1),("A5",.67),("C6",.33),("E6",2),
|
||||
("D6",.67),("C6",.33),("B5",.67),("G5",.33),
|
||||
("C6",3),(None,1),
|
||||
("C6",.67,95),("B5",.33,88),("A5",.67,90),("G5",.33,82),
|
||||
("E5",1,85),("C5",.67,78),("E5",.33,82),
|
||||
("A5",1,90),("G5",.67,85),("E5",.33,78),("C5",1,75),(None,1,0),
|
||||
("F5",1,85),("A5",.67,90),("C6",.33,95),("E6",2,100),
|
||||
("D6",.67,92),("C6",.33,88),("B5",.67,90),("G5",.33,82),
|
||||
("C6",3,95),(None,1,0),
|
||||
]:
|
||||
lead.rest(d) if n is None else lead.add(n, d)
|
||||
lead.rest(d) if n is None else lead.add(n, d, velocity=v)
|
||||
|
||||
for n in ["C2","E2","G2","C3","A1","C2","E2","A2",
|
||||
"F2","A2","C3","F2","G2","B2","D3","G2"] * 2:
|
||||
@@ -664,7 +688,8 @@ def dub_delay_madness():
|
||||
reverb=0.7, reverb_decay=3.0, reverb_type="cathedral",
|
||||
lowpass=1200, detune=8, humanize=0.2)
|
||||
bass = score.part("bass", instrument="bass_guitar",
|
||||
volume=0.6, pan=0.0, lowpass=350, lowpass_q=1.5)
|
||||
volume=0.6, pan=0.0, lowpass=350, lowpass_q=1.5,
|
||||
humanize=0.2)
|
||||
siren = score.part("siren", synth="pwm_slow", envelope="pad",
|
||||
volume=0.12, pan=0.5,
|
||||
reverb=0.8, reverb_decay=4.0, reverb_type="cathedral",
|
||||
@@ -674,7 +699,8 @@ def dub_delay_madness():
|
||||
melodica = score.part("melodica", instrument="flute",
|
||||
volume=0.35, pan=0.3,
|
||||
delay=0.6, delay_time=0.66, delay_feedback=0.55,
|
||||
reverb=0.5, reverb_decay=2.5, reverb_type="cathedral")
|
||||
reverb=0.5, reverb_decay=2.5, reverb_type="cathedral",
|
||||
humanize=0.2)
|
||||
|
||||
for sym in ["Em", "Em", "Am", "Am", "Em", "Em", "Bm", "Em"]:
|
||||
chords.add(Chord.from_symbol(sym), Duration.WHOLE)
|
||||
@@ -684,13 +710,13 @@ def dub_delay_madness():
|
||||
bass.add(n, Duration.HALF)
|
||||
|
||||
# Melodica: very sparse — let the delay do the work
|
||||
for n, d in [
|
||||
("E5", 1.5), (None, 6.5),
|
||||
("G5", 1), ("A5", 1), (None, 6),
|
||||
(None, 4), ("B5", 2), (None, 6),
|
||||
("E5", 1), (None, 3), ("D5", 1.5), (None, 2.5),
|
||||
for n, d, v in [
|
||||
("E5", 1.5, 78), (None, 6.5, 0),
|
||||
("G5", 1, 82), ("A5", 1, 85), (None, 6, 0),
|
||||
(None, 4, 0), ("B5", 2, 88), (None, 6, 0),
|
||||
("E5", 1, 75), (None, 3, 0), ("D5", 1.5, 72), (None, 2.5, 0),
|
||||
]:
|
||||
melodica.rest(d) if n is None else melodica.add(n, d)
|
||||
melodica.rest(d) if n is None else melodica.add(n, d, velocity=v)
|
||||
|
||||
# Siren: long notes that disappear into the void
|
||||
for n, d in [
|
||||
@@ -718,25 +744,27 @@ def drum_and_bass():
|
||||
lead = score.part("lead", instrument="flute",
|
||||
volume=0.4, pan=0.3,
|
||||
delay=0.3, delay_time=0.172, delay_feedback=0.4,
|
||||
reverb=0.25, reverb_type="plate")
|
||||
reverb=0.25, reverb_type="plate",
|
||||
humanize=0.2)
|
||||
bass = score.part("bass", instrument="808_bass",
|
||||
volume=0.55, pan=0.0)
|
||||
volume=0.55, pan=0.0,
|
||||
reverb=0.1)
|
||||
|
||||
for sym in ["Am", "F", "C", "G"] * 2:
|
||||
pads.add(Chord.from_symbol(sym), Duration.WHOLE)
|
||||
|
||||
# Liquid melody — flowing, emotional
|
||||
for n, d in [
|
||||
("A5", 1), ("G5", .5), ("E5", .5), ("C5", 1), (None, 1),
|
||||
("D5", .5), ("E5", .5), ("G5", 1), ("A5", 1.5), (None, .5),
|
||||
("C6", 1), ("B5", .5), ("A5", .5), ("G5", 1), ("E5", 1),
|
||||
("F5", .5), ("G5", .5), ("A5", 1.5), (None, .5), ("G5", 1),
|
||||
("A5", 1), ("G5", .5), ("E5", .5), ("C5", 1), (None, 1),
|
||||
("E5", .5), ("G5", .5), ("B5", 1), ("A5", 2),
|
||||
("G5", 1), ("E5", .5), ("D5", .5), ("C5", 1.5), (None, .5),
|
||||
("E5", .5), ("G5", .5), ("A5", 2), (None, 1),
|
||||
for n, d, v in [
|
||||
("A5", 1, 85), ("G5", .5, 78), ("E5", .5, 72), ("C5", 1, 75), (None, 1, 0),
|
||||
("D5", .5, 72), ("E5", .5, 78), ("G5", 1, 82), ("A5", 1.5, 88), (None, .5, 0),
|
||||
("C6", 1, 92), ("B5", .5, 85), ("A5", .5, 80), ("G5", 1, 82), ("E5", 1, 75),
|
||||
("F5", .5, 78), ("G5", .5, 82), ("A5", 1.5, 88), (None, .5, 0), ("G5", 1, 80),
|
||||
("A5", 1, 85), ("G5", .5, 78), ("E5", .5, 72), ("C5", 1, 75), (None, 1, 0),
|
||||
("E5", .5, 78), ("G5", .5, 82), ("B5", 1, 90), ("A5", 2, 85),
|
||||
("G5", 1, 80), ("E5", .5, 75), ("D5", .5, 70), ("C5", 1.5, 72), (None, .5, 0),
|
||||
("E5", .5, 78), ("G5", .5, 82), ("A5", 2, 88), (None, 1, 0),
|
||||
]:
|
||||
lead.rest(d) if n is None else lead.add(n, d)
|
||||
lead.rest(d) if n is None else lead.add(n, d, velocity=v)
|
||||
|
||||
# Sub bass — half note roots, deep
|
||||
for n in ["A1","A1","F1","F1","C1","C1","G1","G1"] * 2:
|
||||
@@ -762,7 +790,8 @@ def drake_vibes():
|
||||
bells = score.part("bells", instrument="vibraphone",
|
||||
volume=0.3, pan=0.4,
|
||||
reverb=0.4, reverb_decay=2.0, reverb_type="plate",
|
||||
delay=0.25, delay_time=0.44, delay_feedback=0.35)
|
||||
delay=0.25, delay_time=0.44, delay_feedback=0.35,
|
||||
humanize=0.2)
|
||||
lead = score.part("lead", synth="pwm_slow", envelope="strings",
|
||||
volume=0.35, pan=-0.2,
|
||||
reverb=0.3, reverb_type="cathedral", lowpass=2000,
|
||||
@@ -994,10 +1023,12 @@ def dance_party():
|
||||
|
||||
bass = score.part("bass", instrument="synth_bass",
|
||||
volume=0.45, lowpass=500, lowpass_q=1.3,
|
||||
sidechain=0.75, sidechain_release=0.12)
|
||||
sidechain=0.75, sidechain_release=0.12,
|
||||
reverb=0.15)
|
||||
sparkle = score.part("sparkle", instrument="vibraphone",
|
||||
volume=0.3, pan=0.4, reverb=0.3, reverb_decay=1.5,
|
||||
delay=0.2, delay_time=0.234, delay_feedback=0.3)
|
||||
delay=0.2, delay_time=0.234, delay_feedback=0.3,
|
||||
humanize=0.2)
|
||||
chords_part = score.part("chords", instrument="synth_pad",
|
||||
volume=0.2,
|
||||
reverb=0.4, reverb_type="plate", sidechain=0.7)
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "pytheory"
|
||||
version = "0.36.1"
|
||||
version = "0.36.2"
|
||||
description = "Music Theory for Humans"
|
||||
readme = "README.md"
|
||||
license = "MIT"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"""PyTheory: Music Theory for Humans."""
|
||||
|
||||
__version__ = "0.36.1"
|
||||
__version__ = "0.36.2"
|
||||
|
||||
from .tones import Tone, Interval
|
||||
from .systems import System, SYSTEMS, TET
|
||||
|
||||
+5
-2
@@ -303,7 +303,7 @@ def cmd_demo(args):
|
||||
"fill": "rock", "bpm": 85,
|
||||
"prog": ("i", "iv", "V", "i"),
|
||||
"lead": ("theremin_synth", "pad", 0.4, 0.0),
|
||||
"pad": ("granular_synth", "pad", 0.0),
|
||||
"pad": ("strings_synth", "pad", 0.0),
|
||||
"bass_lp": 300, "reverb_type": "cave"},
|
||||
{"name": "Caribbean", "key": ("C", "major"), "drums": "reggae",
|
||||
"fill": "reggae", "bpm": 110,
|
||||
@@ -423,7 +423,10 @@ def cmd_demo(args):
|
||||
print(f" {mood['drums']} | {lead_synth} lead | {pad_synth} pad | {mood['reverb_type']} reverb")
|
||||
print()
|
||||
|
||||
play_score(score)
|
||||
try:
|
||||
play_score(score)
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
print(" ♫")
|
||||
|
||||
|
||||
|
||||
+10
-4
@@ -1741,8 +1741,11 @@ def _play_for(sample_wave, ms):
|
||||
"""Play the given NumPy sample array through the speakers."""
|
||||
normalized_wave = sample_wave.astype(numpy.float32) / SAMPLE_PEAK
|
||||
_sd = _get_sd()
|
||||
_sd.play(normalized_wave, SAMPLE_RATE)
|
||||
_sd.wait()
|
||||
try:
|
||||
_sd.play(normalized_wave, SAMPLE_RATE)
|
||||
_sd.wait()
|
||||
except KeyboardInterrupt:
|
||||
_sd.stop()
|
||||
|
||||
|
||||
class Synth(Enum):
|
||||
@@ -4634,8 +4637,11 @@ def play_score(score):
|
||||
"""
|
||||
buf = render_score(score)
|
||||
_sd = _get_sd()
|
||||
_sd.play(buf, SAMPLE_RATE)
|
||||
_sd.wait()
|
||||
try:
|
||||
_sd.play(buf, SAMPLE_RATE)
|
||||
_sd.wait()
|
||||
except KeyboardInterrupt:
|
||||
_sd.stop()
|
||||
|
||||
|
||||
# ── MIDI export ─────────────────────────────────────────────────────────────
|
||||
|
||||
+176
-7
@@ -77,6 +77,7 @@ def cmd_help(session, args):
|
||||
Parts:
|
||||
part lead saw pluck score.part("lead", synth="saw", envelope="pluck")
|
||||
part bass sine score.part("bass", synth="sine")
|
||||
part lead instrument piano score.part("lead", instrument="piano")
|
||||
part list all parts
|
||||
|
||||
Notes (on active part):
|
||||
@@ -85,6 +86,12 @@ def cmd_help(session, args):
|
||||
rest 2 part.rest(2.0)
|
||||
arp Am updown 2 2 part.arpeggio("Am", pattern="updown", bars=2, octaves=2)
|
||||
prog I V vi IV part adds key.progression(...)
|
||||
strum Am 2 down part.strum("Am", 2, direction="down")
|
||||
strum G 2 up 0.1 lazy strum (strum_time=0.1)
|
||||
roll C3 4 part.roll("C3", 4) — timpani/tremolo
|
||||
roll C3 4 30 110 roll with velocity ramp
|
||||
bend C5 1 2 part.add("C5", 1, bend=2) — bend up 2 semitones
|
||||
bend C5 1 -1 bend down a half step
|
||||
|
||||
Effects (on active part):
|
||||
reverb 0.4 reverb=0.4
|
||||
@@ -110,6 +117,12 @@ def cmd_help(session, args):
|
||||
fingering Am guitar chord fingering
|
||||
diagram [mode] [frets] scale diagram on guitar
|
||||
|
||||
Tuning:
|
||||
temperament equal set temperament (equal/pythagorean/meantone/just)
|
||||
temperament show current temperament
|
||||
reference 432 set reference pitch (default 440)
|
||||
instruments list all available instruments
|
||||
|
||||
Session:
|
||||
show score info
|
||||
status current state
|
||||
@@ -197,12 +210,22 @@ def cmd_part(session, args):
|
||||
return
|
||||
|
||||
name = args[0]
|
||||
synth = args[1] if len(args) > 1 else "saw"
|
||||
envelope = args[2] if len(args) > 2 else "pluck"
|
||||
|
||||
if name not in session.parts:
|
||||
session.parts[name] = session.score.part(name, synth=synth, envelope=envelope)
|
||||
print(f" score.part(\"{name}\", synth=\"{synth}\", envelope=\"{envelope}\")")
|
||||
# Check if second arg is "instrument" keyword or an instrument name
|
||||
if len(args) > 1 and args[1] == "instrument" and len(args) > 2:
|
||||
instrument = args[2]
|
||||
session.parts[name] = session.score.part(name, instrument=instrument)
|
||||
print(f" score.part(\"{name}\", instrument=\"{instrument}\")")
|
||||
elif len(args) > 1 and args[1] in _INSTRUMENT_NAMES:
|
||||
instrument = args[1]
|
||||
session.parts[name] = session.score.part(name, instrument=instrument)
|
||||
print(f" score.part(\"{name}\", instrument=\"{instrument}\")")
|
||||
else:
|
||||
synth = args[1] if len(args) > 1 else "saw"
|
||||
envelope = args[2] if len(args) > 2 else "pluck"
|
||||
session.parts[name] = session.score.part(name, synth=synth, envelope=envelope)
|
||||
print(f" score.part(\"{name}\", synth=\"{synth}\", envelope=\"{envelope}\")")
|
||||
else:
|
||||
print(f" → {name}")
|
||||
session.current_part = session.parts[name]
|
||||
@@ -534,6 +557,97 @@ def cmd_identify(session, args):
|
||||
print(f" error: {e}")
|
||||
|
||||
|
||||
def cmd_strum(session, args):
|
||||
"""Strum a chord on a fretboard-equipped part."""
|
||||
if not args:
|
||||
print(" usage: strum Am [beats] [down|up] [strum_time]")
|
||||
return
|
||||
part = _require_part(session)
|
||||
chord_name = args[0]
|
||||
beats = float(args[1]) if len(args) > 1 else 1.0
|
||||
direction = args[2] if len(args) > 2 else "down"
|
||||
strum_time = float(args[3]) if len(args) > 3 else 0.05
|
||||
try:
|
||||
part.strum(chord_name, beats, direction=direction, strum_time=strum_time)
|
||||
print(f" .strum(\"{chord_name}\", {beats}, direction=\"{direction}\", "
|
||||
f"strum_time={strum_time})")
|
||||
except Exception as e:
|
||||
print(f" error: {e}")
|
||||
|
||||
|
||||
def cmd_roll(session, args):
|
||||
"""Play a roll (rapid repeated notes with velocity ramp)."""
|
||||
if not args:
|
||||
print(" usage: roll C3 [beats] [vel_start] [vel_end]")
|
||||
return
|
||||
part = _require_part(session)
|
||||
tone = args[0]
|
||||
beats = float(args[1]) if len(args) > 1 else 4.0
|
||||
vel_start = int(args[2]) if len(args) > 2 else 40
|
||||
vel_end = int(args[3]) if len(args) > 3 else 100
|
||||
try:
|
||||
part.roll(tone, beats, velocity_start=vel_start, velocity_end=vel_end)
|
||||
print(f" .roll(\"{tone}\", {beats}, velocity_start={vel_start}, "
|
||||
f"velocity_end={vel_end})")
|
||||
except Exception as e:
|
||||
print(f" error: {e}")
|
||||
|
||||
|
||||
def cmd_bend(session, args):
|
||||
"""Add a note with pitch bend."""
|
||||
if len(args) < 3:
|
||||
print(" usage: bend C5 1 2 (note, beats, semitones)")
|
||||
print(" bend C5 1 -1 (bend down)")
|
||||
return
|
||||
part = _require_part(session)
|
||||
note = args[0]
|
||||
beats = float(args[1])
|
||||
bend = float(args[2])
|
||||
bend_type = args[3] if len(args) > 3 else "smooth"
|
||||
try:
|
||||
part.add(note, beats, bend=bend, bend_type=bend_type)
|
||||
print(f" .add(\"{note}\", {beats}, bend={bend}, bend_type=\"{bend_type}\")")
|
||||
except Exception as e:
|
||||
print(f" error: {e}")
|
||||
|
||||
|
||||
def cmd_temperament(session, args):
|
||||
"""Set or show the tuning temperament."""
|
||||
if not args:
|
||||
temp = getattr(session.score, 'temperament', 'equal')
|
||||
ref = getattr(session.score, 'reference_pitch', 440.0)
|
||||
print(f" temperament={temp} reference={ref} Hz")
|
||||
print(f" available: equal, pythagorean, meantone, just")
|
||||
return
|
||||
temp = args[0]
|
||||
valid = ["equal", "pythagorean", "meantone", "just"]
|
||||
if temp not in valid:
|
||||
print(f" unknown temperament: {temp}")
|
||||
print(f" available: {', '.join(valid)}")
|
||||
return
|
||||
session.score.temperament = temp
|
||||
print(f" temperament={temp}")
|
||||
|
||||
|
||||
def cmd_reference(session, args):
|
||||
"""Set the reference pitch (A4 frequency)."""
|
||||
if not args:
|
||||
ref = getattr(session.score, 'reference_pitch', 440.0)
|
||||
print(f" reference={ref} Hz")
|
||||
return
|
||||
ref = float(args[0])
|
||||
session.score.reference_pitch = ref
|
||||
print(f" reference={ref} Hz")
|
||||
|
||||
|
||||
def cmd_instruments(session, args):
|
||||
"""List all available instruments."""
|
||||
cols = 3
|
||||
for i in range(0, len(_INSTRUMENT_NAMES), cols):
|
||||
row = _INSTRUMENT_NAMES[i:i + cols]
|
||||
print(" " + " ".join(f"{name:<22s}" for name in row))
|
||||
|
||||
|
||||
def cmd_circle(session, args):
|
||||
"""Show circle of fifths."""
|
||||
tonic = args[0] if args else session.key.tonic_name
|
||||
@@ -560,7 +674,10 @@ def cmd_clear(session, args):
|
||||
def cmd_status(session, args):
|
||||
parts = ", ".join(session.parts.keys()) if session.parts else "none"
|
||||
active = session.current_part.name if session.current_part else "none"
|
||||
temp = getattr(session.score, 'temperament', 'equal')
|
||||
ref = getattr(session.score, 'reference_pitch', 440.0)
|
||||
print(f" key={session.key} bpm={session.bpm} swing={session.swing}")
|
||||
print(f" temperament={temp} reference={ref} Hz")
|
||||
print(f" drums={session._drum_preset or 'none'} parts=[{parts}] active={active}")
|
||||
|
||||
|
||||
@@ -607,6 +724,12 @@ COMMANDS = {
|
||||
"interval": cmd_interval,
|
||||
"identify": cmd_identify, "id": cmd_identify,
|
||||
"circle": cmd_circle,
|
||||
"strum": cmd_strum,
|
||||
"roll": cmd_roll,
|
||||
"bend": cmd_bend,
|
||||
"temperament": cmd_temperament, "temp": cmd_temperament,
|
||||
"reference": cmd_reference, "ref": cmd_reference,
|
||||
"instruments": cmd_instruments,
|
||||
"clear": cmd_clear,
|
||||
"status": cmd_status,
|
||||
}
|
||||
@@ -653,9 +776,43 @@ def _prompt(session):
|
||||
# ── Tab completion ─────────────────────────────────────────────────────────
|
||||
|
||||
_SYNTH_NAMES = ["sine", "saw", "triangle", "square", "pulse", "fm",
|
||||
"noise", "supersaw", "pwm_slow", "pwm_fast"]
|
||||
"noise", "supersaw", "pwm_slow", "pwm_fast",
|
||||
"pedal_steel_synth", "theremin_synth", "kalimba_synth",
|
||||
"steel_drum_synth", "accordion_synth", "didgeridoo_synth",
|
||||
"bagpipe_synth", "banjo_synth", "mandolin_synth",
|
||||
"ukulele_synth", "vocal_synth", "granular_synth",
|
||||
"piano_synth", "organ_synth", "harpsichord_synth",
|
||||
"strings_synth", "cello_synth", "flute_synth",
|
||||
"clarinet_synth", "oboe_synth", "trumpet_synth",
|
||||
"acoustic_guitar_synth", "electric_guitar_synth",
|
||||
"bass_guitar_synth", "upright_bass_synth", "harp_synth",
|
||||
"sitar_synth", "pluck_synth", "saxophone_synth",
|
||||
"marimba_synth", "timpani_synth"]
|
||||
_INSTRUMENT_NAMES = [
|
||||
# Keys
|
||||
"piano", "electric_piano", "organ", "harpsichord", "celesta", "music_box",
|
||||
# Strings
|
||||
"violin", "viola", "cello", "contrabass", "string_ensemble",
|
||||
# Woodwinds
|
||||
"flute", "clarinet", "oboe", "bassoon",
|
||||
# Brass
|
||||
"trumpet", "trombone", "french_horn", "tuba", "brass_ensemble",
|
||||
# Plucked
|
||||
"acoustic_guitar", "electric_guitar", "clean_guitar", "crunch_guitar",
|
||||
"distorted_guitar", "orange_crunch", "metal_guitar", "bass_guitar",
|
||||
"upright_bass", "harp", "sitar", "pedal_steel", "theremin", "kalimba",
|
||||
"steel_drum", "accordion", "didgeridoo", "bagpipe", "banjo", "mandolin",
|
||||
"mandola", "ukulele", "koto",
|
||||
# Synth presets
|
||||
"synth_lead", "synth_pad", "synth_bass", "acid_bass",
|
||||
"granular_pad", "vocal", "choir", "granular_texture", "808_bass",
|
||||
# Percussion / Mallet
|
||||
"vibraphone", "marimba", "xylophone", "glockenspiel", "tubular_bells", "timpani",
|
||||
# Woodwinds (continued)
|
||||
"saxophone", "alto_sax", "tenor_sax", "bari_sax",
|
||||
]
|
||||
_ENVELOPE_NAMES = ["piano", "pluck", "pad", "organ", "bell", "strings",
|
||||
"staccato", "none"]
|
||||
"staccato", "bowed", "mallet", "none"]
|
||||
_ARP_PATTERNS = ["up", "down", "updown", "downup", "random"]
|
||||
_LFO_SHAPES = ["sine", "triangle", "saw", "square"]
|
||||
_SYSTEMS = ["western", "indian", "arabic", "japanese", "blues", "gamelan"]
|
||||
@@ -667,7 +824,7 @@ _CHORD_SUFFIXES = ["", "m", "7", "m7", "maj7", "dim", "aug", "sus2", "sus4",
|
||||
# Context-aware completions for the second word
|
||||
_ARG_COMPLETIONS = {
|
||||
"drums": lambda: Pattern.list_presets(),
|
||||
"part": lambda: _SYNTH_NAMES,
|
||||
"part": lambda: _SYNTH_NAMES + _INSTRUMENT_NAMES,
|
||||
"key": lambda: [f"{n}m" for n in _NOTE_NAMES[:12]] + _NOTE_NAMES[:12],
|
||||
"arp": lambda: [f"{n}{s}" for n in _NOTE_NAMES[:7] for s in _CHORD_SUFFIXES[:6]],
|
||||
"add": lambda: [f"{n}{o}" for n in _NOTE_NAMES[:12] for o in ["3", "4", "5"]],
|
||||
@@ -679,6 +836,12 @@ _ARG_COMPLETIONS = {
|
||||
"lowpass_q", "reverb_decay", "delay_time", "delay_feedback",
|
||||
"distortion_drive"],
|
||||
"identify": lambda: [f"{n}{s}" for n in _NOTE_NAMES[:7] for s in _CHORD_SUFFIXES[:6]],
|
||||
"strum": lambda: [f"{n}{s}" for n in _NOTE_NAMES[:7] for s in _CHORD_SUFFIXES[:6]],
|
||||
"roll": lambda: [f"{n}{o}" for n in _NOTE_NAMES[:12] for o in ["2", "3", "4", "5"]],
|
||||
"bend": lambda: [f"{n}{o}" for n in _NOTE_NAMES[:12] for o in ["3", "4", "5"]],
|
||||
"temperament": lambda: ["equal", "pythagorean", "meantone", "just"],
|
||||
"reference": lambda: ["440", "432", "415", "444"],
|
||||
"instruments": lambda: _INSTRUMENT_NAMES,
|
||||
}
|
||||
|
||||
|
||||
@@ -705,6 +868,12 @@ def _completer(text, state):
|
||||
elif cmd == "arp" and len(tokens) == 3:
|
||||
# Pattern for arp
|
||||
options = [p for p in _ARP_PATTERNS if p.startswith(text)]
|
||||
elif cmd == "strum" and len(tokens) == 4:
|
||||
# Direction for strum
|
||||
options = [d for d in ["down", "up"] if d.startswith(text)]
|
||||
elif cmd == "bend" and len(tokens) == 5:
|
||||
# Bend type
|
||||
options = [t for t in ["smooth", "linear", "late"] if t.startswith(text)]
|
||||
elif cmd == "lfo" and len(tokens) >= 7:
|
||||
# Shape for lfo
|
||||
options = [s for s in _LFO_SHAPES if s.startswith(text)]
|
||||
|
||||
+240
-1
@@ -5320,7 +5320,7 @@ def test_supersaw_wave():
|
||||
@needs_portaudio
|
||||
def test_all_synths_in_enum():
|
||||
from pytheory.play import Synth
|
||||
assert len(Synth) == 30
|
||||
assert len(Synth) == 41
|
||||
for s in Synth:
|
||||
wave = s(440, n_samples=1000)
|
||||
assert len(wave) == 1000
|
||||
@@ -6912,3 +6912,242 @@ def test_clean_guitar_preset():
|
||||
p = score.part("g", instrument="clean_guitar")
|
||||
assert p.synth == "electric_guitar_synth"
|
||||
assert p.cabinet > 0
|
||||
|
||||
|
||||
# ── New instrument synths (v0.36+) ──────────────────────────────────────────
|
||||
|
||||
def test_new_synths_render():
|
||||
"""All 7 new synths produce valid audio."""
|
||||
from pytheory.play import (pedal_steel_wave, theremin_wave, kalimba_wave,
|
||||
steel_drum_wave, accordion_wave,
|
||||
didgeridoo_wave, bagpipe_wave,
|
||||
banjo_wave, mandolin_wave, ukulele_wave,
|
||||
vocal_wave, SAMPLE_RATE)
|
||||
synths = [pedal_steel_wave, theremin_wave, kalimba_wave, steel_drum_wave,
|
||||
accordion_wave, didgeridoo_wave, bagpipe_wave,
|
||||
banjo_wave, mandolin_wave, ukulele_wave, vocal_wave]
|
||||
for fn in synths:
|
||||
wave = fn(440, n_samples=11025)
|
||||
assert len(wave) == 11025
|
||||
assert wave.dtype == numpy.int16
|
||||
assert numpy.abs(wave).max() > 0
|
||||
|
||||
|
||||
def test_vocal_synth_with_lyric():
|
||||
"""Vocal synth accepts lyric parameter."""
|
||||
from pytheory.play import vocal_wave
|
||||
for lyric in ["ah", "ee", "oh", "oo", "hi", "la"]:
|
||||
wave = vocal_wave(330, n_samples=11025, lyric=lyric)
|
||||
assert len(wave) == 11025
|
||||
assert numpy.abs(wave).max() > 0
|
||||
|
||||
|
||||
def test_vocal_different_vowels_differ():
|
||||
"""Different vowels should produce different waveforms."""
|
||||
from pytheory.play import vocal_wave
|
||||
ah = vocal_wave(330, n_samples=22050, lyric="ah")
|
||||
ee = vocal_wave(330, n_samples=22050, lyric="ee")
|
||||
# They should differ (different formant peaks)
|
||||
assert not numpy.array_equal(ah, ee)
|
||||
|
||||
|
||||
def test_all_instrument_presets_create():
|
||||
"""Every instrument preset in INSTRUMENTS should create a valid Part."""
|
||||
from pytheory import Score
|
||||
from pytheory.rhythm import INSTRUMENTS
|
||||
for name in INSTRUMENTS:
|
||||
score = Score("4/4", bpm=120)
|
||||
p = score.part("test", instrument=name)
|
||||
assert p.synth is not None
|
||||
|
||||
|
||||
def test_new_instrument_presets():
|
||||
"""New instrument presets have correct synths."""
|
||||
from pytheory import Score
|
||||
presets = {
|
||||
"pedal_steel": "pedal_steel_synth",
|
||||
"theremin": "theremin_synth",
|
||||
"kalimba": "kalimba_synth",
|
||||
"steel_drum": "steel_drum_synth",
|
||||
"accordion": "accordion_synth",
|
||||
"didgeridoo": "didgeridoo_synth",
|
||||
"bagpipe": "bagpipe_synth",
|
||||
"banjo": "banjo_synth",
|
||||
"mandolin": "mandolin_synth",
|
||||
"ukulele": "ukulele_synth",
|
||||
}
|
||||
for name, expected_synth in presets.items():
|
||||
score = Score("4/4", bpm=120)
|
||||
p = score.part("t", instrument=name)
|
||||
assert p.synth == expected_synth, f"{name} has {p.synth}, expected {expected_synth}"
|
||||
|
||||
|
||||
# ── Cajón drums ─────────────────────────────────────────────────────────────
|
||||
|
||||
def test_cajon_sounds_render():
|
||||
from pytheory.play import _render_drum_hit
|
||||
from pytheory.rhythm import DrumSound
|
||||
for sound in [DrumSound.CAJON_BASS, DrumSound.CAJON_SLAP, DrumSound.CAJON_TAP]:
|
||||
wave = _render_drum_hit(sound.value, 22050)
|
||||
assert len(wave) == 22050
|
||||
assert wave.dtype == numpy.float32
|
||||
|
||||
|
||||
def test_cajon_patterns():
|
||||
from pytheory.rhythm import Pattern
|
||||
for name in ["cajon", "cajon rumba", "cajon folk"]:
|
||||
p = Pattern.preset(name)
|
||||
assert p.beats > 0
|
||||
|
||||
|
||||
# ── Pitch bends ─────────────────────────────────────────────────────────────
|
||||
|
||||
def test_pitch_bend_renders():
|
||||
"""Pitch bend should produce valid audio without errors."""
|
||||
from pytheory import Score, Duration
|
||||
from pytheory.play import render_score
|
||||
score = Score("4/4", bpm=120)
|
||||
p = score.part("t", instrument="electric_guitar")
|
||||
p.add("A4", Duration.HALF, bend=2, bend_type="smooth")
|
||||
p.add("A4", Duration.HALF, bend=-1, bend_type="late")
|
||||
p.add("A4", Duration.HALF, bend=3, bend_type="linear")
|
||||
p.add("A4", Duration.HALF)
|
||||
buf = render_score(score)
|
||||
assert len(buf) > 0
|
||||
|
||||
|
||||
def test_pitch_bend_types():
|
||||
"""All three bend types should work."""
|
||||
from pytheory.rhythm import Note, Duration
|
||||
for bt in ["smooth", "linear", "late"]:
|
||||
n = Note(tone=None, duration=Duration.QUARTER, bend=2, bend_type=bt)
|
||||
assert n.bend_type == bt
|
||||
|
||||
|
||||
# ── Roll method ─────────────────────────────────────────────────────────────
|
||||
|
||||
def test_roll_adds_notes():
|
||||
from pytheory import Score, Duration
|
||||
score = Score("4/4", bpm=120)
|
||||
p = score.part("t", instrument="timpani")
|
||||
p.roll("C3", Duration.WHOLE, velocity_start=30, velocity_end=100)
|
||||
assert len(p.notes) > 4 # should be many 16th notes
|
||||
|
||||
|
||||
def test_roll_velocity_ramp():
|
||||
from pytheory import Score, Duration
|
||||
score = Score("4/4", bpm=120)
|
||||
p = score.part("t", instrument="timpani")
|
||||
p.roll("C3", Duration.WHOLE, velocity_start=20, velocity_end=100)
|
||||
velocities = [n.velocity for n in p.notes]
|
||||
# First should be quieter than last
|
||||
assert velocities[0] < velocities[-1]
|
||||
|
||||
|
||||
def test_roll_custom_speed():
|
||||
from pytheory import Score, Duration
|
||||
score = Score("4/4", bpm=120)
|
||||
p = score.part("t", synth="sine")
|
||||
p.roll("A4", Duration.WHOLE, speed=0.125) # 32nd notes
|
||||
# 4 beats / 0.125 = 32 notes
|
||||
assert len(p.notes) == 32
|
||||
|
||||
|
||||
# ── Int tone names ──────────────────────────────────────────────────────────
|
||||
|
||||
def test_int_tone_name():
|
||||
from pytheory import Tone, TET
|
||||
edo = TET(22)
|
||||
t = Tone(0, octave=4, system=edo)
|
||||
assert t.name == "0"
|
||||
assert t.frequency == pytest.approx(440.0, rel=1e-3)
|
||||
|
||||
|
||||
def test_int_tone_wrapping():
|
||||
from pytheory import Tone, TET
|
||||
edo = TET(22)
|
||||
t = Tone(22, octave=4, system=edo)
|
||||
assert t.name == "0"
|
||||
assert t.octave == 5
|
||||
assert t.frequency == pytest.approx(880.0, rel=1e-3)
|
||||
|
||||
|
||||
def test_int_tone_negative():
|
||||
from pytheory import Tone, TET
|
||||
edo = TET(22)
|
||||
t = Tone(-1, octave=4, system=edo)
|
||||
assert t.name == "21"
|
||||
assert t.octave == 3
|
||||
|
||||
|
||||
def test_system_tone_method():
|
||||
from pytheory import TET
|
||||
edo = TET(19)
|
||||
t = edo.tone(5, octave=4)
|
||||
assert t.name == "5"
|
||||
assert t.octave == 4
|
||||
|
||||
|
||||
# ── B#/Cb octave boundary ──────────────────────────────────────────────────
|
||||
|
||||
def test_b_sharp_octave():
|
||||
t = Tone("B#4")
|
||||
assert t.octave == 5
|
||||
assert t.frequency == pytest.approx(Tone("C5").frequency, rel=1e-3)
|
||||
|
||||
|
||||
def test_c_flat_octave():
|
||||
t = Tone("Cb4")
|
||||
assert t.octave == 3
|
||||
assert t.frequency == pytest.approx(Tone("B3").frequency, rel=1e-3)
|
||||
|
||||
|
||||
# ── Note choking ────────────────────────────────────────────────────────────
|
||||
|
||||
def test_note_choking_renders():
|
||||
"""Fast repeated notes should render without errors (choking active)."""
|
||||
from pytheory import Score, Duration
|
||||
from pytheory.play import render_score
|
||||
score = Score("4/4", bpm=200)
|
||||
p = score.part("t", instrument="piano")
|
||||
for _ in range(32):
|
||||
p.add("C4", Duration.SIXTEENTH)
|
||||
buf = render_score(score)
|
||||
assert len(buf) > 0
|
||||
|
||||
|
||||
# ── Score system/temperament ───────────────────────────────────────────────
|
||||
|
||||
def test_score_temperament():
|
||||
from pytheory import Score
|
||||
score = Score("4/4", bpm=120, temperament="just")
|
||||
assert score.temperament == "just"
|
||||
|
||||
|
||||
def test_score_reference_pitch():
|
||||
from pytheory import Score
|
||||
score = Score("4/4", bpm=120, reference_pitch=415.0)
|
||||
assert score.reference_pitch == 415.0
|
||||
|
||||
|
||||
def test_score_system_propagates():
|
||||
from pytheory import Score, SYSTEMS
|
||||
shruti = SYSTEMS["shruti"]
|
||||
score = Score("4/4", bpm=120, system=shruti)
|
||||
p = score.part("t", synth="sine")
|
||||
assert p._system is shruti
|
||||
|
||||
|
||||
# ── Synth enum count ────────────────────────────────────────────────────────
|
||||
|
||||
def test_synth_enum_count():
|
||||
from pytheory.play import Synth
|
||||
assert len(Synth) == 41
|
||||
|
||||
|
||||
def test_all_synths_render_and_enum_match():
|
||||
"""Every Synth enum member should render valid audio."""
|
||||
from pytheory.play import Synth
|
||||
for s in Synth:
|
||||
wave = s(440, n_samples=1000)
|
||||
assert len(wave) == 1000
|
||||
|
||||
Reference in New Issue
Block a user