A Euclidean snare
By the end of this chapter, a second snare plays five quiet hits spread as evenly as they will go across every bar, turned so that they pull against the beat.
The piece so far
Everything Ghost fills built, without its render. This chapter adds a pattern and changes none.
import subsequence
import subsequence.constants.instruments.gm_drums as gm_drums
composition = subsequence.Composition(bpm=120, seed=1)
@composition.pattern(channel=10, beats=4, drum_note_map=gm_drums.GM_DRUM_MAP)
def drums (p):
p.hit_steps("kick", [0, 4, 8, 12], velocity=110)
p.hit_steps("snare", [4, 12], velocity=100)
p.hit_steps("hi_hat_closed", range(16), velocity=70)
p.ghost_fill("snare", density=0.5, velocity=(20, 40), bias="before")
A generator
So far the drum pattern has said exactly which steps to play, and p.ghost_fill has chosen steps at random. A generator works the steps out for itself, from a rule and a few numbers. p.euclidean is one of the simplest: give it a number of hits, which it calls pulses, and it spreads them as evenly as they will go across the pattern's steps.
The rhythms it makes are old. Godfried Toussaint showed in a 2005 paper, The Euclidean Algorithm Generates Traditional Musical Rhythms, that spreading pulses this way produces rhythms heard in music around the world: three pulses over eight steps, x..x..x., is the Cuban tresillo.
Here are five pulses over a bar of sixteen steps, in a composition of its own, called on_its_own, so they can be heard alone:
on_its_own = subsequence.Composition(bpm=120, seed=1)
@on_its_own.pattern(channel=10, beats=4, drum_note_map=gm_drums.GM_DRUM_MAP)
def euclidean_snare (p):
p.euclidean("snare_2", pulses=5, velocity=60)
on_its_own.render(bars=1, filename="five-pulses.mid")
"snare_2" is the second snare General MIDI names, an electric snare, note 40, so it sounds apart from the snare on the backbeat. The five hits land three steps apart, with one step more before the bar comes round:
1 1.000 note E2 (40) velocity 60 length 0.083
1 1.750 note E2 (40) velocity 60 length 0.083
1 2.500 note E2 (40) velocity 60 length 0.083
1 3.250 note E2 (40) velocity 60 length 0.083
1 4.000 note E2 (40) velocity 60 length 0.083
Turning it against the beat
Two of those hits double what the piece already plays: the first lands with the kick on the first beat, and the last with the snare on the fourth. p.rotate moves every note of a pattern along by a number of steps, and a note pushed past the end of the bar comes round to its start. Two steps later, none of the hits meets the snare, and only one meets the kick. Add the pattern to the piece, rotated:
@composition.pattern(channel=10, beats=4, drum_note_map=gm_drums.GM_DRUM_MAP)
def euclidean_snare (p):
p.euclidean("snare_2", pulses=5, velocity=60)
p.rotate(2)
composition.render(bars=2, filename="a-euclidean-snare.mid")
In piece.py, add this pattern below drums. Rotating it moves only its own notes, which is why it is a pattern of its own rather than two more lines in drums. Its hits now fall here in every bar, one of them with the kick on the third beat:
1 1.500 note E2 (40) velocity 60 length 0.083
1 2.250 note E2 (40) velocity 60 length 0.083
1 3.000 note E2 (40) velocity 60 length 0.083
1 3.750 note E2 (40) velocity 60 length 0.083
1 4.500 note E2 (40) velocity 60 length 0.083
Try other numbers of pulses and other rotations. Five hits spread evenly cannot fall once a beat in a bar of four, so however they are turned, most of them land off the beat and pull against the kick.
Every generator
Subsequence can list its generators itself. subsequence.generators returns a description of each, and this prints their names:
for generator in subsequence.generators():
print(generator["name"])
for runs the indented line once for each item in a list, calling the item generator each time. Each description holds a generator's name, a one-line summary and its parameters, and generator["name"] picks out the name. The list takes in the methods that place notes where you say, such as p.note and p.hit_steps, as well as the generators that decide for themselves:
bresenham
cellular_1d
euclidean
ghost_fill
golden
reaction_diffusion
thue_morse
Other rhythm generators
Each has its entry in the reference:
p.bresenhamspreads pulses evenly by a different rule, which often places them a little differently.p.cellular_1dgrows a rhythm from a cellular automaton, which changes a little every bar.p.reaction_diffusiontakes its rhythm from a simulation of two chemicals spreading and reacting.p.thue_morseplaces notes by the Thue-Morse sequence, which never settles into a repeating figure within a bar.p.goldenplaces notes at positions spaced by the golden ratio.