Subsystem Search

Patterns that change every cycle

By the end of this chapter, every fourth bar ends in a tom fill, and a pedal hi-hat every three sixteenth notes turns against the beat, and starts a bar with it again only every third bar.

The piece so far

Everything Swing, groove and other transforms built, without its render. This chapter adds two patterns and changes none.

import subsequence
import subsequence.constants.instruments.gm_drums as gm_drums

composition = subsequence.Composition(bpm=120, seed=1)
swing = subsequence.Groove.swing(percent=57)

@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.ghost_fill("snare", density=0.5, velocity=(20, 40), bias="before")
	p.groove(swing)

@composition.pattern(channel=10, beats=4, drum_note_map=gm_drums.GM_DRUM_MAP)
def hats (p):
	p.hit_steps("hi_hat_closed", range(16))
	p.velocity_shape(low=40, high=90)
	p.groove(swing)

@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).rotate(2).groove(swing)

A pattern runs again every cycle

A pattern is not a loop recorded once and played back. It is a function, and Subsequence runs it again before every cycle, fresh. That is why the ghost notes land somewhere new in every bar: p.ghost_fill chooses again each time the function runs.

Each time, p carries what is happening at that moment. Two of the simplest things it knows are p.cycle, how many times this pattern has run before, and p.bar, which bar of the piece is about to play, both counted from 0. This pattern, in a composition of its own called counting, prints them each time it runs:

counting = subsequence.Composition(bpm=120, seed=1)

@counting.pattern(channel=10, beats=4, drum_note_map=gm_drums.GM_DRUM_MAP)
def counter (p):
	print("cycle", p.cycle, "bar", p.bar, "last of four", p.bar_cycle(4).last)
	p.hit_steps("kick", [0])

counting.render(bars=4, filename="counting.mid")
cycle 0 bar 0 last of four False
cycle 3 bar 3 last of four True
cycle 4 bar 4 last of four False

Four bars rendered, and the function ran five times: Subsequence builds each cycle a beat before it plays, so by the end of the fourth bar it had already built the fifth.

A fill every fourth bar

p.bar_cycle(4) says where the bar about to play sits in a cycle of four bars. Its .last is True on the fourth bar of every four, and False on the other three. if runs the lines indented under it only when what follows it is true, so this pattern places a tom fill on the fourth bar of every four, and nothing at all on the rest:

@composition.pattern(channel=10, beats=4, drum_note_map=gm_drums.GM_DRUM_MAP)
def fill (p):
	if p.bar_cycle(4).last:
		p.sequence(steps=[12, 13, 14, 15], pitches=["high_tom", "high_mid_tom", "low_tom", "low_floor_tom"], velocities=[100, 90, 90, 110])
	p.groove(swing)

p.sequence places a note on each step it is given, with the pitch and velocity in the same place in their own lists: the high tom on step 12, the high mid tom on step 13, and so on down to the low floor tom on the last sixteenth note of the bar. .first is True on the first bar of every four.

p.every is a shorter way to do something every so many cycles, and it counts the pattern's cycles rather than bars: in a pattern two bars long, p.every(4, ...) acts every eight bars.

A line three sixteenth notes long

A pattern does not have to be a bar long. This one is three sixteenth notes long, and plays a pedal hi-hat at its start:

@composition.pattern(channel=10, beats=0.75, reschedule_lookahead=0.75, drum_note_map=gm_drums.GM_DRUM_MAP)
def pedal_hats (p):
	p.hit_steps("hi_hat_pedal", [0], velocity=80)

composition.render(bars=4, filename="patterns-that-change.mid")

In piece.py, add fill and pedal_hats below the other patterns.

Its hits fall three sixteenth notes apart and cross the beat, meeting it on every third beat:

    1  1.000  note G#2 (44)  velocity 80  length 0.083
    1  1.750  note G#2 (44)  velocity 80  length 0.083
    1  2.500  note G#2 (44)  velocity 80  length 0.083
    1  3.250  note G#2 (44)  velocity 80  length 0.083
    1  4.000  note G#2 (44)  velocity 80  length 0.083

Sixteen hits later, three bars on, they start the bar together with the kick again. The fourth bar ends in the fill:

    4  1.000  note G#2 (44)  velocity 80  length 0.083
    4  4.000  note D3 (50)  velocity 100  length 0.083
    4  4.292  note C3 (48)  velocity 90  length 0.083
    4  4.500  note A2 (45)  velocity 90  length 0.083
    4  4.792  note F2 (41)  velocity 110  length 0.083