Subsystem Search

A first beat

By the end of this chapter, the piece has begun: a drum beat with a kick on every beat, a snare on the second and fourth beats, and a closed hi-hat on every sixteenth note.

Everything the piece grows into over the rest of the guide starts from the first two blocks of code in this chapter, so keep them: save them together as piece.py in your music folder.

The composition

A script starts by naming what it uses, and by making the composition:

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

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

The beat

Now the drum pattern, and a render of two bars of it:

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

composition.render(bars=2, filename="a-first-beat.mid")

The decorator makes drums a pattern, as in the last chapter, with three things to say about it:

The pattern places its notes on a grid. Four beats are divided into sixteen steps, one for each sixteenth note, numbered from 0 to 15. Step 0 is the first beat, step 4 the second, step 8 the third and step 12 the fourth, and the steps between are the sixteenth notes in between.

p.hit_steps places a short hit of one drum on each step it is given, at one velocity:

The render writes this, shown here for the first beat and the start of the second:

MIDI channel 10
    1  1.000  note C2 (36)  velocity 110  length 0.083
    1  1.000  note F#2 (42)  velocity 70  length 0.083
    1  1.250  note F#2 (42)  velocity 70  length 0.083
    1  1.500  note F#2 (42)  velocity 70  length 0.083
    1  1.750  note F#2 (42)  velocity 70  length 0.083
    1  2.000  note C2 (36)  velocity 110  length 0.083
    1  2.000  note D2 (38)  velocity 100  length 0.083
    1  2.000  note F#2 (42)  velocity 70  length 0.083

The file holds MIDI notes, so the drums appear as the note numbers the map gave them: 36 is the kick, 38 the snare and 42 the closed hi-hat. Beat 1.250 is the second sixteenth note of the first beat. Every hit lasts a small part of a beat.

To hear the beat, set your drum machine or drum instrument to MIDI channel 10 and call composition.play() in place of composition.render(...), as in the last chapter.

The same beat, written as text

A pattern can also be written as a line of text, with p.seq. Here is the same beat in a composition of its own, called as_text, so that composition is still the piece:

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

@as_text.pattern(channel=10, beats=4, drum_note_map=gm_drums.GM_DRUM_MAP)
def drums (p):
	p.seq("kick kick kick kick", velocity=110)
	p.seq(". snare . snare", velocity=100)
	p.seq("x x x x x x x x x x x x x x x x", pitch="hi_hat_closed", velocity=70)

as_text.render(bars=2, filename="a-first-beat-as-text.mid")

The words in the text are spread evenly across the pattern: four words are four beats, and sixteen are sixteen sixteenth notes. A . is a rest. Where pitch= names a drum, every word that is not a rest plays that drum, so the xs are closed hi-hats.

It places the same hits, with one difference: each note lasts as long as its slot, where p.hit_steps makes short hits.

    1  1.000  note C2 (36)  velocity 110  length 1.000
    1  1.000  note F#2 (42)  velocity 70  length 0.250
    1  2.000  note D2 (38)  velocity 100  length 1.000

Use whichever reads better to you. The piece carries on from the first version, with p.hit_steps.

Other ways to place notes