Subsystem Search

Motifs and phrases

By the end of this chapter, a hook you wrote, eight notes long, plays above the melody as a question and its answer: once ending open, on the fifth note of the scale, then again ending at home, on the first.

The piece so far

Everything A melody that remembers built, without its render. This chapter adds a pattern and changes none.

import subsequence
import subsequence.constants.instruments.gm_drums as gm_drums
import subsequence.constants.midi_notes as notes

composition = subsequence.Composition(bpm=120, key="E", scale="minor", 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)

@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)

@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.harmony(style="aeolian_minor")

@composition.pattern(channel=3, beats=4, voice_leading=True)
def pad (p, chord):
	p.chord(chord, root=notes.E3, sustain=True, velocity=70)

@composition.pattern(channel=2, beats=4)
def bass (p, chord):
	p.arpeggio(chord, root=notes.E1, count=4, spacing=0.25)
	p.groove(swing)

melody_state = subsequence.MelodicState(low=notes.E4, high=notes.E5, rest_probability=0.2)

@composition.pattern(channel=4, beats=4)
def melody (p, chord):
	p.melody(melody_state, spacing=0.5, chord_tones=chord.tones(notes.E4))

A motif, in scale degrees

A generated melody is one way to write a line. The other is to write it yourself. subsequence.motif takes a melody as scale degrees, the notes of the scale counted from 1:

hook = subsequence.motif([5, 6, 5, 3, None, 1, 2, 3])

hook is a Motif: a value, like the groove, that plays nothing by itself. A pattern places it with p.motif, and it can be changed, transposed or joined to another motif as a value first.

A question and its answer

Classical composers built phrases from ideas like this in a few standard shapes. One is the period: the idea stated twice, the first time ending open, as a question, and the second time ending at home, as its answer. subsequence.period makes one from the hook, changing only its last note each time. That makes a Phrase, a line of motifs in order, four bars long. Give it a pattern of its own, on MIDI channel 5:

answered = subsequence.period(hook)

@composition.pattern(channel=5, bars=4)
def hook_line (p):
	p.phrase(answered, root=notes.E5)

composition.render(bars=8, filename="motifs-and-phrases.mid")

In piece.py, put hook and answered above the patterns and add hook_line below them. Give an instrument that can sit above the melody, such as a bell or a pluck, MIDI channel 5.

The question ends on B, the fifth note of the scale, and the answer on E:

    2  2.000  note E5 (76)  velocity 100  length 1.000
    2  3.000  note F#5 (78)  velocity 100  length 1.000
    2  4.000  note B5 (83)  velocity 100  length 1.000
    4  2.000  note E5 (76)  velocity 100  length 1.000
    4  3.000  note F#5 (78)  velocity 100  length 1.000
    4  4.000  note E5 (76)  velocity 100  length 1.000

Other shapes, and more of the same idea