mirror of
https://github.com/kennethreitz/pytheory.git
synced 2026-06-05 23:00:20 +00:00
Compare commits
5 Commits
v0.29.0
...
drums-as-part
| Author | SHA1 | Date | |
|---|---|---|---|
| f7c05e1b31 | |||
| c375785bb9 | |||
| 9ebd54b7fc | |||
| ce68ad8f19 | |||
| f402e76480 |
@@ -2,6 +2,16 @@
|
||||
|
||||
All notable changes to PyTheory are documented here.
|
||||
|
||||
## 0.29.2
|
||||
|
||||
- Add `score.set_drum_effects()` — reverb, delay, lowpass, distortion, chorus on the drum bus
|
||||
- Same effects engine as parts, zero code duplication
|
||||
|
||||
## 0.29.1
|
||||
|
||||
- Rename song.py → songs.py
|
||||
- Polish all 20 example songs with stereo, convolution reverb, humanize, detune, sidechain
|
||||
|
||||
## 0.29.0
|
||||
|
||||
- Add `Score.from_midi(path)` — import any Standard MIDI File into a Score
|
||||
|
||||
@@ -46,12 +46,17 @@ def bossa_nova_girl():
|
||||
score.drums("bossa nova", repeats=4)
|
||||
|
||||
rhodes = score.part("rhodes", synth="fm", envelope="piano",
|
||||
volume=0.3, reverb=0.4, reverb_decay=1.8)
|
||||
volume=0.3, pan=-0.3,
|
||||
reverb=0.4, reverb_decay=1.8, reverb_type="plate",
|
||||
detune=8, humanize=0.2)
|
||||
lead = score.part("lead", synth="triangle", envelope="pluck",
|
||||
volume=0.45, delay=0.25, delay_time=0.32,
|
||||
delay_feedback=0.35, reverb=0.2)
|
||||
volume=0.45, pan=0.3,
|
||||
delay=0.25, delay_time=0.32, delay_feedback=0.35,
|
||||
reverb=0.2, reverb_type="plate",
|
||||
humanize=0.2)
|
||||
bass = score.part("bass", synth="sine", envelope="pluck",
|
||||
volume=0.45, lowpass=600)
|
||||
volume=0.45, pan=0.0, lowpass=600,
|
||||
humanize=0.15)
|
||||
|
||||
for sym in ["Am", "Am", "Dm", "Dm", "E7", "E7", "Am", "Am"]:
|
||||
rhodes.add(Chord.from_symbol(sym), Duration.WHOLE)
|
||||
@@ -86,11 +91,18 @@ def bebop_in_bb():
|
||||
score.drums("bebop", repeats=8, fill="jazz", fill_every=8)
|
||||
|
||||
rhodes = score.part("rhodes", synth="fm", envelope="piano",
|
||||
volume=0.25, reverb=0.35, reverb_decay=1.2)
|
||||
volume=0.25, pan=-0.3,
|
||||
reverb=0.35, reverb_decay=1.2, reverb_type="plate",
|
||||
detune=8, humanize=0.2)
|
||||
lead = score.part("lead", synth="saw", envelope="pluck",
|
||||
volume=0.4, lowpass=4000, lowpass_q=1.1)
|
||||
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",
|
||||
humanize=0.2)
|
||||
bass = score.part("bass", synth="triangle", envelope="pluck",
|
||||
volume=0.4, lowpass=900)
|
||||
volume=0.4, pan=0.0, lowpass=500,
|
||||
humanize=0.15)
|
||||
|
||||
for sym in ["Bb", "Gm", "Cm", "F7"] * 2:
|
||||
rhodes.add(Chord.from_symbol(sym), Duration.WHOLE)
|
||||
@@ -133,12 +145,17 @@ def salsa_descarga():
|
||||
score.drums("salsa", repeats=8, fill="salsa", fill_every=4)
|
||||
|
||||
pads = score.part("pads", synth="pwm_slow", envelope="pad",
|
||||
volume=0.2, reverb=0.3, lowpass=2000)
|
||||
volume=0.2, pan=-0.35,
|
||||
reverb=0.3, reverb_type="plate", lowpass=2000,
|
||||
detune=10, humanize=0.2)
|
||||
lead = score.part("lead", synth="saw", envelope="pluck",
|
||||
volume=0.4, delay=0.2, delay_time=0.167,
|
||||
delay_feedback=0.3)
|
||||
volume=0.4, pan=0.3,
|
||||
delay=0.2, delay_time=0.167, delay_feedback=0.3,
|
||||
reverb=0.15, reverb_type="plate",
|
||||
humanize=0.2)
|
||||
bass = score.part("bass", synth="pulse", envelope="pluck",
|
||||
volume=0.45, lowpass=500, lowpass_q=1.3)
|
||||
volume=0.45, pan=0.0, lowpass=500, lowpass_q=1.3,
|
||||
humanize=0.15)
|
||||
|
||||
for sym in ["Em7b5", "A7", "Dm7", "Bbmaj7"] * 2:
|
||||
pads.add(Chord.from_symbol(sym), Duration.WHOLE)
|
||||
@@ -175,12 +192,19 @@ def afrobeat_groove():
|
||||
score.drums("afrobeat", repeats=8, fill="afrobeat", fill_every=8)
|
||||
|
||||
pads = score.part("pads", synth="supersaw", envelope="pad",
|
||||
volume=0.2, reverb=0.4, reverb_decay=2.0,
|
||||
lowpass=3000)
|
||||
volume=0.2, pan=-0.3,
|
||||
reverb=0.4, reverb_decay=2.0, reverb_type="cathedral",
|
||||
lowpass=3000, detune=10, spread=0.6,
|
||||
humanize=0.2)
|
||||
lead = score.part("lead", synth="saw", envelope="pluck",
|
||||
volume=0.4, lowpass=3000, lowpass_q=1.0)
|
||||
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",
|
||||
humanize=0.2)
|
||||
bass = score.part("bass", synth="sine", envelope="pluck",
|
||||
volume=0.5, lowpass=500)
|
||||
volume=0.5, pan=0.0, lowpass=500,
|
||||
humanize=0.15)
|
||||
|
||||
for sym in ["Em", "Am", "D", "C"] * 2:
|
||||
pads.add(Chord.from_symbol(sym), Duration.WHOLE)
|
||||
@@ -213,13 +237,18 @@ def reggae_one_drop():
|
||||
score.drums("reggae", repeats=8, fill="reggae", fill_every=8)
|
||||
|
||||
chords = score.part("chords", synth="square", envelope="staccato",
|
||||
volume=0.2, reverb=0.5, reverb_decay=2.0,
|
||||
lowpass=2000)
|
||||
volume=0.2, pan=-0.4,
|
||||
reverb=0.5, reverb_decay=2.0, reverb_type="cathedral",
|
||||
lowpass=2000, detune=8,
|
||||
humanize=0.2)
|
||||
lead = score.part("lead", synth="triangle", envelope="strings",
|
||||
volume=0.4, delay=0.35, delay_time=0.5625,
|
||||
delay_feedback=0.45, reverb=0.3)
|
||||
volume=0.4, pan=0.3,
|
||||
delay=0.35, delay_time=0.5625, delay_feedback=0.45,
|
||||
reverb=0.3, reverb_type="cathedral",
|
||||
humanize=0.2)
|
||||
bass = score.part("bass", synth="sine", envelope="pluck",
|
||||
volume=0.55, lowpass=400, lowpass_q=1.3)
|
||||
volume=0.55, pan=0.0, lowpass=400, lowpass_q=1.3,
|
||||
humanize=0.15)
|
||||
|
||||
for sym in ["G", "C", "D", "C"] * 2:
|
||||
chords.add(Chord.from_symbol(sym), Duration.WHOLE)
|
||||
@@ -254,12 +283,18 @@ def funk_workout():
|
||||
score.drums("funk", repeats=8, fill="funk", fill_every=4)
|
||||
|
||||
chords = score.part("chords", synth="square", envelope="staccato",
|
||||
volume=0.25, lowpass=2500, reverb=0.15)
|
||||
volume=0.25, pan=-0.4,
|
||||
lowpass=2500, reverb=0.15, reverb_type="plate",
|
||||
sidechain=0.4, humanize=0.2)
|
||||
lead = score.part("lead", synth="saw", envelope="pluck",
|
||||
volume=0.4, lowpass=3500, lowpass_q=1.5,
|
||||
delay=0.15, delay_time=0.15, delay_feedback=0.25)
|
||||
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",
|
||||
humanize=0.2)
|
||||
bass = score.part("bass", synth="pulse", envelope="pluck",
|
||||
volume=0.5, lowpass=600, lowpass_q=1.2)
|
||||
volume=0.5, pan=0.0, lowpass=600, lowpass_q=1.2,
|
||||
humanize=0.15)
|
||||
|
||||
for sym in ["Em", "Am", "D", "B7"] * 2:
|
||||
chords.add(Chord.from_symbol(sym), Duration.WHOLE)
|
||||
@@ -298,13 +333,17 @@ def blues_shuffle():
|
||||
score.drums("12/8 blues", repeats=6)
|
||||
|
||||
chords = score.part("chords", synth="fm", envelope="piano",
|
||||
volume=0.3, reverb=0.3, reverb_decay=1.5)
|
||||
volume=0.3, pan=-0.3,
|
||||
reverb=0.3, reverb_decay=1.5, reverb_type="plate",
|
||||
detune=8, humanize=0.2)
|
||||
lead = score.part("lead", synth="saw", envelope="pluck",
|
||||
volume=0.45, reverb=0.3, reverb_decay=1.2,
|
||||
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", synth="sine", envelope="pluck",
|
||||
volume=0.5, lowpass=500)
|
||||
volume=0.5, pan=0.0, lowpass=500,
|
||||
humanize=0.15)
|
||||
|
||||
for sym in ["A", "A", "D", "D", "E7", "A"]:
|
||||
chords.add(Chord.from_symbol(sym), Duration.DOTTED_HALF)
|
||||
@@ -343,13 +382,18 @@ def samba_de_janeiro():
|
||||
score.drums("samba", repeats=8, fill="samba", fill_every=8)
|
||||
|
||||
pads = score.part("pads", synth="supersaw", envelope="pad",
|
||||
volume=0.2, reverb=0.45, reverb_decay=2.0,
|
||||
lowpass=4000)
|
||||
volume=0.2, pan=-0.3,
|
||||
reverb=0.45, reverb_decay=2.0, reverb_type="plate",
|
||||
lowpass=4000, detune=10, spread=0.5,
|
||||
humanize=0.2)
|
||||
lead = score.part("lead", synth="triangle", envelope="pluck",
|
||||
volume=0.45, delay=0.2, delay_time=0.176,
|
||||
delay_feedback=0.3)
|
||||
volume=0.45, pan=0.3,
|
||||
delay=0.2, delay_time=0.176, delay_feedback=0.3,
|
||||
reverb=0.15, reverb_type="plate",
|
||||
humanize=0.2)
|
||||
bass = score.part("bass", synth="sine", envelope="pluck",
|
||||
volume=0.45, lowpass=700)
|
||||
volume=0.45, pan=0.0, lowpass=500,
|
||||
humanize=0.15)
|
||||
|
||||
for sym in ["G", "Em", "Am", "D7"] * 2:
|
||||
pads.add(Chord.from_symbol(sym), Duration.WHOLE)
|
||||
@@ -383,12 +427,17 @@ def jazz_waltz():
|
||||
score.drums("waltz", repeats=16)
|
||||
|
||||
rhodes = score.part("rhodes", synth="fm", envelope="piano",
|
||||
volume=0.3, reverb=0.4, reverb_decay=2.0)
|
||||
volume=0.3, pan=-0.3,
|
||||
reverb=0.4, reverb_decay=2.0, reverb_type="cathedral",
|
||||
detune=8, humanize=0.2)
|
||||
lead = score.part("lead", synth="triangle", envelope="strings",
|
||||
volume=0.4, reverb=0.3, reverb_decay=1.5,
|
||||
delay=0.2, delay_time=0.4, delay_feedback=0.3)
|
||||
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,
|
||||
humanize=0.2)
|
||||
bass = score.part("bass", synth="sine", envelope="pluck",
|
||||
volume=0.4, lowpass=600)
|
||||
volume=0.4, pan=0.0, lowpass=500,
|
||||
humanize=0.15)
|
||||
|
||||
for _ in range(2):
|
||||
for sym in ["Fmaj7", "Gm", "C7", "Fmaj7"]:
|
||||
@@ -423,14 +472,19 @@ def house_anthem():
|
||||
score.drums("house", repeats=8, fill="house", fill_every=8)
|
||||
|
||||
pads = score.part("pads", synth="supersaw", envelope="pad",
|
||||
volume=0.25, reverb=0.5, reverb_decay=2.5,
|
||||
lowpass=5000)
|
||||
volume=0.25, pan=-0.3,
|
||||
reverb=0.5, reverb_decay=2.5, reverb_type="cathedral",
|
||||
lowpass=5000, detune=12, spread=0.7,
|
||||
sidechain=0.6, humanize=0.2)
|
||||
lead = score.part("lead", synth="saw", envelope="staccato",
|
||||
volume=0.35, lowpass=2000, lowpass_q=2.0,
|
||||
delay=0.2, delay_time=0.242,
|
||||
delay_feedback=0.35)
|
||||
volume=0.35, pan=0.3,
|
||||
lowpass=2000, lowpass_q=2.0,
|
||||
delay=0.2, delay_time=0.242, delay_feedback=0.35,
|
||||
reverb=0.15, reverb_type="plate",
|
||||
humanize=0.2)
|
||||
bass = score.part("bass", synth="sine", envelope="pluck",
|
||||
volume=0.55, lowpass=300)
|
||||
volume=0.55, pan=0.0, lowpass=300,
|
||||
sidechain=0.5, humanize=0.15)
|
||||
|
||||
for sym in ["Cm", "Ab", "Bb", "Cm"] * 2:
|
||||
pads.add(Chord.from_symbol(sym), Duration.WHOLE)
|
||||
@@ -480,16 +534,22 @@ def dub_kingston():
|
||||
score.drums("dub", repeats=8)
|
||||
|
||||
chords = score.part("chords", synth="square", envelope="staccato",
|
||||
volume=0.2, reverb=0.6, reverb_decay=2.5,
|
||||
lowpass=1500, lowpass_q=0.9)
|
||||
volume=0.2, pan=-0.4,
|
||||
reverb=0.6, reverb_decay=2.5, reverb_type="cathedral",
|
||||
lowpass=1500, lowpass_q=0.9, detune=8,
|
||||
humanize=0.2)
|
||||
lead = score.part("lead", synth="triangle", envelope="strings",
|
||||
volume=0.4, delay=0.45, delay_time=0.625,
|
||||
delay_feedback=0.5, reverb=0.35, reverb_decay=2.0)
|
||||
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",
|
||||
humanize=0.2)
|
||||
bass = score.part("bass", synth="sine", envelope="pluck",
|
||||
volume=0.6, lowpass=400, lowpass_q=1.5)
|
||||
volume=0.6, pan=0.0, lowpass=400, lowpass_q=1.5,
|
||||
humanize=0.15)
|
||||
siren = score.part("siren", synth="pwm_slow", envelope="pad",
|
||||
volume=0.15, reverb=0.7, reverb_decay=3.0,
|
||||
lowpass=1200)
|
||||
volume=0.15, pan=0.5,
|
||||
reverb=0.7, reverb_decay=3.0, reverb_type="cathedral",
|
||||
lowpass=1200, detune=10)
|
||||
|
||||
for sym in ["Am", "Am", "Dm", "Dm", "Am", "Am", "Em", "Am"]:
|
||||
chords.add(Chord.from_symbol(sym), Duration.WHOLE)
|
||||
@@ -526,14 +586,19 @@ def techno_minimal():
|
||||
score.drums("techno", repeats=8, fill="house", fill_every=8)
|
||||
|
||||
pad = score.part("pad", synth="supersaw", envelope="pad",
|
||||
volume=0.2, reverb=0.5, reverb_decay=3.0,
|
||||
lowpass=3000)
|
||||
volume=0.2, pan=-0.3,
|
||||
reverb=0.5, reverb_decay=3.0, reverb_type="cathedral",
|
||||
lowpass=3000, detune=12, spread=0.7,
|
||||
sidechain=0.6, humanize=0.2)
|
||||
lead = score.part("lead", synth="pwm_fast", envelope="staccato",
|
||||
volume=0.35, lowpass=1500, lowpass_q=3.0,
|
||||
delay=0.3, delay_time=0.231,
|
||||
delay_feedback=0.4)
|
||||
volume=0.35, pan=0.3,
|
||||
lowpass=1500, lowpass_q=3.0,
|
||||
delay=0.3, delay_time=0.231, delay_feedback=0.4,
|
||||
reverb=0.1, reverb_type="plate",
|
||||
humanize=0.2)
|
||||
bass = score.part("bass", synth="sine", envelope="pluck",
|
||||
volume=0.55, lowpass=250)
|
||||
volume=0.55, pan=0.0, lowpass=250,
|
||||
sidechain=0.5, humanize=0.15)
|
||||
|
||||
for sym in ["Fm", "Db", "Eb", "Fm"] * 2:
|
||||
pad.add(Chord.from_symbol(sym), Duration.WHOLE)
|
||||
@@ -560,12 +625,17 @@ def gospel_shuffle():
|
||||
score.drums("gospel", repeats=8, fill="buildup", fill_every=8)
|
||||
|
||||
organ = score.part("organ", synth="fm", envelope="organ",
|
||||
volume=0.3, reverb=0.45, reverb_decay=2.0)
|
||||
volume=0.3, pan=-0.3,
|
||||
reverb=0.45, reverb_decay=2.0, reverb_type="cathedral",
|
||||
detune=8, humanize=0.2)
|
||||
lead = score.part("lead", synth="triangle", envelope="pluck",
|
||||
volume=0.4, delay=0.2, delay_time=0.278,
|
||||
delay_feedback=0.3, reverb=0.2)
|
||||
volume=0.4, pan=0.3,
|
||||
delay=0.2, delay_time=0.278, delay_feedback=0.3,
|
||||
reverb=0.2, reverb_type="plate",
|
||||
humanize=0.2)
|
||||
bass = score.part("bass", synth="sine", envelope="pluck",
|
||||
volume=0.45, lowpass=500)
|
||||
volume=0.45, pan=0.0, lowpass=500,
|
||||
humanize=0.15)
|
||||
|
||||
for sym in ["C", "Am", "F", "G"] * 2:
|
||||
organ.add(Chord.from_symbol(sym), Duration.WHOLE)
|
||||
@@ -618,18 +688,23 @@ def dub_delay_madness():
|
||||
score._drum_hits.append(_Hit(DrumSound.RIMSHOT, offset + 3.5, 60))
|
||||
|
||||
chords = score.part("skank", synth="square", envelope="staccato",
|
||||
volume=0.15, reverb=0.7, reverb_decay=3.0,
|
||||
lowpass=1200)
|
||||
volume=0.15, pan=-0.4,
|
||||
reverb=0.7, reverb_decay=3.0, reverb_type="cathedral",
|
||||
lowpass=1200, detune=8, humanize=0.2)
|
||||
bass = score.part("bass", synth="sine", envelope="pluck",
|
||||
volume=0.6, lowpass=350, lowpass_q=1.5)
|
||||
volume=0.6, pan=0.0, lowpass=350, lowpass_q=1.5,
|
||||
humanize=0.15)
|
||||
siren = score.part("siren", synth="pwm_slow", envelope="pad",
|
||||
volume=0.12, reverb=0.8, reverb_decay=4.0,
|
||||
volume=0.12, pan=0.5,
|
||||
reverb=0.8, reverb_decay=4.0, reverb_type="cathedral",
|
||||
delay=0.4, delay_time=0.88, delay_feedback=0.6,
|
||||
lowpass=900)
|
||||
lowpass=900, detune=10)
|
||||
# Melodica stabs — sparse, lots of delay
|
||||
melodica = score.part("melodica", synth="triangle", envelope="pluck",
|
||||
volume=0.35, delay=0.6, delay_time=0.66,
|
||||
delay_feedback=0.55, reverb=0.5, reverb_decay=2.5)
|
||||
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",
|
||||
humanize=0.2)
|
||||
|
||||
for sym in ["Em", "Em", "Am", "Am", "Em", "Em", "Bm", "Em"]:
|
||||
chords.add(Chord.from_symbol(sym), Duration.WHOLE)
|
||||
@@ -667,13 +742,18 @@ def drum_and_bass():
|
||||
score.drums("drum and bass", repeats=8, fill="buildup", fill_every=8)
|
||||
|
||||
pads = score.part("pads", synth="supersaw", envelope="pad",
|
||||
volume=0.25, reverb=0.5, reverb_decay=2.5,
|
||||
lowpass=4000)
|
||||
volume=0.25, pan=-0.3,
|
||||
reverb=0.5, reverb_decay=2.5, reverb_type="plate",
|
||||
lowpass=4000, detune=10, spread=0.6,
|
||||
humanize=0.2)
|
||||
lead = score.part("lead", synth="triangle", envelope="strings",
|
||||
volume=0.4, delay=0.3, delay_time=0.172,
|
||||
delay_feedback=0.4, reverb=0.25)
|
||||
volume=0.4, pan=0.3,
|
||||
delay=0.3, delay_time=0.172, delay_feedback=0.4,
|
||||
reverb=0.25, reverb_type="plate",
|
||||
humanize=0.2)
|
||||
bass = score.part("bass", synth="sine", envelope="pluck",
|
||||
volume=0.55, lowpass=300)
|
||||
volume=0.55, pan=0.0, lowpass=300,
|
||||
humanize=0.15)
|
||||
|
||||
for sym in ["Am", "F", "C", "G"] * 2:
|
||||
pads.add(Chord.from_symbol(sym), Duration.WHOLE)
|
||||
@@ -708,18 +788,24 @@ def drake_vibes():
|
||||
score.drums("trap", repeats=8, fill="trap", fill_every=8)
|
||||
|
||||
pads = score.part("pads", synth="supersaw", envelope="pad",
|
||||
volume=0.2, reverb=0.5, reverb_decay=3.0,
|
||||
lowpass=2500)
|
||||
volume=0.2, pan=-0.25,
|
||||
reverb=0.5, reverb_decay=3.0, reverb_type="cathedral",
|
||||
lowpass=2500, detune=12, spread=0.6,
|
||||
sidechain=0.4, humanize=0.2)
|
||||
bells = score.part("bells", synth="fm", envelope="bell",
|
||||
volume=0.3, reverb=0.4, reverb_decay=2.0,
|
||||
delay=0.25, delay_time=0.44,
|
||||
delay_feedback=0.35)
|
||||
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,
|
||||
humanize=0.2)
|
||||
lead = score.part("lead", synth="pwm_slow", envelope="strings",
|
||||
volume=0.35, reverb=0.3, lowpass=2000,
|
||||
delay=0.2, delay_time=0.88, delay_feedback=0.3)
|
||||
volume=0.35, pan=-0.2,
|
||||
reverb=0.3, reverb_type="cathedral", lowpass=2000,
|
||||
delay=0.2, delay_time=0.88, delay_feedback=0.3,
|
||||
humanize=0.2)
|
||||
bass = score.part("bass", synth="sine", envelope="pluck",
|
||||
volume=0.6, lowpass=200, lowpass_q=1.8,
|
||||
distortion=0.4, distortion_drive=2.0)
|
||||
volume=0.6, pan=0.0, lowpass=200, lowpass_q=1.8,
|
||||
distortion=0.4, distortion_drive=2.0,
|
||||
sidechain=0.3, humanize=0.15)
|
||||
|
||||
for sym in ["Ebm", "B", "Gb", "Db"] * 2:
|
||||
pads.add(Chord.from_symbol(sym), Duration.WHOLE)
|
||||
+13
-1
@@ -1836,6 +1836,8 @@ def render_score(score):
|
||||
# Named parts — each rendered to own buffer for per-part effects
|
||||
_pending_sidechain = []
|
||||
for part in score.parts.values():
|
||||
if part.is_drums:
|
||||
continue # drums are rendered separately via _drum_hits
|
||||
if part.notes:
|
||||
part_buf = numpy.zeros(total_samples, dtype=numpy.float32)
|
||||
synth_fn = _resolve_synth(part.synth)
|
||||
@@ -1989,6 +1991,16 @@ def render_score(score):
|
||||
panned = _pan_to_stereo(mono_hit, pan)
|
||||
drum_stereo[start:start + hit_len] += panned
|
||||
|
||||
# Apply drum Part effects through the same pipeline as any other Part
|
||||
drums_part = score.parts.get("drums")
|
||||
if drums_part:
|
||||
has_drum_fx = (drums_part.lowpass > 0 or drums_part.delay_mix > 0
|
||||
or drums_part.reverb_mix > 0 or drums_part.distortion_mix > 0
|
||||
or drums_part.chorus_mix > 0)
|
||||
if has_drum_fx:
|
||||
for ch in range(2):
|
||||
drum_stereo[:, ch] = _apply_part_effects(drum_stereo[:, ch], drums_part)
|
||||
|
||||
# Apply sidechain compression to parts that request it
|
||||
for part, part_buf in _pending_sidechain:
|
||||
part_buf = _apply_sidechain(
|
||||
@@ -2001,7 +2013,7 @@ def render_score(score):
|
||||
if score.notes:
|
||||
stereo_buf += _pan_to_stereo(buf, 0.0)
|
||||
|
||||
# Drums: stereo panned
|
||||
# Drums: stereo panned (with effects already applied)
|
||||
stereo_buf += drum_stereo
|
||||
|
||||
# Master bus compressor/limiter (per channel)
|
||||
|
||||
+67
-4
@@ -1399,6 +1399,8 @@ class Part:
|
||||
self.pan = pan
|
||||
self.spread = spread
|
||||
self.notes: list[Note] = []
|
||||
self._drum_hits: list[_Hit] = []
|
||||
self._drum_pattern_beats: float = 0.0
|
||||
self._automation: list[tuple[float, dict]] = [] # (beat, {param: value})
|
||||
|
||||
def add(self, tone_or_string, duration=Duration.QUARTER, *, velocity: int = 100) -> "Part":
|
||||
@@ -1690,12 +1692,21 @@ class Part:
|
||||
|
||||
return self
|
||||
|
||||
@property
|
||||
def is_drums(self) -> bool:
|
||||
"""True if this part contains drum hits."""
|
||||
return len(self._drum_hits) > 0
|
||||
|
||||
@property
|
||||
def total_beats(self) -> float:
|
||||
return sum(n.beats for n in self.notes)
|
||||
note_beats = sum(n.beats for n in self.notes)
|
||||
if self._drum_hits:
|
||||
drum_beats = self._drum_pattern_beats
|
||||
return max(note_beats, drum_beats)
|
||||
return note_beats
|
||||
|
||||
def __len__(self):
|
||||
return len(self.notes)
|
||||
return len(self.notes) + len(self._drum_hits)
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self.notes)
|
||||
@@ -1786,12 +1797,63 @@ class Score:
|
||||
self._drum_humanize = drum_humanize
|
||||
self.notes: list[Note] = []
|
||||
self.parts: dict[str, Part] = {}
|
||||
self._drum_hits: list[_Hit] = []
|
||||
self._drum_pattern_beats: float = 0.0
|
||||
self._tempo_changes: list[tuple[float, int]] = []
|
||||
self._sections: dict[str, Section] = {}
|
||||
self._current_section: Optional[Section] = None
|
||||
|
||||
def _ensure_drums_part(self) -> Part:
|
||||
"""Get or create the drums Part."""
|
||||
if "drums" not in self.parts:
|
||||
self.parts["drums"] = Part("drums", synth="sine", volume=0.7)
|
||||
return self.parts["drums"]
|
||||
|
||||
@property
|
||||
def _drum_hits(self) -> list:
|
||||
"""Proxy: drum hits live on the drums Part."""
|
||||
return self._ensure_drums_part()._drum_hits
|
||||
|
||||
@property
|
||||
def _drum_pattern_beats(self) -> float:
|
||||
"""Proxy: drum pattern beats live on the drums Part."""
|
||||
return self._ensure_drums_part()._drum_pattern_beats
|
||||
|
||||
@_drum_pattern_beats.setter
|
||||
def _drum_pattern_beats(self, value: float):
|
||||
self._ensure_drums_part()._drum_pattern_beats = value
|
||||
|
||||
@property
|
||||
def drum_effects(self) -> dict:
|
||||
"""Proxy: drum effects are just the drums Part's effect settings."""
|
||||
p = self._ensure_drums_part()
|
||||
return {
|
||||
"reverb_mix": p.reverb_mix, "reverb_decay": p.reverb_decay,
|
||||
"reverb_type": p.reverb_type,
|
||||
"delay_mix": p.delay_mix, "delay_time": p.delay_time,
|
||||
"delay_feedback": p.delay_feedback,
|
||||
"lowpass": p.lowpass, "lowpass_q": p.lowpass_q,
|
||||
"distortion_mix": p.distortion_mix,
|
||||
"distortion_drive": p.distortion_drive,
|
||||
"chorus_mix": p.chorus_mix,
|
||||
}
|
||||
|
||||
def set_drum_effects(self, **kwargs) -> "Score":
|
||||
"""Set effects on the drum bus.
|
||||
|
||||
The drums Part is a real Part — set effects the same way
|
||||
you would on any other part.
|
||||
|
||||
Example::
|
||||
|
||||
score.set_drum_effects(reverb=0.2, reverb_type="plate")
|
||||
"""
|
||||
p = self._ensure_drums_part()
|
||||
param_map = {"reverb": "reverb_mix", "delay": "delay_mix",
|
||||
"distortion": "distortion_mix", "chorus": "chorus_mix"}
|
||||
for k, v in kwargs.items():
|
||||
attr = param_map.get(k, k)
|
||||
setattr(p, attr, v)
|
||||
return self
|
||||
|
||||
def part(self, name: str, *, synth: str = "sine",
|
||||
envelope: str = "piano", volume: float = 0.5,
|
||||
reverb: float = 0.0, reverb_decay: float = 1.0,
|
||||
@@ -1904,6 +1966,7 @@ class Score:
|
||||
fill_pattern = Pattern.fill(name)
|
||||
return self.add_pattern(fill_pattern, repeats=1)
|
||||
|
||||
|
||||
def drums(self, preset: str, repeats: int = 4, fill: str = None,
|
||||
fill_every: int = None) -> "Score":
|
||||
"""Add a drum pattern by preset name, with optional auto-fills.
|
||||
|
||||
Reference in New Issue
Block a user