Chapter 0 · Setup and Your First Sound¶
Welcome. By the end of this chapter you’ll have Python and Subsequence installed, your instrument connected, and a four-bar drum loop playing — or saved to a MIDI file you can drop into any DAW. No prior Python experience needed; we’ll explain the few programming ideas as they come up.
If you already have a working Python setup, you can skim to §0.4. If you’re brand new to Python, follow every step in order — it’s about fifteen minutes, once.
0.1 What Subsequence is (and what it isn’t)¶
Subsequence is an algorithmic sequencer: you describe music with short Python functions, and it turns them into MIDI in real time. The crucial thing to understand before anything else:
Important
Subsequence makes no sound of its own. It sends MIDI — the same note, timing, and controller messages your gear already speaks — to your instrument, which makes the sound. If nothing is connected to receive that MIDI, you’ll hear silence even when everything is working perfectly.
That instrument can be a hardware synth or drum machine, a Eurorack setup, or a software instrument inside a DAW. §0.5 covers both hardware and software routing — pick whichever you have.
You write Subsequence music in plain Python, but you only need a little Python: how to call a function and how to write a list of numbers. Everything else we teach as we go. The payoff for learning that little is large — patterns that evolve, react to the chord underneath them, and never loop quite the same way twice.
0.2 Installing Python and git¶
Subsequence needs Python 3.10 or newer and git (the installer downloads Subsequence from a git repository). Open a terminal and check what you have:
python3 --version
git --version
If both print a version (Python 3.10+), skip to §0.3. Otherwise, follow the steps for your operating system.
macOS. Install Python from python.org/downloads
(avoid the old system Python). If you use Homebrew, brew install python works
too. Get git with xcode-select --install.
Windows. Download the installer from python.org/downloads
and — this matters — tick “Add python.exe to PATH” on the first screen. Install
git from git-scm.com. Windows users can use the
py launcher in place of python3 throughout this guide (e.g. py -m venv ...).
Linux. Most distributions ship Python 3. On Debian/Ubuntu also install the venv and pip packages plus git:
sudo apt install python3-venv python3-pip git
Note
On Linux, Subsequence’s MIDI backend may build a small C extension
(python-rtmidi) the first time. If installation complains about a missing
compiler or headers, install the build tools once:
sudo apt install build-essential libasound2-dev libjack-dev.
0.3 A clean workspace: the virtual environment¶
A virtual environment (venv) is an isolated folder that holds the Python packages for one project, so Subsequence and its dependencies don’t collide with anything else on your system. You make one once.
On macOS / Linux:
python3 -m venv ~/subsequence
source ~/subsequence/bin/activate
On Windows (PowerShell):
py -m venv subsequence
subsequence\Scripts\Activate.ps1
After activating, your prompt shows the environment name (e.g. (subsequence)).
Important
You must activate the venv in every new terminal session before running your
music — otherwise Python won’t find Subsequence. The give-away that you forgot is
ModuleNotFoundError: No module named 'subsequence'. Just re-run the activate
line above.
Note
On Windows, if PowerShell refuses to run the activate script, allow it once with
Set-ExecutionPolicy -Scope CurrentUser RemoteSigned and try again.
0.4 Installing Subsequence¶
With the venv active, upgrade pip and install Subsequence straight from its repository:
python -m pip install --upgrade pip
pip install "subsequence @ git+https://github.com/simonholliday/subsequence@v0.6.2"
This pulls in everything Subsequence needs (the MIDI libraries mido and
python-rtmidi, and a few others) automatically. The @v0.6.2 pins the exact
version this guide is written for, so the examples match what you see.
Confirm it landed:
python -c "import importlib.metadata as m; print(m.version('subsequence'))"
You should see 0.6.2. If instead you get
ModuleNotFoundError, your venv isn’t active — see the box in §0.3.
0.5 Connecting your instrument¶
Subsequence sends MIDI to a port — a named connection your operating system exposes. The port leads either to a piece of hardware or to a virtual cable that carries MIDI to another app on the same computer. Set up whichever matches your setup; you can always add the other later.
0.5.1 Path A — A hardware synth or drum machine¶
Connect the instrument by USB or a USB-MIDI interface and switch it on. The operating system lists it as a MIDI port automatically — there’s nothing else to install. Skip ahead to §0.5.3.
0.5.2 Path B — A DAW or software instrument¶
Software instruments live inside your computer, so you need a virtual MIDI port to carry MIDI from Subsequence to your DAW. Subsequence doesn’t create one itself, so make one at the operating-system level — a one-time setup:
macOS: open Audio MIDI Setup → Window ▸ Show MIDI Studio → double-click IAC Driver → tick “Device is online”. The IAC bus now appears as a MIDI port.
Windows: install loopMIDI and click + to create a named port.
Linux: load the ALSA virtual MIDI module (
sudo modprobe snd-virmidi) or wire it up in your JACK/patchbay.
Then, in your DAW, set a track’s MIDI input to that virtual port and arm it, and point its instrument at the track. Subsequence sends to the port; the DAW receives and plays the sound.
0.5.3 Choosing and checking your port¶
List the output ports Python can see:
python -c "import mido; print(mido.get_output_names())"
You’ll get a list of names, for example ['IAC Driver Bus 1', 'Minilogue']. When
you create a Composition, tell it which one to use:
import subsequence
composition = subsequence.Composition(bpm=120, output_device="IAC Driver Bus 1")
Warning
The name must match exactly — Subsequence does not guess from partial names.
Copy it verbatim from the list above. If you leave output_device out entirely,
Subsequence uses the only port if there’s exactly one, or prompts you to pick when
there are several.
Note
On Linux, ALSA port names include trailing numbers (e.g. Minilogue:Minilogue MIDI 1 24:0) that can change between reboots. Re-run the list command if a
previously-working name stops matching.
0.6 Your first composition¶
Here is a complete Subsequence script: a one-bar General MIDI drum loop —
four-on-the-floor kick, backbeat snare, and a steady sixteenth-note hi-hat. Save
it as hello.py.
import subsequence
import subsequence.constants.instruments.gm_drums as gm_drums
composition = subsequence.Composition(bpm=120)
@composition.pattern(channel=10, beats=4, drum_note_map=gm_drums.GM_DRUM_MAP)
def drums(p):
p.hit_steps("kick_1", [0, 4, 8, 12], velocity=100) # one hit per beat
p.hit_steps("snare_1", [4, 12], velocity=90) # backbeat (beats 2 & 4)
p.hit_steps("hi_hat_closed", range(16), velocity=70) # every sixteenth
composition.render(bars=4, filename="hello.mid")
Reading it top to bottom:
subsequence.Composition(bpm=120)creates the piece and sets the tempo. (To send to a specific instrument, addoutput_device="..."from §0.5.)@composition.pattern(...)is a decorator — the@line just above a function. For now, read it as “register the function below as a musical pattern.” Here it says: play on channel 10 (the General MIDI drum channel), make the pattern 4 beats long, and translate drum names via the GM drum map.def drums(p):is your pattern. Thepit receives is a builder you paint notes onto.p.hit_steps(name, steps, velocity=...)places a drum hit on specific grid steps. A 4-beat bar is divided into 16 sixteenth-note steps numbered 0–15, so[0, 4, 8, 12]is one kick per beat,[4, 12]is the backbeat, andrange(16)is all sixteen hi-hats.velocityis how hard each hit plays (1–127).composition.render(bars=4, filename="hello.mid")writes four bars to a MIDI file — covered next.
Note
Channels are 1-indexed; steps are 0-indexed. MIDI channels run 1–16 to match the labels on hardware (channel 10 = drums). Grid steps, like most things you count in code, start at 0. This trips up everyone once — we’ll come back to it in Chapter 1.
0.7 Rendering it to a file¶
You don’t need any hardware to check your code works. composition.render() runs
the sequencer as fast as possible and writes a standard MIDI file:
composition.render(bars=4, filename="hello.mid")
Run the script:
python hello.py
It produces hello.mid in the current folder. Open that file in any DAW (or a
MIDI viewer) and you’ll see the kick, snare, and hi-hat laid out across four bars.
render is the quickest way to answer “did my code do what I meant?” — it never
waits for real time and never needs an instrument connected.
Tip
Pass bars= to set the length. Without it, render keeps going up to a 60-minute
safety cap — handy for generative pieces that would otherwise never end.
0.8 Going live with play()¶
When you’re ready to hear it through your instrument in real time, swap the
render line for play:
composition.play() # streams MIDI live; press Ctrl-C to stop
play() opens your MIDI port and runs off the wall clock, so the music comes out
of your synth or DAW as it happens. Stop it with Ctrl-C. To capture a live
take to a file at the same time, start the composition with record=True:
composition = subsequence.Composition(bpm=120, record=True, record_filename="take.mid")
That’s the whole loop you’ll use from here on: write a pattern, render to check
it, play to perform it.
0.9 Troubleshooting your first run¶
Symptom |
Fix |
|---|---|
|
The venv isn’t active. Re-run the |
|
git isn’t installed or not on PATH — see §0.2. The install is a git download, not a plain package. |
|
A port was auto-chosen but your instrument isn’t listening. Pass an explicit |
It prints a numbered list and waits for input |
Several MIDI ports were found. Type the number, or set |
No errors, but silence |
MIDI is flowing but nothing makes sound. Confirm the port name is exact, the instrument is on the right channel (drums = channel 10), and — for a DAW — the track’s MIDI input is the virtual port and it’s record-armed. |
Linux: |
Install build headers once: |
You now have a working setup and a first loop. In Chapter 1 we’ll stay with this drum pattern and learn the step grid properly — building a groove by hand, shaping velocity, and meeting that 1-indexed-channel / 0-indexed-step distinction head-on.