Chord Progressions
Flow provides a dedicated progression expression that compiles a sequence of roman numerals into a voice-led chord Sequence. It’s similar to writing chord symbols in a note stream, but it applies an automatic voice-leading algorithm that chooses nearby voicings for smoother motion.
Basic Syntax
Progressions are expressions, not statements. Use them anywhere a Sequence is expected:
use "@std"
key Cmajor {
Sequence chords = progression | I IV V |
(print (str chords))
}Open in playgroundA key context is required — the roman numerals resolve relative to the active key.
Delimited by Pipes
Like note streams, a progression body is delimited by |:
progression | I IV V I |Open in playgroundUppercase numerals = major chords, lowercase = minor. Extensions (e.g., V7, iim7) work just like roman numerals inside note streams.
Bar Count Suffix
Append :N to a numeral to hold it for N bars:
use "@std"
key Cmajor {
Sequence chords = progression | I:2 IV vi V:2 |
Note: I for 2 bars, IV for 1, vi for 1, V for 2
}Open in playgroundWithout :N, each numeral gets one bar.
Voice Count
By default, progressions use as many voices as the largest chord in the progression (3 for triads, 4 for 7ths, etc.). To force a denser voicing, add voices N:
use "@std"
key Cmajor {
Sequence thick = progression voices 4 | I IV V |
}Open in playgroundVoice counts above the triad add chord tones (7th, 9th) where appropriate. For broader polyphony control across an entire passage (independent of individual chord voicing), see the voicePool context block.
Minor Keys
In a minor key, lowercase numerals become the natural choices:
use "@std"
key Aminor {
Sequence minor = progression | i iv v i |
}Open in playgroundVoice Leading
The progression compiler applies nearest-neighbor voice leading:
- Bass line follows the chord root, constrained to a bass range (~MIDI 36–55)
- Upper voices are rearranged between chords to minimize motion (within ~MIDI 48–84)
- Each chord is emitted as a whole-note block chord in the output sequence
This produces smoother results than raw roman numeral chords in a note stream, which would always use root-position voicings.
Combining with Transforms
A progression returns a Sequence, so all standard transforms apply:
use "@std"
key Cmajor {
Sequence base = progression | I IV V I |
Sequence up2 = base -> transpose(2)
Sequence ret = (retrograde base)
Sequence loop = base -> repeat 4
}Open in playgroundRendering a Progression
use "@std"
use "@audio"
tempo 100 {
timesig 4/4 {
key Cmajor {
section hook {
Sequence chords = progression | I vi IV V |
}
Song song = [hook*4]
Buffer rendered = (renderSong song "piano")
Buffer final = rendered -> reverb 0.3 -> fadeOut 0.5
(exportWav final "ivvi_iv_v.wav")
}
}
}Open in playgroundprogression vs. Note-Stream Chords
Both approaches can produce chord sequences — pick based on what you want:
| You want… | Use |
|---|---|
| Auto voice-leading between chords | progression \| I IV V I \| |
| Fixed chord shapes in root position | Note-stream roman numerals: \| I IV V I \| |
| Custom voicings (e.g. drop-2, specific inversions) | Bracket chord notation: \| [C4 E4 G4] [F4 A4 C5] \| |
| Named chord symbols | Chord literals in a note stream: \| Cmaj7 Am7 Dm7 G7 \| |
Common Progressions
use "@std"
key Cmajor {
Sequence ionian = progression | I IV V I |
Sequence deceptive = progression | I IV V vi |
Sequence twoFiveOne = progression | ii V I |
Sequence circle = progression | I vi ii V |
Sequence blues = progression | I:4 IV:2 I:2 V:1 IV:1 I:2 |
}
key Aminor {
Sequence andalusian = progression | i VII VI V |
Sequence naturalMin = progression | i iv v i |
}Open in playgroundSee Also
- Chords and Harmony - Chord literals, roman numerals, scales
- Musical Context - Setting
keyfor progressions - Pattern Transforms - Transforming progression sequences
- Song Structure - Putting progressions into sections